ASP.NET MVC 3 & Unity 2.0: Using XML configuration for design-time configuration

Introduction

In one of my blog post “ASP.NET MVC 3: Dependency injection with Unity 2.0” I explained how to use the Unity 2.0 dependency injection (DI) container in an ASP.NET MVC 3 web application. The example shown in this previous post uses run-time configuration to set up the DI container. A drawback of run-time configuration is, that one needs a reference to the concrete implementations the Unity container should use for dependency injection when setting up the container. In the example the Application_Start method in the Global.asax.cs refers to the concrete implementation Messages of the interface IMessages:

container.RegisterType<IMessages, Messages>();

Unity also support design-time configuration that enables you to uncouple your application from the concrete implementations that should be injected. Based on the project from my previous post (VS 2010 project download), I will show how to use a XML configuration file for design-time configuration.

Implementation

To uncouple the ASP.NET MVC 3 project from the concrete implementations we first create two new class library projects:

  1. MVC3-Unity-Sample.Contracts
  2. MVC3-Unity-Sample.Core

The idea is, that the contracts project defines the interfaces (IMessage in the example) and the core project defines the concrete implementations (Message in the example) and the ASP.NET MVC 3 project only needs a reference to the contracts project and no reference to the core project. In other words: The ASP.NET MVC 3 project does no longer “know” the concrete implementations.

After creating the two new projects we move/rename the IMessage interface and the Message class:

  1. We move MVC3_Unity_Sample.Models.IMessages to MVC3_Unity_Sample.Contracts.IMessages in the contracts project.
  2. We move MVC3_Unity_Sample.Models.Message to MVC3_Unity_Sample.Core.Message in the core project.

Now we need to add a reference the contracts project in the ASP.NET MVC 3 project and the core project because both refer the IMessage interface.

In a second step, we now need to remove the programmatically (run-time) initialization of the Unity container in the Global.asax.cs and add the (design-time) configuration to the Web.config:

  1. Change the method Application_Start in Global.asax.cs to:
    protected void Application_Start()
    {
      AreaRegistration.RegisterAllAreas();
     
      RegisterGlobalFilters(GlobalFilters.Filters);
      RegisterRoutes(RouteTable.Routes);
     
      var container = new UnityContainer().LoadConfiguration();
      DependencyResolver.SetResolver(new UnityDependencyResolver(container));
    }
  2. Add Unity XML configuration to Web.config:
    <configSections>
      <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
    </configSections>
    <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
      <alias alias="IMessages" type="MVC3_Unity_Sample.Contracts.IMessages, MVC3-Unity-Sample.Contracts" />
      <alias alias="Message" type="MVC3_Unity_Sample.Core.Messages, MVC3-Unity-Sample.Core" />
      <container>
        <register type="IMessages" mapTo="Message" />
      </container>
    </unity>

In a last step we customize the Visual Studio build process because the core project needs to be build in order to run the ASP.NET MVC 3 project but VS2010 does not know this dependency. We need to:

  1. Add project (build) dependencies: Solution properties > Common Properties > Project Dependencies > Select MVC3-Unity-Sample project and check the MVC3-Unity-Sample.Core project
  2. Change the output path of the core project: MVC3-Unity-Sample.Core project properties > Build tab > Output path: “..\MVC3-Unity-Sample\bin\“.

Summary

Using Unity design-time XML configuration decouples the application from concrete implementations. For example in a mutlitier architecture one could use this approach to gain more flexibility: One could replace different layers of the application without recompiling because the type mapping is defined in XML configuration files .

You can download a sample Visual Studio 2010 project containing all the source code here.

Comments

  1. Orlando

    Hi Jan,

    I followed the previous post (Unity at run time) and everything worked fine, but for some reason this one is not working for me.

    If I use:
    container.RegisterType; on the Global.asax everything works fine but as soon as I comment those lines and add my registrations to the web config the IMessage interface is not instantiated at all.

    Any advise here? I am just exploring Unity 2.0 with your posts .. 🙂

    Thanks!

  2. Orlando

    Never mind,

    I already fixed it. But I think you should update this post. In the Global.asax you need to change:

    var container = new UnityContainer();

    by

    var container = new UnityContainer().LoadConfiguration();

    (Note: LoadConfiguration’s method lives in Microsoft.Practices.Unity.Configuration so do not forget to add the using statement)

    I spent more than 4 hours to understand what the problem was.

    Thanks for sharing!!

  3. Jan Jonas

    Hi Orlando,
    you’re right. To use design time configuration one has to call LoadConfiguration(), but this is exactly what I’ve described in this post (see step 1 “Change the method Application_Start in Global.asax.cs to […]”). Have fun with Unity … 🙂

  4. Den

    Hi Jan,

    Thanks for the very nice post.

    I’ve a contract and a core project as per your sample and followed all the steps. But, the property for which I’m setting the Dependency attribute is never instantiated. The configuration, global.asax are identical as per your example.

    In fact, I have referenced my contract and core projects in the sample solution that you’ve provided and there the property gets instantiated properly.

    I’ve noticed that the version of our unity dlls were different, so I used the ones in the sample project but, that did not help as well.

    If I use the below code in my controller, an instance of the concrete implementation that I chose in the web config is provided:

    logger = DependencyResolver.Current.GetService()

    But, this code should not be needed, as per your example.

    This is my first entry into the DI world and would appreciate your help.

    Den

  5. Den

    I’ve pasted a wrong line of code, the below instantiates the class fine:

    logger = DependencyResolver.Current.GetService();

  6. Den

    Hi Jan,

    Apparently unity only resolves public properties(mine was protected).

    Thanks for the nice tutorial.

Leave a comment

Your email address will not be published. Required fields are marked *

*