Feb 27 2009

Using StructureMap with the ASP.NET MVC framework

Category: Uncategorizedbengtbe @ 06:13

In this post I will try to show you how to use StructureMap with the new ASP.NET MVC framework. You will need to have some basic knowledge about the ASP.NET MVC framework and Dependency Injection (DI)/Inversion of Control (IoC). The method described is not limited to StructureMap; if you prefer, you can of course use another DI/IoC tool.

The example starts with a UserController that has an dependency to a IUserService in the business layer, which again has a dependency to a IUserRepository in the database layer. The UserController uses inversion of control in regards to the IUserService. This means that the concrete UserService class must be injected into the UserController through the constructur:

public class UserController : Controller

{

    private readonly IUserService m_UserService;

 

    public UserController(IUserService userService)

    {

        m_UserService = userService;

    }

 

    public ActionResult Edit(int id)

    {

        return View(m_UserService.GetById(id));

    }

}

This is also called constructor injection. If you try to access this controller in the ASP.NET MVC framework you will get the following error:

No parameterless constructor defined for this object.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.MissingMethodException: No parameterless constructor defined for this object. 

By default, the ASP.NET MVC framework requires a parameterless constructor in the controllers. One way to fix this is to add a parameterless constructor:

public UserController() : this(new UserService(new UserRepository()))

{

}

This constructor is calling the other constructor using this passing in it's dependencies. Overloading the constructor in this manner is sometimes called Poor Man's Dependency Injection. It is a valid approach if you don't have access to an DI/IoC tool.

The downside of this approach is that you create a tight coupling between the controller and a concrete implementation of IUserService. You also have to take care of the dependencies (UserRepository) of the UserService class. Hence, the controller in the presentation layer now has a direct dependency to the UserRepository in database layer. If the UserRepository also had some dependencies then it really would start to get ugly :)

Let's fix this by using StructureMap's ObjectFactory to get an instance of IUserService.

public UserController() : this(ObjectFactory.GetInstance<IUserService>())

{

}

Much cleaner! The direct dependencies are now gone. However, every controller in your ASP.NET MVC application now needs to have an extra parameterless constructor and an reference to the ObjectFactory. This is just plumbing code, let's see if we can get rid of it all together.

The ASP.NET MVC framework uses the factory pattern to create controllers, and it also provides a base class called DefaultControllerFactory that you can derive from to customize the creation of controllers:

public class StructureMapControllerFactory : DefaultControllerFactory

{

    protected override IController GetControllerInstance(Type controllerType)

    {

        if(controllerType == null) return null;

 

        try

        {

            return ObjectFactory.GetInstance(controllerType) as Controller;

        }

        catch (StructureMapException)

        {

            System.Diagnostics.Debug.WriteLine(ObjectFactory.WhatDoIHave());

            throw;

        }

    }

}

The GetControllerInstance method is called when the framework needs a controller, specifed by its type. The code then asks StructureMap's ObjectFactory to create the controller. Since the controller is a concrete class (not an interface), it doesn't need to be configured with StructureMap. StructureMap will manage to create an instance of the controller and resolve all it's dependencies.

Now we have to tell the ASP.NET MVC framework to use the StructureMapControllerFactory. You can do this in the Application_Start method in Global.asax.cs:

protected void Application_Start()

{

    RegisterRoutes(RouteTable.Routes);

 

    StructureMapConfiguration.Configure();

 

    ControllerBuilder.Current.SetControllerFactory(new

       StructureMapControllerFactory());

}

As you can see the last line tells the framework to use the new factory. You can now remove the parameterless constructor, and the reference to StructureMap in the controllers.

Configuration of StructureMap

The second line in the Application_Start method is the configuration of StructureMap. This is done using the awesome new fluent configuration; no XML-configuration is needed!

public class StructureMapConfiguration

{

    public static void Configure()

    {

        ObjectFactory.Initialize(InitializeStructureMap);

    }

 

    private static void InitializeStructureMap(IInitializationExpression x)

    {

        x.Scan(y =>

                   {

                       y.Assembly("MvcWithNHibernate.Repositories");

                       y.Assembly("MvcWithNHibernate.Services");

                       y.With<DefaultConventionScanner>();

                   }

            );

    }

}

As you can see this uses the DefaultConventionScanner. This scanner uses a naming convention to automatically register the class UserService with the the interface IUserService, and the class UserRepository with IUserRepository.

Summary

In this post I have shown you how to use StructureMap with the new ASP.NET MVC framework. I described how you can implement your own controller factory to reduce the plumbing code in the controllers. When I first started to use StructureMap I had several calls to ObjectFactory.GetInstance throughout the solutions. A much better approach is to reduce these calls as much as possible. In this solution the only call to ObjectFactory.GetInstance is in the controller factory.

I also gave you a short glimpse of how you could configure StructureMap using the new fluent configuration and the default convention scanner. This follows the Convention over Configuration (CoC) paradigm made popular by Ruby on Rails. By following strict naming conventions, you don't need to configure the specific interfaces and classes with the DI/IoC tool, they are automatically added based on the conventions. In StructureMap you can also create your own auto register conventions.

kick it on DotNetKicks.com   Shout it

Tags: ,