ASP.NET MVC:是否为每个请求都创建了Controller?


112

非常简单的问题:是在ASP.NET中为每个HTTP请求创建控制器,还是在应用程序启动时创建并在整个请求中重用这些控制器?

是否仅针对特定的HTTP请求创建控制器?

如果我以前的假设是正确的,我可以依靠它吗?我想创建仅对一个请求有效的数据库上下文(实体框架)。如果我将其创建为在控制器的构造函数中初始化的属性,是否是否将为每个请求创建新的上下文实例?


16
在您的构造函数中设置一个断点,看看您能找到什么...
Greg B

10
@Greg B:好主意,除了它不会告诉我它是否总是那样-如果环境变化并且某些控制器将改变它的行为,我的bug可能很难找到……
Rasto

@drasto您将如何检查它是否总是那样工作?检查对您的应用程序的每个请求?
Greg B

4
@Todd Smith,请提供一些链接或至少全名。树字母IoC很难谷歌。谢谢。
拉斯托

2
@drasto IoC =控制权反转en.wikipedia.org/wiki/Inversion_of_control
Bala R

Answers:


103

会为每个请求创建一个控制器ControllerFactory(默认为DefaultControllerFactory)。

http://msdn.microsoft.com/zh-CN/library/system.web.mvc.defaultcontrollerfactory.aspx

请注意,Html.ActionHTML Helper将创建另一个控制器。

简短的版本是ControllerActivator.Create(针对每个请求)调用以创建控制器(如果没有设置解析器,则可以通过DependencyResolver或通过Activator来初始化新的Controller):

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

更长的版本是这样(这是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));
    }
}

这是Controller的工厂代码:

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

基本上称之为:

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

ControllerActivator(此代码尝试向DependencyResolver请求实例,或仅使用Activator类)中调用此方法的方法:

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

这可能属于过多的信息.​​..但是我想证明您确实确实为每个请求都获得了一个新的控制器。



32

我为控制器创建了一个空的构造函数,并在构造函数中放置了一个断点。每当有新要求时,它都会受到打击。因此,我认为它是为每个请求创建的。


3
+1我希望您是对的,但我希望获得一些更好的认可知识,而不仅仅是“在我尝试过的所有情况下都行得通”。如果有时由于某种原因而无法正常工作,则表示存在错误。
拉斯托

6
@drasto:不用担心。控制器为每个请求实例化。虽然确实会重用一些内存,但是您不必担心控制器状态(如果您有一个状态)。它将按预期初始化。但是有可能会实例化多个控制器。那就是视图调用控制器动作的时候(即Html.RenderAction("action", "controller");
Robert Koritnik 2011年

@RobertKoritnik和Bala R,请问一个问题。在操作方法将其创建后,将其创建为Student或List <Student>之类的对象时,会发生什么情况?他们会被处置吗?当一个新请求到来时,这些对象会发生什么?
Mahdi Alkhatib

3

当执行特定控制器中的任何操作时,将创建该控制器。

我有一个项目,我的所有Controller都继承自一个项目,ApplicationController并且每次执行操作时,ApplicationController都会在-的内部命中断点,而不管其“ 当前 ” Controller如何。

每当创建控制器时,我都会初始化代理(作为上下文):

    public IWidgetAgent widgetAgent { get; set; }

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

    }

显然这不是您所需要的-正如您提到的,每次调用它只需要一个实例。但这是检查每次发生的情况并确保当前不存在上下文的另一个实例的好地方。

希望这可以帮助。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.