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.


Published Friday, October 10, 2008 10:56 PM by shiju
Filed under: , ,

Comments

# re: ASP.NET MVC Tip: Dependency Injection with StructureMap

Friday, October 10, 2008 11:33 PM by Kim

This was the one of articles i was looking for.

Thanks a lot Shiju

# re: ASP.NET MVC Tip: Dependency Injection with StructureMap

Thursday, October 16, 2008 12:27 PM by koistya

Great sample, I like it. Thanks Shiju.

# re: ASP.NET MVC Tip: Dependency Injection with StructureMap

Friday, October 17, 2008 2:12 PM by Pawan Pawar

Hey,

thanks for posting this blog.....i am looking in same ...but am not able to find this kind  blog.......

Cheersssssssssssss!!!!!!!!!!!!!

Pawan Pawar

# re: ASP.NET MVC Tip: Dependency Injection with StructureMap

Friday, November 14, 2008 7:38 AM by cik

Hi,

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

ForRequestedType<DBDataContext >()

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

   .CacheBy(InstanceScope.Hybrid)

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

Thanks !  

# re: ASP.NET MVC Tip: Dependency Injection with StructureMap

Thursday, February 26, 2009 5:18 PM by JC Grubbs

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?

# re: ASP.NET MVC Tip: Dependency Injection with StructureMap

Thursday, March 5, 2009 4:47 AM by Janus Knudsen

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.

# re: ASP.NET MVC Tip: Dependency Injection with StructureMap

Tuesday, March 31, 2009 7:45 PM by Yazid

Hello,

Is it possible to download the code?

TIA

Yaz

# re: ASP.NET MVC Tip: Dependency Injection with StructureMap

Wednesday, June 17, 2009 1:24 PM by Chris Holmes

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.

# re: ASP.NET MVC Tip: Dependency Injection with StructureMap

Tuesday, July 14, 2009 3:39 AM by firmguide

May I ask you?...

How to get registered services in code directly (not in constructor)?

something Like IoC container:

...

IMyService iMyService = IoC.Container.Resolve<IMyService>();

...

P.S.: Excuse my English

# re: ASP.NET MVC Tip: Dependency Injection with StructureMap

Monday, March 22, 2010 1:40 AM by Nova Concept

Thank you a lot!!!

# re: ASP.NET MVC Tip: Dependency Injection with StructureMap

Saturday, March 27, 2010 7:42 AM by asma01

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 ;)

# re: ASP.NET MVC Tip: Dependency Injection with StructureMap

Saturday, March 27, 2010 6:48 PM by asma01

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<gestionutilisateur.Models.gestionutilisateurDBentitiesDataContext>' does not contain a definition for 'TheDefaultIs' and no extension method 'TheDefaultIs' accepting a first argument of type 'StructureMap.Configuration.DSL.Expressions.CreatePluginFamilyExpression<gestionutilisateur.Models.gestionutilisateurDBentitiesDataContext>' could be found (are you missing a using directive or an assembly reference?)

help please :'(

# re: ASP.NET MVC Tip: Dependency Injection with StructureMap

Tuesday, February 8, 2011 9:22 AM by Daniel

Isn't missing the Controller Registry???

# re: ASP.NET MVC Tip: Dependency Injection with StructureMap

Saturday, March 26, 2011 3:53 AM by weblogs.asp.net

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

# re: ASP.NET MVC Tip: Dependency Injection with StructureMap

Monday, June 27, 2011 9:02 PM by brad

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?

# re: ASP.NET MVC Tip: Dependency Injection with StructureMap

Thursday, May 17, 2012 3:55 AM by Kinshuk

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

Leave a Comment

(required) 
(required) 
(optional)
(required)