Here is a simple class that allows you to use a container to register and resolve your instances of controllers. You’d want to do this if you inject dependencies into your controller via constructor injection.
Controller Example:
public class AdminController : Controller { private readonly ILocalDbManager _localDbManager; public AdminController(ILocalDbManager localDbManager) { _localDbManager = localDbManager; } public ActionResult Index() { return View(); } // Other Actions ... }
If you use the default ControllerFactory provided by ASP.NET MVC you’ll get a MissingMethodException, such as this:
No parameterless constructor defined for this object.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.MissingMethodException: No parameterless constructor defined for this object.
The default ASP.NET MVC Controller Factory looks for a parameter-less constructor to build the controller from. If it cannot find one, the above is what happens.
Since I want to use a container (Windsor in this case) to supply my depenencies, the default ControllerFactory will not work. We have to create our own.
The Container Controller Factory
Building your own controller factory is easy. Simply implement the IControllerFactory interface from the System.Web.Mvc namespace and then set your controller factory as the one to use. Here’s how to do it:
The Controller Factory
public class ControllerFactory : IControllerFactory { private readonly IKernel _kernel; public ControllerFactory(IKernel kernel) { _kernel = kernel; } public IController CreateController(RequestContext requestContext, string controllerName) { return _kernel.Resolve<IController>(controllerName.ToLowerInvariant() + "controller"); } public void ReleaseController(IController controller) { _kernel.ReleaseComponent(controller); } }
This class, takes a container in through the constructor, and then resolves a controller from the container via the name of the controller . It then releases it from the container when its done with it.
Please note, you can create your own naming structure when you register your controllers, and if you do so you’ll need to adjust the “CreateController” method to resolve to the proper key in the container.
Now that we have our own ControllerFactory, we need to put it INTO the container so we can have the kernel injected via the constructor.
This is a bit difficult to understand, therefore I’m going to post the code and then explain it.
Global.asax.cs
public class Global : System.Web.HttpApplication { public static WindsorContainer container; protected void Application_Start(object sender, EventArgs e) { container = new WindsorContainer(Server.MapPath("~/Config/Windsor.config")); var app = container.Resolve<Application>(); app.RegisterFacilities(container.Kernel); app.RegisterComponents(container.Kernel); app.RegisterRoutes(RouteTable.Routes); app.RegisterViewEngines(ViewEngines.Engines); // Tell MVC which controller factory to use. Since we're using // the container to inject some items into the controller we need to use this controller factory // that was set up in the component registration. ControllerBuilder.Current.SetControllerFactory(container.Resolve<IControllerFactory>()); } // Other global members below ... }
Application.cs
public class Application { public void RegisterViewEngines(ViewEngineCollection engines) { if (engines == null) throw new ArgumentNullException("engines"); SparkEngineStarter.RegisterViewEngine(engines); } public void RegisterRoutes(RouteCollection routes) { if (routes == null) throw new ArgumentNullException("routes"); // default route routes.Add(new Route( "{controller}/{action}/{id}", new RouteValueDictionary(new { controller = "home", action = "index", id = "" }), new MvcRouteHandler())); } public void RegisterComponents(IKernel kernel) { kernel.Register( Component .For<IControllerFactory>() .ImplementedBy<ControllerFactory>(), // Register all controllers in assembly. AllTypes .Of<IController>() .FromAssembly(typeof (Application).Assembly) .Configure( reg => reg.Named(reg.Implementation.Name.ToLowerInvariant()).LifeStyle.Transient), // Register all services that implement marker interface in current assembly AllTypes. Of<IService>() .FromAssembly(typeof (Application).Assembly) .WithService.FromInterface()); } public void RegisterFacilities(IKernel kernel) { kernel.AddFacility("logging", new LoggingFacility(LoggerImplementation.Trace)); kernel.AddFacility("activerecord", new ActiveRecordFacility()); } }
This is done in the Application.cs file (which is the bootstrapper for the container and other application details). This class is called on Application Start. We call a RegisterComponents on the Application.cs file and give it a container in which to register things.
In the RegisterComponents method call we register the ControllerFactory in the container, and then all of the other components. A key one to notice is this bit of code:
// Register all controllers in assembly. AllTypes .Of<IController>() .FromAssembly(typeof (Application).Assembly) .Configure( reg => reg.Named(reg.Implementation.Name.ToLowerInvariant()).LifeStyle.Transient),
The code above analyzes the current assembly (which Application.cs resides within), and configures the container to load all instances of IController (which is implemented on the Controller base class in ASP.NET MVC). In short, it registers all controllers into the container. The dependency is registered with a key, that is the name of the controller. Therefore if you have a controller called “AdminController” the key would be “admincontroller”. We then set the life style to transient for each controller.
This naming structure has meaning. If we look at the ControllerFactory again below …
return _kernel.Resolve(controllerName.ToLowerInvariant() + "controller");
… we can see that when we resolve the controller from the container we use a string key and concatinate the “controller” to the end of it. This is the key in the container. At this point the proper controller will be returned. If you change yoru controller key structure you will need to change it in the registration as well as in the factory (as they depend on each other).
In the Global.asax.cs file we are setting up a new container, and upon Application Start we register the components, facilities, view engines, and a few other things (which the component registration is shown above). At the bottom of the Application_Start call, we tell the ControllerBuilder class (which is in the System.Web.Mvc namespace) to set the ControllerFactory to our own ControllerFactory … like this:
// Tell MVC which controller factory to use. Since we're using // the container to inject some items into the controller we need to use this controller factory // that was set up in the component registration. ControllerBuilder.Current.SetControllerFactory(container.Resolve<IControllerFactory>());
All Done
Now, when we fire up the app, the following will happen:
- The App Starts
- The Container is created
- The Container registers its components
- The controller factory gets registered, its dependency, IKernel, is injected from the kernel itself (it knows how to supply itself to an object if it needs it)
- The controllers get registered with key.
- Our new ControllerFactory is set to be the ControllerFactory to use when resolving controllers during runtime via the SetControllerFactory method.
- When a route is requested, our ControllerFactory will take over, the controller will be resolved via the key that is created by using the name of the current controller concatenated with the word “controller” (following a convention over configuration methodology).
- The controller is returned with all of its dependencies resolved, which in this case would be ILocalDbManager
- The app then continues to run.
At this point your able to create a controller which takes injected dependencies. This helps with decoupling, maintenance and also testing.
nike air jordan says
Mark S. is definitely on the right track. If you want to get a professional looking email address, Id recommend buying your name domain name, like or
air jordan 17.5
If its common it might be difficult to get, however, be creative and you can usually find something.
haha says
authentic nfl jerseys Inexpensive items
coach bags on sale I am confident with his
coach outlet store online First step in success
coach outlet online Workmanship
coach bags outlet Value of goods
coach outlet store Of love
wholesale designer bags Beautiful lines
coach bags outlet There range of children
cheap coach What are you waiting
wholesale nfl jerseys Is always expected
authentic nfl jerseys It is pretty good
Coach Factory Outlet says
http://buycoachfactoryoutletsz.com