ASP.NET MVC: Is Controller created for every request?
Very simple question: Are controllers in ASP.NET created for every HTTP request, or are they created at application startup and reused throughout requests?
Will the controller be created only for a particular HTTP request?
If my previous assumptions are correct, can I depend on it? I want to create database context (Entity Framework) that will live only for one request. If I create it as a property initialized in controller's constructor, is it granted that new instance of context will be created on for every request?
Solution 1:
A Controller is created for every request by the ControllerFactory
(which by default is the DefaultControllerFactory
).
http://msdn.microsoft.com/en-us/library/system.web.mvc.defaultcontrollerfactory.aspx
Note that the Html.Action
Html Helper will create another controller.
The short version is that ControllerActivator.Create
is called (for every request) to create a Controller (which inits a new Controller either through the DependencyResolver or through the Activator if no Resolver has been set up):
public IController Create(RequestContext requestContext, Type controllerType)
{
try
{
return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
}
The longer version is this (Here's the code from the source from the MvcHandler):
protected internal virtual void ProcessRequest(HttpContextBase httpContext)
{
SecurityUtil.ProcessInApplicationTrust(() =>
{
IController controller;
IControllerFactory factory;
ProcessRequestInit(httpContext, out controller, out factory);
try
{
controller.Execute(RequestContext);
}
finally
{
factory.ReleaseController(controller);
}
});
}
private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
// non-relevant code
// Instantiate the controller and call Execute
factory = ControllerBuilder.GetControllerFactory();
controller = factory.CreateController(RequestContext, controllerName);
if (controller == null)
{
throw new InvalidOperationException(
String.Format(
CultureInfo.CurrentCulture,
MvcResources.ControllerBuilder_FactoryReturnedNull,
factory.GetType(),
controllerName));
}
}
Here's the Controller factory code:
public virtual IController CreateController(RequestContext requestContext, string controllerName)
{
Type controllerType = GetControllerType(requestContext, controllerName);
IController controller = GetControllerInstance(requestContext, controllerType);
return controller;
}
Which basically calls this:
protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return ControllerActivator.Create(requestContext, controllerType);
}
Which calls this method in the ControllerActivator
(This code tries to ask the DependencyResolver for an instance, or just uses the Activator class):
public IController Create(RequestContext requestContext, Type controllerType)
{
try
{
return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
}
This might fall under too much information... But I wanted to show that you really DO get a new controller for EVERY request.
Solution 2:
I created an empty constructor for a controller and put a break point in the constructor. It got hit every time there was a new request. So I think it's created for every request.
Solution 3:
The controller will be created when any Action in a specific Controller is performed.
I have a project where all of my Controllers inherit from an ApplicationController
and every time that an action is performed, the breakpoint is hit inside of the ApplicationController
- regardless of its "current" Controller.
I initialize my agent (which works as my context) whenever my controller is created like such:
public IWidgetAgent widgetAgent { get; set; }
public WidgetController()
{
if (widgetAgent == null)
{
widgetAgent = new WidgetAgent();
}
}
This is obviously not what you need - as you mentioned that you only wanted a single instance each time it was called. But it is a good place to check what is going on each time and to ensure that another instance of your context does not currently exist.
Hope this helps.
Solution 4:
Controllers are created for every request. The magic happens in the routing in the gobal.aspx. The mapping paths direct MVC to which controller to create and action on the controller to call, and parameters to pass to them.
http://www.asp.net/mvc/tutorials/asp-net-mvc-routing-overview-vb