Introduction
In a simple statement if I want to define an ASP.NET MVC controller then
I can say that classes that are responsible for receiving and processing incoming http 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 creates controller objects at run time. There is only one prerequisite, that 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 fail to create controller object. In that scenario we need
to create controller object by our self and injection dependency there.
There are many ways you can inject dependency to a class. For example, it might be Property setter, Method, Constructor injection.
In this article I will explain how to inject controller dependency to ASP.NET MVC framework with constructor injection. Without create custom controller
factory, dependency injection to controllers are not possible. So I will also explain how to create a very simple custom controller factory and register it to
ASP.NET MVC framework. I will also demonstrate a way to inject dependency to a controller using Managed Extensible Framework (MEF).
Why controller dependency injection
In real life application development, you will see almost all
ASP.NET MVC applications are needed to inject its dependent component. You can create component directly inside the controller instead of inject them. In that case the controller will be strongly coupled on those components. If any component's implementation is changed or new version of that component is released then you must change controller class itself. Another problem you will face when you will do unit test. You cannot do unit test of those controllers independently (within isolation). You cannot take mocking features from unit testing framework. Without mocking, you cannot do unit test of your code in isolated environment.
Controller static structure
ASP.NET MVC framework’s controller structure is defined inside a abstract class named Controller. If you want to create any controller, first you will create a class which must be inherited from abstract class Controller
. The UML class diagram of controller class and its hierarchy looks as follows
All controllers root is
IController
interface. Its abstract implementation is
ControllerBase
class. Another abstract class is inherited from
ControllerBase
class and name of that class is Controller. 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
.
If you look at the HomeController
class definition, then you will see, 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.
public class HomeController : Controller
{
public HomeController()
{
}
}
Now I created ILogger
interface and its implementation DefaultLogger
class. Home controller class will use that ILogger object. I will 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");
}
}
HomeController
with ILogger
constructor injection looks like
public class HomeController : Controller
{
private readonly 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 HomeController
(ILogger logger
) constructor. In that state if I build my project, it will build without any errors. But in run time it will throw exception. Exception details in error page like as follow
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 is generated and that is “Make sure that the controller has a parameterless public constructor.” If I want to make workable to Home controller then it must have a parameter less
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
those are playing vital 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 and their behavior then you can download its source code and see the implementation. ASP.NET
MVC implements abstract factory design pattern for creating controller class. If you debug code and see the value with quick watch then you can see that
DefaultControllerFactory
is automatically created as CurrentControllerFactory
(IControllerFactory
).<o:p>
Why need custom controller factory
Already you know that Default controller factory creates controller object using parameter less constructor. But we need parameterised constructor so that we can inject our components though that constructor. So
DefaultControllerFactory
current implementation does not support our requirement. So we need a new custom controller factory.
Create custom controller factory
We can create a new custom controller factory by implementing
IControllerFactory
interface. Suppose our new controller factory named
CustomControllerFactory
. So its implementation looks like
public class CustomControllerFactory : 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();
}
}
Now at first 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 constructor HomeController
is not called, instead of that parameterized
HomeController(ILogger logger)
constructor is called by MVC framework. Wow! your problem is solved so easily.
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 dependent object through reflection. In current code implementation has some problems, which are:
- You need to pass controller namespace (using
constructor) so every controller should be same namespace and
- All controllers need single parameterized construction which accept
ILogger
object only. Without that it will throw
MissingMethodException
.
Another approach
<o:p>
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 virtual emthods and changed/implement whatever you need. One implementation example might be as follows
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 create my own CustomControllerFactory
class which is inherited from
DefaultControllerFactory
and override GetControllerInstance
method and implement my custom logic.
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 problems need to raise and handle if you try to dynamically create dependent object and controller object. So it will be better approach to use any IOC container to your project and register all your dependent objects there and use it. You can use various popular IOC containers like Castle Windsor, Unity, NInject, StructureMap etc. I will demonstrate how Managed Extensibility Framework (MEF) is used in this situation. MEF is not an IOC container. It is a composition layer. You can also called it plug-able framework by which you can plugin your dependent component at run time. Almost all types of work you can do by MEF which you can do with IOC. When to use MEF when IOC it depends on your requirements, application architecture. In my suggestion is when you need to compose your component at run time( run time plug-in play) in that case you can use MEF, when you create your components with its dependent component with static reference then you can use IOC. There are many articles published online where you can find more details/technical write-up regarding that. I hope you can study more on that and easily take decision which you can use and when. By the way MEF comes with .NET framework 4.0 So main benefit is, no third party component dependency is there. First you take reference of
system.ComponentModel.Composition
to your project.
Then you 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<o:p>
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 InheritedExportAttribute
, ExportAttribute
, PartCreationPolicyAttribute
of MEF to interface
ILogger
, HomeController
.
Based on these attributes MEF framework create objects. Just one important think you should remember that when you will use MEF, you should decorate your controllers through PartCreationPolicyAttribute
and set controllers life time as create object per request policy. [PartCreationPolicy (CreationPolicy.NonShared)]
Without that you
will get an error. By default it will use SharedCreation policy.
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 and second approach is just make 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 IOC or MEF framework for that. You can do more research on MEF and learn MEF usage and best practices after that you will use it to your real life projects. Near future I have a plan to write another article that will demonstrate to use of various IOC containers like Windsor, Unity, NInject, StrucutureMap 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.<o:p>