Environment Tests and Self-Diagnosing Configuration (with StructureMap)

I added an exciting new feature to our suite of applications this week.  Not “seeing Star Wars for the first time” exciting or maybe even Ajax/Web 2.0 cool, but something that will definitely make our collective lives easier.  I added environment tests to our codebase and deployment scripts to troubleshoot and automate the verification of the deployed build.  The deployment script is now self-diagnosing.  Even better yet we could take advantage of the diagnostic tools in my StructureMap tool to embed the environment tests directly into the code since we already use StructureMap for configuration and attaching dependencies.


Our main application isn’t that big, but it’s nasty to deploy because it has a lot of environmental dependencies and configuration, but not much visibility into exceptions and failure conditions.  When we inherited the application we spent a lot of manhours getting the application to run correctly on our developer workstations.  We had to literally spend a couple man-weeks to make a new development environment work correctly.  In the last release we had at least two instances of a botched testing deployment costing us a day to track down and wasting the time of scarce testing resources.  Environment tests to the rescue. 


The new environment tests paid for themselves on day one.  I immediately found two assemblies and a certificate file that was missing from the deployment scripts.  We would have found the problems before rollout anyway, but the environment tests told me exactly where the problems were, and that’s exactly what we wanted.


Here are some of this things we’ve created environment tests for so far:



  • Database connectivity
  • Remoting configuration
  • Web service availability, including security configuration
  • External files
  • Our custom rules engine component stores client configuration data in xml files.  These configuration files can contain references to client specific database tables and stored procedures.  We have an environment test now that verifies the existence of the configuration file for each client in the database and checks that the referenced database objects actually exist
  • Any and all dependencies on legacy COM objects.  Nothing aggravates me more than troubleshooting whether or not a COM component is properly registered.  Death to COM!
  • NHibernate mappings and configuration
  • File and assembly manifest.  I’ve put a new set of NAnt tasks in StructureMap to create and check a list of versioned .Net assemblies and other files (compares a hash of the file contents) in a deployed directory.

At some point we’ll supplement the StructureMap environment tests by integrating some sort of synthetic transaction to run fake messages all the way through the system.


I first envisioned the environment and configuration troubleshooting in StructureMap after a nasty incident on a project two years ago.  We were building a WinForms client that talked to web services.  One day in the standup meeting a tester got up and said the testing installation wasn’t functioning and all testing was stopped.  With the project manager fuming right behind me, I grabbed the current version of the client in testing and spent the better part of the day banging my head against the problem.  Inevitably, it worked perfectly on my box, but blew up with a seemingly randomly selected http error code as soon as I tried it on a tester’s workstation.  Eventually I checked the configuration for the client and realized the testing client was trying to access the web services at “localhost.”  Perfectly valid on any developer’s workstation, but invalid anywhere else.   Several man days went down the drain on an already challenged project.


I think I could have easily filled up this entire post with anecdotes of bugs caused by incorrect or incomplete testing deployments and 48 hour marathon production moves, but I think you get the point (and you’ve probably lived through it anyway).  Incomplete, invalid , or just plain wrong code deployments can be a major source of inefficiency.  My theory was that I could embed the ability into StructureMap to make a codebase be self-diagnosing to “tell” you about any problems or inconsistencies immediately after a deployment.  In other words, make the code tell you exactly when and where there’s a problem in the deployment before a tester wastes anytime with a bad build.  Not to mention making the 48 hour, let’s all camp out in the warroom, production moves much less risky and stressful.


How StructureMap Validates a Deployment


First off, to really take advantage of StructureMap’s abilities you need to very consciously build a system somewhat as a microkernal.  The functional core of the system (business logic, user interface controlling logic, workflow logic) needs to be isolated from external dependencies and services like data access/persistence, middleware, web services, and even just external files.  The core of the system should only depend on abstracted interfaces to the external dependencies.  The external dependencies are managed and attached via Dependency Injection and/or Service Location by StructureMap (or Spring.Net, Castle, etc.).  Now that StructureMap is aware of all of the external dependencies in our system, we can take advantage of the built in troubleshooting tools within StructureMap to embed environment tests directly into the classes controlled by StructureMap.


Instead of code like this that creates dependencies with a call to “new” and “pulling” configuration:


    public class DataProvider
    {
        private string _connectionString;
 
        public DataProvider()
        {
            _connectionString = System.Configuration.ConfigurationSettings.AppSettings["ConnectionString"];
        }
    }
 
    public class Worker
    {
        private DataProvider _provider;
 
        public Worker()
        {
            // Strongly coupled dependency on the DataProvider class that pulls its configuration
            // out of the App config file
            _provider = new DataProvider();
        }
    }

use StructureMap to find the external dependencies and “push” in the configuration.


    public interface IDataProvider{}
 
    public class DataProvider2 : IDataProvider
    {
        private string _connectionString;
 
        public DataProvider2(string connectionString)
        {
            _connectionString = connectionString;
        }
 
        // Decorate this method with the ValidationMethod to instruct StructureMap
        // to call this during diagnostics
        [ValidationMethod]
        public void ValidateConnection()
        {
            // try to open a database connection
        }
    }
 
    public class Worker2
    {
        private DataProvider _provider;
 
        public Worker2()
        {
            // Pull the dependency from StructureMap, and give StructureMap a chance to call
            // any validation methods
            _provider = (DataProvider) ObjectFactory.GetInstance(typeof(IDataProvider));
        }
    }

StructureMap has quite a bit of diagnostics support that can be used from either a command line tool, a NAnt task, or a GUI tool that provides a Windows Explorer-like view of the configuration (in the forthcoming version, it’ll be released on SourceForge only after we dogfood it a while longer).  So, here’s some of the things StructureMap will do to diagnose a deployment:



  1. Look for any referenced assemblies that might be missing
  2. Check that all referenced concrete classes can be created within the deployment
  3. Verify that all required arguments to either constructor functions or setter properties exist with a valid value.  I.e., you can’t put “hello” into an integer argument.  Because StructureMap depends on constructor arguments and setter properties, it’s able to use reflection to determine the properties that need to be present and configured.  If you add a new constructor argument to a concrete class that is configured by StructureMap, the diagnostics will complain if you forget to go add a value for the new argument to configuration.
  4. Try to create each and every configured instance in the StructureMap configuration.  Reports any failures.
  5. Lastly, search the objects that were created successfully for methods decorated with a [ValidationMethod] attribute.  Call these methods to give the classes a chance to perform environment tests or further validation.  Report any exceptions thrown.

A while back I had some comments asking why or how StructureMap is better or at least differnt than the other DI tools for .Net.  I’d claim that the self-diagnostic configuration and environment tests are a big advantage over the other tools.


Example


An obvious example for an environment test is database connectivity.  The average enterprise application is an inert lump without being able to connect to the database.  When we do traditional data access we use a class called DataSession as our facade to ADO.Net.  The very first environment test I added to our code was the ValidateConnection() method in the DataSession class that is shown below:


    [Pluggable("Default")]
    public class DataSession : IDataSession
    {
        private readonly IDatabaseEngine _database;
        private readonly ICommandFactory _factory;
        private readonly IExecutionState _defaultState;
        private readonly ITransactionalExecutionState _transactionalState;
        private IExecutionState _currentState;
        private readonly ICommandCollection _commands;
        private readonly ReaderSourceCollection _readerSources;
 
        [DefaultConstructor]
        public DataSession(IDatabaseEngine database)
            : this(database, 
                   new CommandFactory(database),
                   new AutoCommitExecutionState(database.GetConnection(), database.GetDataAdapter()),
                   new TransactionalExecutionState(database.GetConnection(), database.GetDataAdapter()))
        {
 
        }
 
 
        [ValidationMethod]
        public void ValidateConnection()
        {
            using (IDbConnection connection = _database.GetConnection())
            {
                connection.Open();
            }
        }
 
    }

In the NAnt deployment script there is a call to StructureMap’s task to validate the configuration like this:


<structuremap.verification configPath=”${deployment.dir}\StructureMap.config” failonerror=”${fail.on.environment.tests}”/>


This NAnt task directs StructureMap to analyze and validate the configuration of the .Net application deployed to the “${deployment.dir},” including a call to the DataSession.ValidateConnection() method.  If the DataSession instance is either missing the configuration for the connection string, or the connection to the database fails, the build fails.  If the verification task finds any errors, the build fails with a report of the specific problems.  Here’s a sample output from the verification task I created by when the database was offline.

StructureMap.Configuration.Tokens.InstanceToken
PluginFamily: StructureMap.DataAccess.IDataSession, StructureMap.DataAccess (Explicit)
DefaultKey ShareDoc
StructureMap.Configuration.PluginGraphReport

Problem: A Validation Method Failed

SQL Server does not exist or access denied.
at System.Data.SqlClient.SqlInternalConnection.OpenAndLogin()
at System.Data.SqlClient.SqlInternalConnection..ctor(SqlConnection connection, SqlConnectionString connectionOptions)
at System.Data.SqlClient.SqlConnection.Open()
at StructureMap.DataAccess.DataSession.ValidateConnection() in

d:\work\sideshow-trunk\source\StructureMap.DataAccess\DataSession.cs:line 175
————————————————–

The big advantage of doing environment tests with StructureMap is the ability to accrue the environment tests as new external environment dependencies are added to the codebase instead of a big bang approach at the end.  All you have to do is put methods directly in the environmentally sensitive classes that will throw exceptions if the environment is incorrect.  I really like having the environment tests embedded directly into the code because it means fewer pieces to deploy. 


This functionality is available in the version of StructureMap released on SourceForge, but it is much more robust in the forthcoming version that we’re using at work.  I will make another release in the near future.


Links


About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in Continuous Integration, Legacy Code, StructureMap. Bookmark the permalink. Follow any comments here with the RSS feed for this post.