ASP.NET MVC: ¿Se crea el controlador para cada solicitud?

112

Pregunta muy simple: ¿Se crean controladores en ASP.NET para cada solicitud HTTP, o se crean al inicio de la aplicación y se reutilizan en todas las solicitudes?

¿Se creará el controlador solo para una solicitud HTTP en particular?

Si mis suposiciones anteriores son correctas, ¿puedo confiar en ello? Quiero crear un contexto de base de datos (Entity Framework) que vivirá solo para una solicitud. Si lo creo como una propiedad inicializada en el constructor del controlador, ¿se concede que se creará una nueva instancia de contexto para cada solicitud?

Rasto
fuente
16
Ponga un punto de interrupción en su constructor y vea qué puede averiguar ...
Greg B
10
@Greg B: gran idea, excepto que no me dirá si se comporta así siempre; si las circunstancias cambian y algún controlador cambiará su comportamiento, tengo un error que podría ser muy difícil de encontrar ...
Rasto
@drasto, ¿cómo comprobarás si funciona así siempre? Verifique todas las solicitudes a su aplicación?
Greg B
4
@Todd Smith por favor algún enlace o al menos su nombre completo. Las letras de árbol IoC son difíciles de buscar en Google. Gracias.
Rasto
2
@drasto IoC = Inversión de control en.wikipedia.org/wiki/Inversion_of_control
Bala R

Respuestas:

103

El controlador crea un controlador para cada solicitud ControllerFactory(que de forma predeterminada es el DefaultControllerFactory).

http://msdn.microsoft.com/en-us/library/system.web.mvc.defaultcontrollerfactory.aspx

Tenga en cuenta que Html.ActionHtml Helper creará otro controlador.

La versión corta es la que ControllerActivator.Createse llama (para cada solicitud) para crear un controlador (que inicia un nuevo controlador, ya sea a través del DependencyResolver o mediante el Activator si no se ha configurado ningún Resolver):

public IController Create(RequestContext requestContext, Type controllerType) 
{
    try 
    {
        return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
    }

La versión más larga es esta (aquí está el código de la fuente del 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));
    }
}

Aquí está el código de fábrica del controlador:

public virtual IController CreateController(RequestContext requestContext, string controllerName) 
{
    Type controllerType = GetControllerType(requestContext, controllerName);
    IController controller = GetControllerInstance(requestContext, controllerType);
    return controller;
}

Que básicamente llama a esto:

protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType) 
{
    return ControllerActivator.Create(requestContext, controllerType);
}

Que llama a este método en el ControllerActivator(Este código intenta pedirle al DependencyResolver una instancia, o simplemente usa la clase Activator):

public IController Create(RequestContext requestContext, Type controllerType) 
{
    try 
    {
        return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
    }

Esto podría incluir demasiada información ... Pero quería mostrar que realmente SÍ obtienes un nuevo controlador para CADA solicitud.

Linkgoron
fuente
@Daniel @drasto aquí está la cita aspnet.codeplex.com/SourceControl/changeset/view/63930#266503
Bala R
32

Creé un constructor vacío para un controlador y puse un punto de interrupción en el constructor. Recibía un impacto cada vez que había una nueva solicitud. Entonces creo que está creado para cada solicitud.

Bala R
fuente
3
+1 Espero que tenga razón, pero me gustaría tener un conocimiento mejor aprobado que simplemente "en todos los casos en que lo he probado funcionó". Si a veces no funciona así por alguna razón, significa un error.
Rasto
6
@drasto: No hay necesidad de preocuparse. Se crea una instancia del controlador para cada solicitud. Sin embargo, parte de la memoria se reutiliza, pero no debe preocuparse por el estado del controlador (si el suyo tiene uno). Se inicializará como se esperaba. Pero puede haber una situación en la que se instancia más de un controlador. Y ahí es cuando las vistas llaman a las acciones del controlador (es decir Html.RenderAction("action", "controller");)
Robert Koritnik
@RobertKoritnik & Bala R, tengo una pregunta, por favor. ¿Qué sucede con los objetos creados como Student o List <Student> después de que el método de acción los ha servido a la vista? ¿Se deshacen? ¿Y qué sucede con estos objetos cuando llega una nueva solicitud?
Mahdi Alkhatib
3

El controlador se creará cuando se realice cualquier acción en un controlador específico.

Tengo un proyecto en el que todos mis controladores heredan de un ApplicationControllery cada vez que se realiza una acción, el punto de interrupción se alcanza dentro del ApplicationController- independientemente de su controlador " actual ".

Inicializo mi agente (que funciona como mi contexto) cada vez que mi controlador se crea así:

    public IWidgetAgent widgetAgent { get; set; }

    public WidgetController()
    {
        if (widgetAgent == null)
        {
            widgetAgent = new WidgetAgent();
        }

    }

Obviamente, esto no es lo que necesita, como mencionó que solo quería una instancia única cada vez que se llamaba. Pero es un buen lugar para verificar lo que sucede cada vez y para asegurarse de que no exista otra instancia de su contexto actualmente.

Espero que esto ayude.

Rion Williams
fuente
2

Los controladores se crean para cada solicitud. La magia ocurre en el enrutamiento en gobal.aspx. Las rutas de mapeo dirigen MVC a qué controlador crear y actuar en el controlador para llamar, y los parámetros para pasarles.

http://www.asp.net/mvc/tutorials/asp-net-mvc-routing-overview-vb

BlackICE
fuente
cita requerida : no se puede encontrar información de respaldo en el documento vinculado. Gracias
Rasto