Using StructureMap with ASP.NET MVC & MVC Contrib

21. September 2009

I’ve found myself using the MVC Contrib project more and more lately. There are tons of golden framework nuggets just waiting to be used.

I recently integrated StructureMap into the my current ASP.NET MVC framework using MVC Contrib. The reason I decided to write this post is because most of the resources I found on the internet appeared to be a little out of date and used deprecated StructureMap APIs. So, here it goes…

Note: The following examples are using StructureMap v2.5.3 & ASP.NET MVC v2 Preview 1 & MVC Contrib MVC2 Branch code bits. You may find minor differences in API &| syntax if you are using a different version.

First lets investigate why StructureMap is necessary in the first place. You can find some good blog posts by Jeremy D. Miller about the basics of the Dependency Injection Pattern and using an IOC tool.

In order to facilitate mocking and decouple our application we pass an interface of our service into our controller instead of a concrete class. The default controller factory that ASP.NET MVC uses requires a default constructor to be present, but we are going to define our own Controller Factory later in this post using one of the MVC Contrib classes.

Note: There is actually a really good screencast with @robconery and @jeremydmiller about using StructureMap in ASP.NET MVC. There were several “Aha!” moments for me as I watched it. The StructureMap API has changed slightly since the screencast, but I will show the updated syntax in the following of this post.

The following is a typical ContactController class that will house the Index, Details, Create, Edit, and Delete actions. You will notice that instead of having a default constructor, I have an overloaded contructor and am passing in an interface to my service. I will wire up StructureMap to handle passing in the appropriate object later in this post.

public partial class ContactController : Controller
{
    private IContactService service;

    public ContactController(IContactService service)
    {
        this.service = service;
    }
}    

The wiring part, happens typically in the Application_Start event from the Global.asax.cs file. In addition to Registering your MVC routes (which should have already been wired up when you created your MVC application) you need to both configure StuctureMap to know what concrete classes map to what interfaces as well as tell MVC to use StructureMap to create its controllers.

public class Global : HttpApplication
{
    protected void Application_Start(object sender, EventArgs e)
    {
        RegisterRoutes(RouteTable.Routes);

        Bootstrapper.ConfigureStructureMap();
        ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
    }
}

I am going to attempt and explain the above code snippet line by line, so lets start with the Bootstrapper.ConfigureStructureMap() and then we will discuss the StructureMapControllerFactory().

After everything is said and done, the important part of StructureMap is that it knows what interfaces should map to what concrete types so that it can inject the appropriate instances at runtime. This is where the Bootstrapper.ConfigureStructureMap() comes into play.

public static class Bootstrapper 
{
    public static void ConfigureStructureMap()
    {
        ObjectFactory.Initialize(x => x.AddRegistry(new MyApplicationRegistry()));            
    }
}

public class MyApplicationRegistry : Registry
{
    public MyApplicationRegistry()
    {
        Scan(assemblyScanner =>
        {
            assemblyScanner.TheCallingAssembly();
            assemblyScanner.WithDefaultConventions();
        });
    }
}

The above code is initializing StructureMap with the MyApplicationRegistry that contains the rules for the interface & concrete type mappings. You may be wondering, “But I don’t see where IContactService is mapped to ContactService” and that is a very good question. The answer is that StuctureMap takes the Convention Over Configuration approach and tries to take some educational guesses based on a set of default naming conventions.

Lets say that your configuration isn’t following standard naming conventions. Can you still use StructureMap? Well, of course you can :) You have full control over the mappings and can set them up however you wish. The following is an example of me manually doing the mapping instead of using the default naming conventions. The Bootstrapper remains the same, so I only will show the code that is different below…

public class MyApplicationRegistry : Registry
{
    public MyApplicationRegistry()
    {
        ForRequestedType<IContactService>().TheDefaultIsConcreteType<ContactService>();
        ForRequestedType<IValidationRunner>().TheDefaultIsConcreteType<ValidationRunner>();
    }
}

Now lets focus on the StructureMapControllerFactory that we saw after we Configured StructureMap from the Global.asax. The StructureMapControllerFactory class that I am instantiating actually comes with the MVC Contrib project.  The contents of this class isn’t really all that complicated, but its one less thing you have to write by hand. The following is an example of a oversimplified implementation of the StructureMapControllerFactory that you could write yourself…

public class StructureMapControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        return ObjectFactory.GetInstance(controllerType) as IController;
    }
}

Since we separated our dependencies and used StructureMap for injection our application is now loosely coupled and our ability to Unit Test more areas has increased.

Stay tuned for a new series where I will upgrade a standard ASP.NET MVC project to ASP.NET MVC 2 and then integrate StructureMap, Moq, MbUnit, and suite of Unit Tests.

Blog , ,


Comments

9/21/2009 5:11:36 PM #
Using StructureMap with ASP.NET MVC

You've been kicked (a good thing) - Trackback from DotNetKicks.com
9/21/2009 9:17:09 PM #
Wow. Thanks for this post. I'm still learning .NET MVC, but this is helping me with a few things I need to work out in an app I'm trying to write.
9/21/2009 9:18:42 PM #
Nice blog post. I've always meant to play with StructureMap but I first cut my teeth on Windsor and I've never really looked back.

Also, was great chatting to you on the site - quite a surprise to actaully chat with you Smile

based on what we chatted about - Windsor isn't always xml config hell and we use quite a lot of convention over configuration as mentioned on our blog (in particular: blog.theagileworkshop.com/.../). The fluent registration api included in Windsor is also quite nice.

One thing we do use the xml config for is for environment specific properties that you want to allow an admin to change. Since Windsor can include seperate config files as part of its main config you can push these out so they are isolated and visible. This way your admins can modify them without affecting the actual structure of your app.

When this is combined with a strongly typed configuration model then it makes it very easy to have an EmailServer class depend on an EmailServerConfiguration for which the properties of the config class are all pulled from the properties using Windsor. We've found it to work quite well (but always open to suggestions).

Hmm - it's about time I actually blogged about this in more detail Smile
10/2/2009 6:44:18 PM #
#.think.in infoDose #43 (11th September - 22nd September)

#.think.in infoDose #43 (11th September - 22nd September)
11/9/2009 7:45:56 PM #
Thanks for this post. It has allowed me to get up and running with Structure Map in no time. I started out using what was an old version and tried going down the structuremap.config route, but had nothing but hassle. Now I am using the bootstrapper example. Thanks again.
11/11/2009 2:14:52 PM #
I really impressed by your post. Thank you for this great information, you write very well which i like very much.
12/18/2009 4:21:50 PM #
Good post man, just looking around some blogs, seems a pretty nice platform you are using.

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading



Olark Livehelp