Asp.Net MVC是否针对每次请求都重新创建一个控制器实例
一、Asp.Net MVC是否针对每次请求都重新创建一个控制器实例
默认情况下,答案是确定的。
ControllerBuilder类 ControllerBuilder.Current用户获取默认的控制器工厂DefaultControllerFactory
// // 摘要: // 表示默认情况下已注册的控制器工厂。 public class DefaultControllerFactory : IControllerFactory
获取方式
IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
IControllerFactory用户创建和释放Controller
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); } }
二、答案验证方式一,查看源代码
目前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的继承关系:
特别说明:在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中的代码片段:
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(); } }
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; }
三、答案验证方式二、通过控制器的构造函数验证
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(); } }
更多: