ASP.NET MVC Tip: Dependency Injection with StructureMap

In this tip, I demonstrate how you can use the dependency injection with StructureMap within an MVC application. StructureMap is an open source Dependency Injection framework for the .NET platform and has been in use since 2004 .StructureMap supports both setter and constructor injection and also offers testing and diagnostic features such as logging, tracing and wiring of mock objects. For download and more details visit http://structuremap.sourceforge.net/default.htm. Jeremy D Miller’s (Creator of StructureMap) blog is a great learning resource for StructureMap and good object oriented programming thoughts.

 

If you are not familiar with Dependency Injection (DI) and Inversion of Control (IoC), read Martin Fowler’s article Inversion of Control Containers and the Dependency Injection pattern . A Dependency Injection framework injects the dependencies into a class when the dependencies are needed. Dependency Injection enables looser coupling between classes and their dependencies and can be improve architectural qualities of an object oriented business application.

 

Dependency Injection provides the following advantages,

 

1) Enables looser coupling between classes and their dependencies

2) It provides better testability of an application

3) It removes the need for clients to know about their dependencies and how to   create them.

4) It avoid behind the problems of creating factory classes, by moving construction responsibility to a framework.

5) Improve the architecture quality of an object oriented system.

 

In this tip, I show how you can use the StructureMap to perform Dependency Injection within an ASP.NET MVC application.  In this tip, I will show you how to perform constructor injection. Constructor Injection will push dependencies into a concrete class through constructor arguments.

 

The below code listings show that a controller class and its dependent classes.

 

 

Listing 1 – CategoryController

 

public class CategoryController : Controller {

 ICategoryService  _categoryService = null;

 

 public CategoryController(ICategoryService categoryService) {         

    _categoryService = categoryService;

   }       

 public ActionResult List(int? page) {

  var categories = _categoryService.GetCategories(page ?? 0, 10);

    return View("CategoryList",categories);

  }


 

Listing 2 – ICategoryService

 

public interface ICategoryService {

  PagedList<Category> GetCategories(int pageIndex,int pageSize);       

 }

                               

Listing 3 – CategoryService

 

public class CategoryService : ICategoryService  {

 ICategoryRepository _repository = null;       

 public CategoryService(ICategoryRepository repository) {

     _repository = repository;

     if (_repository == null) {

         throw new InvalidOperationException("Repository cannot be null");

        }

public PagedList<Category> GetCategories(int pageIndex,int pageSize) {

    return _repository.GetCategories().ToPagedList<Category>(pageIndex, pageSize);

        }

    }

 

Listing 4 – ICategoryRepository

 

public interface ICategoryRepository {

      IQueryable<Category> GetCategories();

    }

 

Listing 5 – CategoryRepository

 

public class CategoryRepository : ICategoryRepository  {

  DBDataContext _db;

  public CategoryRepository(DBDataContext dataContext) {           

     _db = dataContext;           

   }

       

 public IQueryable<Category> GetCategories() {

    return from c in _db.Categories

      select new Category {

        ID=c.ID,

        Name=c.Name,

        Description=c.Description,

        CategoryType = c.CategoryType

      };

     }

    }

 

Depedencies

 

The CategoryController has a dependency with ICategoryService. The concrete implementation of ICategoryService, i.e. CategoryService has a dependency with ICategoryRepository. The concrete implementation of ICategoryRepository, i.e. CategoryRepository has a dependency with DBDataContext. When we calling action methods of Category controller, we need to create objects CategoryService, CategoryRepository and DBDataContext.

 

The below steps will configure StructureMap to perform constructor injection in our ASP.NET MVC application.

 

Step 1 – Add reference to StructureMap

 

Add a reference to StructureMap.dll.

Download available from http://sourceforge.net/projects/structuremap/

 

Step 2 – Add StructureMap configuration

 

using StructureMap;

using StructureMap.Configuration.DSL;

using StructureMap.Configuration;

using StructureMap.Pipeline;

 

public class DomainRegistry : Registry {

   protected override void configure() {

    ForRequestedType<ICategoryService>()

       .TheDefaultIsConcreteType<CategoryService>();

   ForRequestedType<ICategoryRepository>()

      .TheDefaultIsConcreteType<CategoryRepository>();

        }

    }

 

public class DBServiceRegistry:Registry {

  protected override void configure() {

     ForRequestedType<DBDataContext >()

      .TheDefaultIs(() => new DBDataContext())

        .CacheBy(InstanceScope.Hybrid);

        }

    }

 

The above configuration tells StructureMap to inject CategoryService when there is a request for ICategoryService. And also inject CategoryRepository when there is a request for ICategoryRepository. The CategoryRepository class has a dependency with Linq DataContext DBDataContext. So we configure that create a new instance DBDataContext when there is request for DBDataContext. we are telling the StructureMapConfiguration to make hybrid instance scope. The below are the different type of instance scoping,

 

   1. PerRequest - The default operation.  A new instance will be created for each request.

   2. Singleton - A single instance will be shared across all requests

   3. ThreadLocal - A single instance will be created for each requesting thread.  Caches the instances with ThreadLocalStorage.

   4. HttpContext - A single instance will be created for each HttpContext.  Caches the instances in the HttpContext.Items collection.

   5. Hybrid - Uses HttpContext storage if it exists, otherwise uses ThreadLocal storage

 

Step 3 – Register with StructureMap registry

 

The below code will add instances of DomainRegistry and DBServiceRegistry into StructureMapConfiguration registry.

 

using StructureMap;

public static class Bootstrapper {

 public static void ConfigureStructureMap() {

   StructureMapConfiguration.AddRegistry(new DBServiceRegistry());

   StructureMapConfiguration.AddRegistry(new DomainRegistry ());

  }

 }

 

Step 4 – Controller Factory for StructureMap

 

using StructureMap;

public class StructureMapControllerFactory : DefaultControllerFactory {

  protected override IController GetControllerInstance(Type controllerType) {

   try {

      return ObjectFactory.GetInstance(controllerType) as Controller;

    }

catch (StructureMapException) {

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

      throw;

   }

  }

 

 

The controller factory is responsible for creating controller instances. We extend the built in default controller factory with our own factory for working StructureMap with ASP.NET MVC .

 

Step 5 – Modify Global.asax.cs

 

protected void Application_Start() {

  RegisterRoutes(RouteTable.Routes);

   //Configure StructureMapConfiguration

   Bootstrapper.ConfigureStructureMap();

    //Set current Controller factory as StructureMapControllerFactory

    ControllerBuilder.Current.SetControllerFactory( new myFinance.Web.Controllers.StructureMapControllerFactory()

   );

 }

 

The above code will set our controller factory and configure StructureMap configuration when our ASP.NET MVC application is started.

 

Summary

 

In this tip, I demonstrated how you can use the StructureMap to perform Dependency Injection through constructor injection within an ASP.NET MVC application. One of the greatest advantages of ASP.NET MVC is testability. With a Dependency Injection framework, we can make our ASP.NET MVC application is fully testable and maintainable.


16 Comments

  • This was the one of articles i was looking for.
    Thanks a lot Shiju

  • Great sample, I like it. Thanks Shiju.

  • Hey,
    thanks for posting this blog.....i am looking in same ...but am not able to find this kind blog.......
    Cheersssssssssssss!!!!!!!!!!!!!
    Pawan Pawar

  • Hi,

    Can you achieve this with the new version of StructureMap 2.5 (since a few breaking changes happened in the API) ?

    ForRequestedType()
    .TheDefaultIs(() => new DBDataContext())
    .CacheBy(InstanceScope.Hybrid)

    Do you have an idea of how I could did it with the latest version ?

    Thanks !

  • This is great...thanks a bunch. I'm having one problem though. I'm trying to use InstanceScope.HttpContext or InstanceScope.HttpSession but it doesn't seem to be working as advertised. When I set it to InstanceScope.Singleton, that works, I only ever get back one instance of a given type. However, the other two, HttpContext/HttpSession give me back a new instance every time. Any ideas?

  • Hello
    The problem with this solution IMHO is that you kill the object graph in CategoryRepository. The Repository-pattern is somehow outdated in a pure data-centric approach, of cause one can still use the Repository-pattern in Linq driven datalayer, but.... IMHO you've to choose, Repository or Linq or better use a Repository (which cannot be named Repository (DDD)) and pull those data classes up into your service.

  • Hello,

    Is it possible to download the code?

    TIA
    Yaz

  • Best, most comprehensive post I've seen on getting StructureMap to work with ASP.NET MVC. This is the complete package - exactly what I needed to see, but couldn't find elsewhere on the web.

    Well done.

  • May I ask you?...
    How to get registered services in code directly (not in constructor)?

    something Like IoC container:
    ...
    IMyService iMyService = IoC.Container.Resolve();
    ...

    P.S.: Excuse my English

  • Thank you a lot!!!

  • hi! I've a little probleme: In the class BootStrapper I've this error
    The name 'StructureMapConfiguration' does not exist in the current context

    and in the DBServiceRegistry i've this one:

    'gestionutilisateur.StructureMap.DBServiceRegistry.configure()': no suitable method found to override

    I have the StructureMap.dll in the reference and I've put those using:
    using StructureMap;
    using StructureMap.Configuration.DSL;
    using StructureMap.Configuration;
    using StructureMap.Pipeline;

    Hope you have an anwer for me, thanks ;)

  • Hi! I've try this, first with version 2.6 and it wasn't working and with 2.5 but I've now this error:

    'StructureMap.Configuration.DSL.Expressions.CreatePluginFamilyExpression' does not contain a definition for 'TheDefaultIs' and no extension method 'TheDefaultIs' accepting a first argument of type 'StructureMap.Configuration.DSL.Expressions.CreatePluginFamilyExpression' could be found (are you missing a using directive or an assembly reference?)
    help please :'(

  • Isn't missing the Controller Registry???

  • Asp net mvc tip dependency injection with structuremap.. Corking :)

  • I followed all the instructions, but MVC 3.0 gives me an error "Cannot create an instance of an interface."
    The custom factory is being invoked. I can call ObjectFactory.GetInstance just fine.

    Another thing -> Articles override is out dated. MVC 3 now takes RequestContext requestContext as first param, Type as 2nd.

    Anyone have ideas?

  • Very helpful, One of the article I was looking for.

Comments have been disabled for this content.