一、Asp.Net MVC是否针对每次请求都重新创建一个控制器实例

默认情况下,答案是确定的。

ControllerBuilder类 ControllerBuilder.Current用户获取默认的控制器工厂DefaultControllerFactory


//     // 摘要:     //     表示默认情况下已注册的控制器工厂。     public class DefaultControllerFactory : IControllerFactory


获取方式


IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();


IControllerFactory用户创建和释放Controller

Asp.Net MVC是否针对每次请求都重新创建一个控制器实例_控制器实例化Asp.Net MVC是否针对每次请求都重新创建一个控制器实例_控制器继承关系_02

namespace System.Web.Mvc {     //     // 摘要:     //     定义控制器工厂所需的方法。     public interface IControllerFactory     {         //         // 摘要:         //     使用指定的请求上下文来创建指定的控制器。         //         // 参数:         //   requestContext:         //     请求上下文。         //         //   controllerName:         //     控制器的名称。         //         // 返回结果:         //     控制器。         IController CreateController(RequestContext requestContext, string controllerName);         //         // 摘要:         //     获取控制器的会话行为。         //         // 参数:         //   requestContext:         //     请求上下文。         //         //   controllerName:         //     你想要获取器其会话行为的控制器的名称。         //         // 返回结果:         //     控制器的会话行为。         SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName);         //         // 摘要:         //     释放指定的控制器。         //         // 参数:         //   controller:         //     控制器。         void ReleaseController(IController controller);     } }

View Code

二、答案验证方式一,查看源代码

目前Asp.Net MVC最先版本v5.2.4 ,CodeFlex源代码地址:​​http://aspnetwebstack.codeplex.com/SourceControl/latest​

CodeFlex源代码Asp.Net首页:​​http://aspnetwebstack.codeplex.com/​

官方MVC文档参考:​​https://www.asp.net/mvc​

.Net Function 博客:​​https://dotnetfoundation.org/projects?q=mvc​

关于Controller的实例化:

默认情况下,MVC的控制器工厂使用DefaultControllerFactory,继承了IControllerFactory,所以在默认控制器工厂中实现的CreateController()方法,就是用来创建控制器实例。

特别说明:从默认控制器工厂的Create()源代码看,每次请求都会创建对应的控制器实例,并且是通过反射的方式创建的。

源代码片段:来自DefaultControllerFactory


public virtual IController CreateController(RequestContext requestContext, string controllerName) {     if (requestContext == null)     {         throw new ArgumentNullException("requestContext");     }      if (String.IsNullOrEmpty(controllerName) && !requestContext.RouteData.HasDirectRouteMatch())     {         throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName");     }      Type controllerType = GetControllerType(requestContext, controllerName);     IController controller = GetControllerInstance(requestContext, controllerType);     return controller; }


本类中的Create()方法


public IController Create(RequestContext requestContext, Type controllerType)     {         try         {             return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));         }         catch (Exception ex)         {             throw new InvalidOperationException(                 String.Format(                     CultureInfo.CurrentCulture,                     MvcResources.DefaultControllerFactory_ErrorCreatingController,                     controllerType),                 ex);         }     }



关于Controller的继承关系:

Asp.Net MVC是否针对每次请求都重新创建一个控制器实例_控制器继承关系_03

特别说明:在System.Web.Mvc.Dll中

1.IController中的Execute() 方法是在ControllerBase中实现的,Execute()中执行的操作主要操作:

1.实例化Controller实例,调用Initialize(),从这个方法中可以看出每次都是重新实例化控制器上线文ControllerContext对象

2.调用子类的ExecuteCore(),也就是Controller类中定义的ExecuteCore()

源代码片段,来自ControllerBase类:


protected virtual void Execute(RequestContext requestContext) {     if (requestContext == null)     {         throw new ArgumentNullException("requestContext");     }     if (requestContext.HttpContext == null)     {         throw new ArgumentException(MvcResources.ControllerBase_CannotExecuteWithNullHttpContext, "requestContext");     }      VerifyExecuteCalledOnce();     Initialize(requestContext);//初始化ControllerBase对象     using (ScopeStorage.CreateTransientScope())     {         ExecuteCore();     } }


protected virtual void Initialize(RequestContext requestContext) {     ControllerContext = new ControllerContext(requestContext, this); }


2.Controller中只有ExecuteCore() 方法用于

1.激活Action方法并执行

2.处理View视图加载,视图代码编译执行,并呈现

Controller中的代码片段:

Asp.Net MVC是否针对每次请求都重新创建一个控制器实例_控制器实例化Asp.Net MVC是否针对每次请求都重新创建一个控制器实例_控制器继承关系_02

protected override void ExecuteCore()         {             // If code in this method needs to be updated, please also check the BeginExecuteCore() and             // EndExecuteCore() methods of AsyncController to see if that code also must be updated.              PossiblyLoadTempData();             try             {                 string actionName = GetActionName(RouteData);                 if (!ActionInvoker.InvokeAction(ControllerContext, actionName))                 {                     HandleUnknownAction(actionName);                 }             }             finally             {                 PossiblySaveTempData();             }         }

View Code Asp.Net MVC是否针对每次请求都重新创建一个控制器实例_控制器实例化Asp.Net MVC是否针对每次请求都重新创建一个控制器实例_控制器继承关系_02

public virtual bool InvokeAction(ControllerContext controllerContext, string actionName) {     if (controllerContext == null)     {         throw new ArgumentNullException("controllerContext");     }      Contract.Assert(controllerContext.RouteData != null);     if (String.IsNullOrEmpty(actionName) && !controllerContext.RouteData.HasDirectRouteMatch())     {         throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");     }      ControllerDescriptor controllerDescriptor = GetControllerDescriptor(controllerContext);     ActionDescriptor actionDescriptor = FindAction(controllerContext, controllerDescriptor, actionName);      if (actionDescriptor != null)     {         FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor);          try         {             AuthenticationContext authenticationContext = InvokeAuthenticationFilters(controllerContext, filterInfo.AuthenticationFilters, actionDescriptor);              if (authenticationContext.Result != null)             {                 // An authentication filter signaled that we should short-circuit the request. Let all                 // authentication filters contribute to an action result (to combine authentication                 // challenges). Then, run this action result.                 AuthenticationChallengeContext challengeContext = InvokeAuthenticationFiltersChallenge(                     controllerContext, filterInfo.AuthenticationFilters, actionDescriptor,                     authenticationContext.Result);                 InvokeActionResult(controllerContext, challengeContext.Result ?? authenticationContext.Result);             }             else             {                 AuthorizationContext authorizationContext = InvokeAuthorizationFilters(controllerContext, filterInfo.AuthorizationFilters, actionDescriptor);                 if (authorizationContext.Result != null)                 {                     // An authorization filter signaled that we should short-circuit the request. Let all                     // authentication filters contribute to an action result (to combine authentication                     // challenges). Then, run this action result.                     AuthenticationChallengeContext challengeContext = InvokeAuthenticationFiltersChallenge(                         controllerContext, filterInfo.AuthenticationFilters, actionDescriptor,                         authorizationContext.Result);                     InvokeActionResult(controllerContext, challengeContext.Result ?? authorizationContext.Result);                 }                 else                 {                     if (controllerContext.Controller.ValidateRequest)                     {                         ValidateRequest(controllerContext);                     }                      IDictionary<string, object> parameters = GetParameterValues(controllerContext, actionDescriptor);                     ActionExecutedContext postActionContext = InvokeActionMethodWithFilters(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters);                      // The action succeeded. Let all authentication filters contribute to an action result (to                     // combine authentication challenges; some authentication filters need to do negotiation                     // even on a successful result). Then, run this action result.                     AuthenticationChallengeContext challengeContext = InvokeAuthenticationFiltersChallenge(                         controllerContext, filterInfo.AuthenticationFilters, actionDescriptor,                         postActionContext.Result);                     InvokeActionResultWithFilters(controllerContext, filterInfo.ResultFilters,                         challengeContext.Result ?? postActionContext.Result);                 }             }         }         catch (ThreadAbortException)         {             // This type of exception occurs as a result of Response.Redirect(), but we special-case so that             // the filters don't see this as an error.             throw;         }         catch (Exception ex)         {             // something blew up, so execute the exception filters             ExceptionContext exceptionContext = InvokeExceptionFilters(controllerContext, filterInfo.ExceptionFilters, ex);             if (!exceptionContext.ExceptionHandled)             {                 throw;             }             InvokeActionResult(controllerContext, exceptionContext.Result);         }          return true;     }      // notify controller that no method matched     return false; }

View Code

三、答案验证方式二、通过控制器的构造函数验证

1.在控制器方法中,设置断电,启动调试

2.通过访问同一个控制器,相同或不同的Action,发现每次断电都会停住。


public class HomeController : Controller     {         /// <summary>         /// 构造函数         /// </summary>         public HomeController()         {             /*              *  特别说明:              *  1.MVC请求机制,中会为每一次请求都重新创建一个控制器实例,也就是说针对每一次请求该构造函数都会执行              *  2.在控制器的构造函数中,当前控制器的 http上线文(HttpContextBase)、当前请求上下文(HttpRequestBase)、路由当前路由数据(RouteData)都为空              *  3.在控制器的构造函数中,Asp.Net的原始上下文(HttpContext)已经初始化,可以使用              */             LogHelper.LogHelper _log = new LogHelper.LogHelper();             HttpContext httpCurrent = System.Web.HttpContext.Current;             //测试结果一下都为空             HttpContextBase httpContext = this.HttpContext;             string url = Request == null ? "请求上下文为空" : Request.Url.AbsoluteUri;             _log.WriteLine("当前请求地址:" + url);             string action = RouteData == null ? "路由数据为空" : RouteData.Values["action"].ToString();             _log.WriteLine(string.Format("当前请求控制器:{0},Action:{1}", this.GetType().FullName, RouteData));         }         // GET: Home         public ActionResult Index()         {             //IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();             //factory.CreateController();             //factory.ReleaseController()             return View();         }         public ActionResult ShowOne()         {             return View();         }     }