ninja star Simple Dependency Injection using a Custom MVC Controller Factory

by Michael Ceranski, posted on August 30 2010

Whenever I develop an MVC application there is always some degree of data access required. As a best practice, I usually define a interface that my repository objects will adhere to. Creating an interface is generally a requirement for Dependency Injection (DI). DI is a very important pattern if you plan on doing any unit testing later on. For the purpose of this demo, I am going to keep things simple and only create a fake repository.  Here is the code:

public interface IRepository
{
    Person GetPerson( int id ); 
}

public class FakeRepository : IRepository
{        
    public Person GetPerson( int id )
    {
        return new Person { Id = id, FirstName = "Mike", LastName = "Ceranski" };
    }
}

Obviously, in a real-world application you would probably utilize the Entity Framework or LINQ to SQL in order to implement the IRepository interface. However, for the purposes of this demo the FakeRepository illustrates the point. Moving on, the next step is to create a base controller class which all of the other controllers in the application will derive from. The BaseController class has a IRepository property which gets set by the constructor. By having this constructor we can easily “inject” our repository objects.

public class BaseController : Controller
{        
    public IRepository Repository { get; private set; }

    public BaseController(IRepository repository)
    {
        Repository = repository;
    }
}

So now its time to create the "Person" controller which inherits from the BaseController class. We also add a single action named "Details" which will get return a Person model from the repository:

public class PersonController : BaseController
{
    public PersonController(IRepository repository) : base(repository) { }

    public ActionResult Details( int id = 1)
    {
        return View( Repository.GetPerson(id) );
    }
}

So at this point you may think your work is done, right? Well, if you were to run the application at this point and try to view the Details for the person with the ID 1 (“/Person/Details/1”) you would get an error stating that “No parameterless constructor is defined for this object”. That’s because the default controller factory used in MVC always uses the default constructor to create a controller. Since our PersonController does not have a parameterless constuctor defined, the application throws an error. Obviously, we will need to do a little more work in order to make MVC use our DI friendly constructor. Luckily this is easily accomplished by creating and registering our own custom controller factory. Here is the code:

public class CustomControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
    {
        return Activator.CreateInstance(controllerType, new FakeRepository()) as IController;
    }
}

The code above overrides the CreateController method. It uses the Activator.CreateInstance method to create the controller using our custom constructor and passes in a new instance of the FakeRepository class. So now the final step is to register the CustomControllerFactory in the Global.asax:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterRoutes(RouteTable.Routes);

    ControllerBuilder.Current.SetControllerFactory(typeof(CustomControllerFactory));
}

Now, when I run my application and access the URL "/Person/Details/1" I get the following results:

image

The end result is a MVC application which allows you to easily inject repository objects for testing purposes!  The sample code is attached.

DI_MVC_Example.zip (252.38 kb)

blog comments powered by Disqus

About the author

MikeMichael Ceranski is a developer specializing in the .NET stack. I have spent time as a DBA, Web Developer and even a network engineer. Up til now most of my career has revolved around the .NET stack but I have recently taken an interest in microcontrollers which has forced me to get acquainted with lower level languages such as C, and C++.

View my resume

Sponsors