Using StructureMap with the ASP.NET MVC framework

Friday, 27 February 2009 06:13 by bengtbe

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

Comments

February 4. 2009 14:13

Kazi Manzur Rashid

Just a correction I think you do not have to do this, SM automatically injects it:
public UserController() : this(ObjectFactory.GetInstance<IUserService>())

Kazi Manzur Rashid

February 4. 2009 14:43

bengtbe

Just a correction I think you do not have to do this, SM automatically injects it:
public UserController() : this(ObjectFactory.GetInstance<IUserService>())


Thanks for your comment Kazi. I do belive that you have to call the parameterless constructor at that point, because it is not StructureMap that creates the controller, it's the ASP.NET MVC framework. After we have created the StructureMapControllerFactory then we no longer need it, as I also write:

You can now remove the parameterless constructor, and the reference to StructureMap in the controllers.

Please correct me if you still think I'm wrong Smile

bengtbe

February 4. 2009 15:34

Kazi Manzur Rashid

Sorry I have missed that completely. Great Article.

Kazi Manzur Rashid

February 4. 2009 18:56

trackback

Trackback from DotNetKicks.com

Using StructureMap with the ASP.NET MVC framework

DotNetKicks.com

February 4. 2009 20:09

trackback

Trackback from DotNetShoutout

Using StructureMap with the ASP.NET MVC framework

DotNetShoutout

February 11. 2009 13:00

pingback

Pingback from sleeplesscoder.com

A bit about using StructureMap and WebForms | Sleepless Coder

sleeplesscoder.com

March 28. 2009 09:26

lazer epilasyon

nices article.

lazer epilasyon

May 24. 2009 08:27

Sandy

I've followed your code, but i'm getting error message "StructureMap Exception Code:  202. No Default Instance defined for PluginFamily" when click http://localhost:54496/Account/LogOn

Sandy

May 24. 2009 13:15

bengtbe

Hi Sandy,

The reason you see that error is because you are using the default AccountController that follows the ASP.NET MVC project. This controller has two constructors:

1. An empty (takes zero arguments):

public AccountController() : this(null, null)

2. One that take two arguments:

public AccountController(IFormsAuthentication formsAuth, IMembershipService service)

By default ASP.NET MVC will use the empty constructor (the other is used by the tests that follows the project). StructureMap however will, by default, use the constructor with the most parameter, but no one has told it how to resolve the parameters.

You can fix this in 3 different ways:

1. Tell StructureMap how to resolve those parameters in InitializeStructureMap:

x.ForRequestedType<IFormsAuthentication>()
   .TheDefaultIsConcreteType<FormsAuthenticationService>();

x.ForRequestedType<IMembershipService>()
   .TheDefaultIsConcreteType<AccountMembershipService>();

x.ForRequestedType<MembershipProvider>()
   .TheDefault.IsThis(Membership.Provider);


2. Tell StructureMap to use the empty constructor in InitializeStructureMap:

x.ForRequestedType<AccountController>()
   .TheDefault.Is.ConstructedBy(() => new AccountController());


3. Mark the empty controller with the DefaultConstructor attribute:

[StructureMap.DefaultConstructor]
public AccountController() : this(null, null)
{
}


Just choose the fix that you like the most Smile

bengtbe

May 25. 2009 02:10

Sandy

Yes, it's working.
Thank you, Sir.

Sandy

October 9. 2009 13:09

paul

Do you ever offer download code samples? That would be great as most examples on the web are "Demo code" and leave out all the important stuff.

Thanks

paul

October 10. 2009 19:28

Bengt Berge

Hi Paul. I haven't offered any code samples yet, but maybe I will in the future. I agree that there is to much "Demo code" on the web.

If you want to check out some good ASP.NET MVC code then you might want to check out the following projects:

CodeCampServer: http://code.google.com/p/codecampserver
CodeBetter Canvas: http://code.google.com/p/codebettercanvas/
Sharp Architecture: http://wiki.sharparchitecture.net

Bengt Berge

October 10. 2009 19:52

paul

Thanks for the reply Bengt. I have started reading Pro ASP.NET MVC Framwork but it uses L2S in all the examples similar to nerddinner. He also uses an IoC that requires XML mapping and after reading this post I am starting to think the book in out dated??? Have you read this book?

Thanks for the code examples I will definitely check them out Smile

-Paul

paul

October 12. 2009 00:05

Bengt Berge

Hi again Paul. I have read the book by Steven Sanderson and it is actually very good. It will give you a very good understanding of the ASP.NET MVC framework. In the book he uses the Castle Windsor IoC container, and this container does also support configuration with C# code. A search for "Castle Windsor" and "Fluent" will give you some examples of this.

If you like the code in CodeCampServer then you can also check out the ASP.NET MVC in Action book. I believe that this code was written for this book. I'm planning to read it soon.

Bengt Berge

October 16. 2009 16:30

Paul

Thanks for the info. I think I am going to use StructureMap and nHibernate for the examples in the book as I don't really want to learn L2S. I am also reading Microsoft .NET: Architecting Applications for the Enterprise and enjoying it. Thanks again for the info.

Paul

Comments are closed