Testing Your Unity Configuration when you Build or Deploy .Net Apps

Dependency injection is great, but it does come with a risk that errors with the container configuration don’t show up until runtime (eg. forgetting to specify which implementation should be used for a given interface). In an MVC app, this can mean broken controllers, fatal errors with service classes, and parts of your site/application being unavailable. So a safeguard against this is to check your IOC configuration, either at deployment time, or even better, at build time. Then you can fail the build or back out of a deployment if the various services or controllers can’t be resolved.

To solve this problem on a recent project, I wrote some custom code to do a “get me one of everything” test. So if I have a service requiring other services/repositories, or a controller that uses those services, I know about any missing Unity configuration entries. This post covers .Net, MVC and Unity, but the same approaches should work for other IOC setups.

I’ve listed a couple of different approaches to Unity configuration testing in the following code snippets – applying a simple strategy to a large production codebase threw up a few issues, and prompted some experimentation and refactoring.

Basic Approach

First, I try and resolve everything I can find registered in the Unity container. Then I check that I can get an instance of each controller. This should ensure that all the constructor-injection is tested. Any errors with Unity get collected up and reported (and hopefully other errors are left to a different test). If the checks return no errors we’re good, otherwise we need to go fix the configuration. There are limits to this approach – I’m still trying to figure out a way to deal with individual calls to directly resolve implementations from the container – but checking the listed container contents and all the controllers cuts down on a lot of potential problems.

Running a Unity Check

Once you have a basic Unity checker class setup, you have options for running it. I have an API controller run this, so I can poll it from a command-line app/script on deployment. Our build pipeline does a “deploy to a development environment and run some tests” following a successful CI build, so we know soon after a code commit whether we have a shippable build. Getting the tests running at the local/CI build stage (eg. via unit tests) is even better.

Example Code

The first thing I need is a simple app with Unity setup (your production codebase will no doubt require some tweaks), and some very basic/stupid test interfaces/implementations. And then I can add some Unity configuration. I just grabbed the Unity.Mvc Nuget package, used the out-of-the-box UnityConfig.cs, and edited it to set up a load of config entries eg.

container.RegisterType();

I then made sure I had service implementations and controllers constructed with dependency injection so they get whatever’s configured in Unity as the implementation, eg.

public StuffController(IDoStuffService doStuffService) { ... }

I start by building a basic Unity checking class like this:


public class UnityConfigurationChecker
{
    public static IList GetUnityErrors()
    {
        List errors = new List();
        var container = UnityConfig.GetConfiguredContainer();

        foreach (ContainerRegistration registration in container.Registrations)
        {
            try
            {
                Type registrationType = registration.RegisteredType;
                var instance = container.Resolve(registrationType);
            }
            catch (Exception e)
            {
                errors.Add(e.Message);
            }
        }

        //Note: going to add extra checks for controllers in here!

        return errors;
    }
}

I can then call it to get a list of (hopefully zero) errors with

var messages = UnityConfigurationChecker.GetUnityErrors();

This class isn’t intended to be hit by production code or user action, it’s just a helpful utility that tells us all the configuration errors we currently have. No messages is good, otherwise we need to investigate the issues (so I just catch all the exceptions and make a note of them).

Running Unity Tests

You could start with a basic controller/action that just runs the Unity checks and reports any errors to a view. Expand this with an API method and a script that runs during your build process to call the API and get a list of (hopefully zero) issues.

Now the fun begins as we start commenting-out Unity entries and watch those errors eg. “The current type, UnityChecker.Services.IDoStuffService, is an interface and cannot be constructed. Are you missing a type mapping?”

So far this only tests the registered container entries. It will only pick up issues with registered types that require other registered types.

Assume you have this setup of three services, only one of which requires constructor injection:

container.RegisterType();
container.RegisterType();
container.RegisterType();

public DoStuffService() { ... }
public DoThingsService() { ... }
public DoStuffAndThingsService(IDoStuffService doStuffService, IDoThingsService doThingsService) { ... }

If you forgot to register either the DoStuffService or DoThingsService, the DoStuffAndThingsService can’t be resolved.

Testing Unity With Unit Tests

So this gives you a Unity-checking utility that you can use on a running web application, but that means you have to wait until deployment time to check your config. Better than a fatal runtime exception days after deployment, but checking this during the CI process (or even before check-in) would be awesome. So let’s try building container-checking into a unit test.

Add a unit test project to the solution (I’m using MsTest, but the NUnit approach should be the same) and create a simple unit test class:


[TestClass]
public class UnityConfigurationCheckerTest
{
    [TestMethod]
    public void GetUnityErrors_ExpectZeroErrors()
    {
        var messages = UnityConfigurationChecker.GetUnityErrors();
        Assert.AreEqual(0, messages.Count);
    }
}

Verifying Controllers (Version 1)

So far, this example only checks the container registrations, not the controllers. We can amend our method with extra code that also checks the controllers:


    //Need reference to the main MVC web application assembly
    //May need to check for typeof Controller and ApiController
    //Note: Prevent false-positives of abstract controllers
    var assembly= typeof(UnityConfig).Assembly;
    var controllerTypes = assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(Controller)));

    foreach (var controllerType in controllerTypes)
    {
        if (!controllerType.IsAbstract)
        {
            try
            {
                var controllerInstance = container.Resolve(controllerType);
            }
            catch (Exception e)
            {
                errors.Add(e.Message);
            }
        }
    }
    return errors;

Note that searching the correct assembly for controllers is vital. Amend as necessary if you want to use the Unity checker with multiple different web application assemblies.

If the controller constructor expects something that’s not registered in the container, we’ll now get an error about it. Actually, I did get an error regarding one of the controllers in the demo MVC solution I used as a starting point, so some care may need to be taken about what constitutes an actual error in your configuration…

Better Exception Checking

Treating all the exceptions you hit as “fatal” is unhelpful, we want to distinguish between container registration errors and other runtime issues (eg. a service fails because of some other database or configuration issue). Be mindful of the testing context you run the Unity checks in. This is especially important if you’re going to use container checking as a build-breaking condition.

An improvement is to catch “System.InvalidOperationException” and “Microsoft.Practices.Unity.ResolutionFailedException”, and then log the exception type and message. For controllers that throw ResolutionFailedException, if there’s an InnerException then use that instead.

As a test, you could make sure your container registers everything you need, then deliberately throw an exception in a service/controller constructor – differentiate between being unable to construct the controller (missing Unity configuration entry) and a subsequent runtime exception.

Deciding on the correct set of exceptions to catch / ignore is still a judgement call and might not catch every scenario of “IOC configuration vs other runtime error” problem you run into…

Verifying Controllers (Version 2)

At this point, it’s maybe worth re-thinking the controller checks. While we’re making sure we can get controller instances, we’re not too worried about whether we can construct an instance of a controller so much as whether the controller has access to everything it needs to be constructed. So what if, instead of exercising Unity by constructing an instance of the controller, we just check that everything injected into the controller’s constructor is available in Unity?

So my refactored UnityConfigurationChecker class now contains this:


public class UnityConfigurationChecker
{
    private static void ResolveImplementationFromIoc(IUnityContainer container, Type registrationType)
    {
        try
        {
            var instance = container.Resolve(registrationType);
        }
        catch (InvalidOperationException e)
        {
            throw e;
        }
        catch (ResolutionFailedException e)
        {
            throw e;
        }
        catch (Exception)
        {
            //Ignore
        }
    }

    public static IList GetUnityErrors()
    {
        List errors = new List();

        var container = UnityConfig.GetConfiguredContainer();


        foreach (ContainerRegistration registration in container.Registrations)
        {
            Type registrationType = registration.RegisteredType;
            try
            {
                ResolveImplementationFromIoc(container, registrationType);
            }
            catch (Exception e)
            {
                errors.Add(e.GetType() + " - " + e.Message);
            }
        }
        //Need reference to the main MVC web application assembly
        //May need to check for typeof Controller and ApiController
        var assembly = typeof(UnityConfig).Assembly;
        var controllerTypes = assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(Controller)));

        foreach (var controllerType in controllerTypes)
        {
            if (!controllerType.IsAbstract)
            {
                var constructors = controllerType.GetConstructors();
                foreach (var constructor in constructors)
                {
                    System.Reflection.ParameterInfo[] parameters = constructor.GetParameters();
                    foreach (var parameter in parameters)
                    {
                        var parameterType = parameter.ParameterType;
                        if (parameterType.IsInterface)
                        {
                            try
                            {
                                ResolveImplementationFromIoc(container, parameterType);
                            }
                            catch (Exception e)
                            {
                                errors.Add("Registration error with controller " + controllerType.FullName + ". " + e.GetType() + " - " + e.Message);
                            }
                        }
                    }
                }
            }
        }

        return errors;
    }
}

And then a quick test – get the controller to deliberately fail eg. by throwing a new NotImplementedException in the constructor – and as long as the Unity configuration is fine, the Unity checks will pass, because you’re not actually constructing an instance of the controller. However, throw an exception in one of the concrete implementations you resolve from the container, and you will get an error.

Check again that this is all working by editing the UnityConfig.cs and hiding a few necessary registrations.

Gotchas and Other Issues

I encountered a few issues when applying this strategy to an existing codebase. The Unity configuration works fine in its natural web application context, but running in an unfamiliar unit testing context causes issues. Because you’re actually running the Unity registration and creating instances of those registered types during your tests, you may encounter errors in the setup before the test even runs and starts testing your newly-configured container.

Firstly, I had a few types that wouldn’t resolve themselves because they fell over at construction time looking for non-existent configuration settings. A few extra “appSettings” entries in the unit test project’s “app.config” file fixed that.

Next, I had our old friend the “Could not load file or assembly” exception. Because the unit test project is running the same code as your target application, it’s going to need to reference and load the same assemblies. Good luck debugging that one.

I was running the Unity configuration in application startup with a “UnityConfig.RegisterComponents()” call to run all my “RegisterType” calls. I also had the unit test run that as a setup step to mimic a clean application startup.

You can wrap a try-catch around your setup call, or just step-through in the debugger to find the problem registration, but it might take some effort to get your container to work correctly for your unit tests.

An Alternative Approach Using Reflection (Version 3)

There’s an alternate approach worth considering at this point. The aim of this exercise is not to actually resolve and construct any concrete instances (we won’t be using them). That’s just one way to test the container (it’s probably the best way). All we actually care about is one thing: if you have a service/controller with a concrete instance of another service injected at run-time, will it work? Or will the container say “I don’t know how to resolve that” and let the app fall over?

I already used reflection to inspect my controller constructor parameters, I can do the same trick for my service classes.

So here’s code for an alternative approach. I also took the opportunity to wrap any returned errors in a class that can easily show errors in the test runner just by overriding ToString().


public class UnityConfigurationChecker
{
    private static Type GetMappedRegisteredConcreteType(IUnityContainer container, Type registrationType)
    {
        if (container.IsRegistered(registrationType))
        {
            //Don't resolve, just ask the container what it might resolve to
            ContainerRegistration registration = container.Registrations.FirstOrDefault(r => r.RegisteredType == registrationType);
            if (registration != null)
            {
                return registration.MappedToType;
            }
        }
        throw new ArgumentException("Could not map to concrete type for " + registrationType);
    }

    private static bool InspectConcreteTypeEnsureConstructorParametersValid(IUnityContainer container, Type concreteType)
    {
        //Don't care about abstract controllers / services
        if (!concreteType.IsAbstract)
        {
            //Look for constructor parameters and resolve all injected interface implementations
            var constructors = concreteType.GetConstructors();
            foreach (var constructor in constructors)
            {
                System.Reflection.ParameterInfo[] parameters = constructor.GetParameters();
                foreach (var parameter in parameters)
                {
                    var parameterType = parameter.ParameterType;
                    if (parameterType.IsInterface)
                    {
                        try
                        {
                            GetMappedRegisteredConcreteType(container, parameterType);
                        }
                        catch (Exception e)
                        {
                            throw new ArgumentException("Registration error with type " + concreteType.FullName + ". " + e.GetType() + " - " + e.Message);
                        }
                    }
                }
            }
        }
        return true;
    }

    public static UnityConfigurationCheckSummary GetUnityErrorsContainerConfiguration()
    {
        UnityConfigurationCheckSummary summary = new UnityConfigurationCheckSummary();
        var container = UnityConfig.GetConfiguredContainer();

        foreach (ContainerRegistration registration in container.Registrations)
        {
            Type registrationType = registration.RegisteredType;
            var concreteType = registration.MappedToType;
            try
            {
                InspectConcreteTypeEnsureConstructorParametersValid(container, concreteType);
            }
            catch (Exception e)
            {
                summary.Errors.Add(e.Message);
            }
        }
        return summary;
    }

    public static UnityConfigurationCheckSummary GetUnityErrorsControllerConfiguration()
    {
        UnityConfigurationCheckSummary summary = new UnityConfigurationCheckSummary();
        var container = UnityConfig.GetConfiguredContainer();

        var assembly = typeof(UnityConfig).Assembly;
        var controllerTypes = assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(Controller)));

        foreach (var controllerType in controllerTypes)
        {
            try
            {
                InspectConcreteTypeEnsureConstructorParametersValid(container, controllerType);
            }
            catch (Exception e)
            {
                summary.Errors.Add(e.Message);
            }
        }
        return summary;
    }
}


public class UnityConfigurationCheckSummary
{
    public IList Errors { get; set; }
    public int Count { get { return Errors.Count(); } }

    public UnityConfigurationCheckSummary()
    {
        Errors = new List();
    }

    public override string ToString()
    {
        if (Errors.Any())
        {
            return string.Join(", ", Errors);
        }
        return string.Empty;
    }
}

Here’s the unit test code, checking that we get no errors, but giving a nice summary if we do. You might need to add a “Setup” method to reset/recreate your container for each test.


[TestClass]
public class UnityConfigurationCheckerTest
{
    [TestMethod]
    public void GetUnityErrorsContainerConfiguration_ExpectZeroErrors()
    {
        var summary = UnityConfigurationChecker.GetUnityErrorsContainerConfiguration();
        Assert.AreEqual(string.Empty, summary.ToString());
        Assert.AreEqual(0, summary.Count);
    }

    [TestMethod]
    public void GetUnityErrorsControllerConfiguration_ExpectZeroErrors()
    {
        var summary = UnityConfigurationChecker.GetUnityErrorsControllerConfiguration();
        Assert.AreEqual(string.Empty, summary.ToString());
        Assert.AreEqual(0, summary.Count);
    }
}

Summary – Verifying Unity Configuration

With some simple code like this, every time you add a service or change a controller, your Unity configuration should be tested for correctness with a regular unit test run. And you can always put the tests behind an API method and poll after a deployment to be sure that your configuration is correct.