一、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(); } }
更多: