Click here to Skip to main content
Click here to Skip to main content
Articles » Web Development » ASP.NET » General » Revisions
 

ASP.NET MVC controller dependency injection for beginners

, 12 Mar 2013 CPOL
Rate this:
Please Sign up or sign in to vote.
In this article I demonastrate a very simple and straightforward way to inject controller dependency to ASP.NET MVC framework with a constructor.
This is an old version of the currently published article.

Introduction   

In a simple statement if I want to define an ASP.NET MVC controller then I can say that it has classes which are responsible for receiving and processing incoming requests, handling client input, and sending response back to the client. Controllers also act as a coordinator between Model (Business) and View (Presentation). ASP.NET MVC framework itself create controller object at run time. Only prerequisite is controller class must have a parameter less constructor. But if you need to pass some objects with constructor then what will happen? Simply framework failed to create controller object. In that scenario we need to create controller object by our self and injection dependency there.

There are many ways to inject dependency to a class. For example it might be Property setter injection, Method injection, Constructor injection. In this article I will explain how to inject controller dependency to ASP.NET MVC framework with constructor.  Without built custom controller factory, dependency injection to controller is not possible, so I also show how to create a very simple custom controller factory and register it to ASP.NET MVC framework.

Why controller dependency injection is needed 

In real life application development, you will see almost all ASP.NET MVC applications need to inject dependency component. You can create component directly inside controller instead of inject that dependency. In that case the controller will be dependent (strongly coupled) on that component. If any component implementation changed or new version of that component released then you need to change controller class itself. Another problem will face when you go for unit testing. You cannot unit test of those controllers independently (within isolation). You cannot take mocking feature from unit testing framework. Without mocking, you cannot unit test your code in isolation.  

Controller static structure 

ASP.NET MVC framework’s controller structure is defined inside abstract controller class. If want to create any controller, create a class which will be inherited from Controller abstract class.  The UML class diagram of controller class and its hierarchy looks  

1

Controller root is IController interface. Its abstract implementation is ControllerBase class. Another controller abstract class is inherited from ControllerBase class. All our custom controller classes should be inherited from Controller abstract class or its child class. 

Simple custom controller definition 

If you create an ASP.NET MVC project, you will get two default controllers: AccountController and HomeController

2

If you look at the HomeController class definition, the class has no constructor. 

public class HomeController : Controller
{
    public ActionResult Index()
    {
        ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
        return View();
    }
    public ActionResult About()
    {
        ViewBag.Message = "Your app description page.";
        return View();
    }
} 

We all know that if there is no constructor defined then at compile time .NET Framework creates a default parameter-less constructor like as follows

public class HomeController : Controller
{
    public HomeController()
    {
    }
} 

Now create ILogger interface and its implementation DefaultLogger class for using Home controller class. I want to inject it throw constructor. 

public interface ILogger
{
    void Log(string logData);
}
public class DefaultLogger : ILogger
{
    public void Log(string logData)
    {
        System.Diagnostics.Debug.WriteLine(logData, "default");
    }
} 

Now HomeController with ILogger constructor injection looks like 

public class HomeController : Controller
{
    private ILogger _logger;
    public HomeController(ILogger logger)
    {
        _logger = logger;
    }
} 

Still I do not find any place where I can create DefaultLogger object in my codebase and though I am not creating HomeController object by myself so I do not find the place where I can create DefaultLogger object and how I can pass it to the HomeController with defined parameterized constructor HomeController (ILogger logger). In that state if I build my project it will build without any problem. But in runtime it will throw exception. Exception details in error page like as follow 

4

See stack trace above, DefaultContollerActivator throw MissingMethodException. If you go MSDN, search when the exception is raised, will find there and it clearly mentions “The exception that is thrown when there is an attempt to dynamically access a method that does not exist.” That is the inner exception message. If see next  exception InvalidOperationException, it is actually wrapped MissingMethodException and there more user friendly message generated that is “Make sure that the controller has a parameterless public constructor.” If make workable to Home controller then it must have a parameterless constructor and framework will create controller object with the help of that constructor. Question will rise how I can pass DefaultLogger object to that controller? Please keep your patience. 

How framework create controllers 

Before start to dependency injection process of DefaultLogger object to controller, we should have a clear picture how MVC framework create controller object. IControllerFactory interface is responsible for creating controller object. DefaultControllerFactory is its default framework provided implementation. If you add a parameter less constructor to the HomeController class and set break point there and run application with
debug mode, you can see that IControllerFactory contain DefaultControllerFactory object. DefaultControllerFactory has various methods 

like Create, GetControllerInstance, CreateController are playing role for creating HomeController object. You know that ASP.NET MVC framework is open source project, so if you want to know more details about those methods then you can download its source code and see the implementation. ASP.NET MVC implement abstract factory design pattern for creating controller class. If you debug code and see value with quick watch then you can see that DefaultControllerFactory is automatically created as CurrentControllerFactory (IControllerFactory). 

Why need to create custom controller factory 

Already you know that Default controller factory create controller object using parameter less constructor from controller class. But we need parameterize constructor so that we can inject our component dependency though that constructor. So DefaultControllerFactory current implementation does not support our requirement. So we need a new controller factory class. 

Create custom controller factory 

We can create a new controller factory by implementing IControllerFactory interface. Suppose our new controller factory named CustomControllerFactory. So its implementation looks like 

public class CustomontrollerFactory : IControllerFactory
{
    public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
    {
        ILogger logger = new DefaultLogger();
        var controller = new HomeController(logger);
        return controller;
    }
    public System.Web.SessionState.SessionStateBehavior GetControllerSessionBehavior(
       System.Web.Routing.RequestContext requestContext, string controllerName)
    {
        return SessionStateBehavior.Default;
    }
    public void ReleaseController(IController controller)
    {
        IDisposable disposable = controller as IDisposable;
        if (disposable != null)
            disposable.Dispose();
    }
} 

You need to register CustomControllerFactory to MVC framework. We can do it inside Application_Start event. 

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
	RegisterCustomControllerFactory ();
    }
}
private void RegisterCustomControllerFactory ()
{
    IControllerFactory factory = new CustomControllerFactory();
    ControllerBuilder.Current.SetControllerFactory(factory);
} 

If you run application and see that your parameterless HomeController constructor is not called, instead parameterized HomeController(ILogger logger) is called by framework. 

You can create your controller creation with little generic way using reflection. 

public class CustomControllerFactory : IControllerFactory
{
    private readonly string _controllerNamespace;
    public CustomControllerFactory(string controllerNamespace)
    {
        _controllerNamespace = controllerNamespace;
    }
    public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
    {
        ILogger logger = new DefaultLogger();
        Type controllerType = Type.GetType(string.Concat(_controllerNamespace, ".", controllerName, "Controller"));
        IController controller = Activator.CreateInstance(controllerType, new[] { logger }) as Controller;
        return controller;
    }
} 

First you need to create controller type object from controller full name. Then you create controller object at run time using Type.GetType method and inject dependency object to that object through reflection. In current code implementation has some problems which are: i) You need to pass controller namespace (using constructor) so every controller should be same namespace and ii) all controllers need single parameterized construction which accept ILogger object only. Without that it will throw MissingMethodException.  

Another approach 

Another way you can create your own controller factory. Though MVC framework’s default implementation of IControllerFactory is DefaultControllerFactory and it is not a sealed class. So you can extend that class and override whatever you need to changed. One implementation like 

public class CustomControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
    {
        ILogger logger = new DefaultLogger();
        IController controller = Activator.CreateInstance(controllerType, new[] { logger }) as Controller;
        return controller;
    }
} 

just created my own CustomControllerFactory class inherited from DefaultControllerFactory and override GetControllerInstance method. 

Take MEF's help for creating custom controller factory 

In real life project you will see experts are using IOC containers inside controller factory for creating/fetching the Controller object. Why because many problem need to raise and handle if you try to dynamically create dependent object and controller class. So it is a better approach to use IOC container to our project and register all my dependent objects there and use it. You can use various IOC containers like Castle Windsor, Unity, NInject there. I will demonstrate how MEF is used there. By the way MEF comes with .NET framework 4.0 so no third party component dependency there. First you take to reference of system.ComponentModel.Composition to your project. 

Then need to create custom Controller Factory. The name of the controller factory is MefControllerFactory

public class MefControllerFactory : DefaultControllerFactory
{
    private readonly CompositionContainer _container;
    public MefControllerFactory(CompositionContainer container)
    {
        _container = container;
    }
    protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
    {
        Lazy<object, object> export = _container.GetExports(controllerType, null, null).FirstOrDefault();
 
        return null == export
                            ? base.GetControllerInstance(requestContext, controllerType)
                            : (IController)export.Value;
    }
    public override void ReleaseController(IController controller)
    {
        ((IDisposable)controller).Dispose();
    }
} 

CompositContainer object is works like as IOC container here. Inside GetControllerInstance method I fetch controller object from that. If found null value then I fetch it from default controller (base class) object otherwise from CompositContainer object. After creating MefControllerFactory class we need to register it to MVC framework. Registration code in Application Start event 

protected void Application_Start()
{
    var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
    var composition = new CompositionContainer(catalog);
    IControllerFactory mefControllerFactory = new MefControllerFactory(composition);
    ControllerBuilder.Current.SetControllerFactory(mefControllerFactory);
} 

I use InheritedExportAttributeExportAttribute,  PartCreationPolicyAttribute of MEF to interface ILoggerHomeController.  Based on these attributes MEF framework create object. Just one important think you should remember that when use MEF you should decorate your controller through PartCreationPolicyAttribute to your controllers and set controllers life time as create object per request policy.  [PartCreationPolicy (CreationPolicy.NonShared)] Without that you will get an error.

 

Points of Interest  

I tried to explain various ways to create controller factory and inject its dependency in a very simple and state forward way. First 1 or 2 approach is just making understandable to the process of building and injecting controller and its dependency. You should not use that approach directly to the real life application. You can more reach on MEF and choose MEF approach to use that to your real life projects. Near future I have a plan to write another article that will demonstrate to use various IOC containers like Windsor, Unity, NInject etc. to inject controller dependency injection and a comparative study with them. In my sample downloadable code I used visual studio 2012 with .NET framework 4.5. Anyone can download and play with that. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

S. M. Ahasan Habib
Software Developer (Senior) The Jaxara IT Ltd.
Bangladesh Bangladesh
Mostly I work with MS technologies (ASP.NET MVC, WPF, C#, SQL Server, SSRS, SharePoint, Entity Framework, MSTest, Enterprise Library, MEF, WCF, WebAPI, MS Excel, IIS).
Non MS technologies which I love and use (Resharper, NHiberNet, JQuery, AngularJS, KnockoutJS, NodeJS, Python, MSpec, RihnoMock, Crystal Report, Subversion, Crome)

Comments and Discussions


Discussions posted for the Published version of this article. Posting a message here will take you to the publicly available article in order to continue your conversation in public.
 
GeneralMy vote of 5 Pinmemberphq0112-May-13 4:37 
GeneralRe: My vote of 5 PinmemberS. M. Ahasan Habib12-Sep-13 1:40 
GeneralMy vote of 5 PinmemberMember 98032559-May-13 1:09 
GeneralRe: My vote of 5 PinmemberS. M. Ahasan Habib12-Sep-13 1:40 
GeneralMy vote of 5 PinmemberMihai MOGA12-Apr-13 19:17 
GeneralRe: My vote of 5 PinmemberS. M. Ahasan Habib13-Apr-13 6:21 
GeneralMy vote of 5 PinmemberLilith Ortega4-Apr-13 22:13 
GeneralRe: My vote of 5 PinmemberS. M. Ahasan Habib4-Apr-13 22:27 
GeneralMy vote of 5 PinmemberRazan Paul (Raju)28-Mar-13 2:57 
GeneralRe: My vote of 5 PinmemberS. M. Ahasan Habib28-Mar-13 4:24 
GeneralMy vote of 4 Pinmembersameer26-Mar-13 23:17 
GeneralRe: My vote of 4 PinmemberS. M. Ahasan Habib26-Mar-13 23:22 
QuestionGood stuff PinmemberfunkyAnu26-Mar-13 19:25 
AnswerRe: Good stuff PinmemberS. M. Ahasan Habib26-Mar-13 21:10 
AnswerRe: Good stuff PinmemberS. M. Ahasan Habib12-Sep-13 1:40 
QuestionIoC = 4x slower and code bloating PinmemberMadmaximus25-Mar-13 15:11 
AnswerRe: IoC = 4x slower and code bloating PinmemberS. M. Ahasan Habib25-Mar-13 21:42 
Generalexcellent! PinmemberRodrigo Barros Pascual25-Mar-13 8:15 
GeneralRe: excellent! [modified] PinmemberS. M. Ahasan Habib25-Mar-13 21:43 
GeneralMy vote of 5 PinmemberMonjurul Habib20-Mar-13 9:12 
GeneralRe: My vote of 5 PinmemberS. M. Ahasan Habib20-Mar-13 15:25 
GeneralMy vote of 4 Pinmembertvj0819-Mar-13 8:17 
GeneralRe: My vote of 4 PinmemberS. M. Ahasan Habib19-Mar-13 15:37 
GeneralMy vote of 3 PinmemberSCADirector19-Mar-13 7:38 
GeneralRe: My vote of 3 PinmemberS. M. Ahasan Habib19-Mar-13 15:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.141015.1 | Last Updated 12 Mar 2013
Article Copyright 2013 by S. M. Ahasan Habib
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid