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);
    }
}
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的繼承關系:

特別說明:在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();
            }
        }
View Code
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();
        }
    }

更多:

Asp.Net MVC--Controller激活2

ASP.NET MVC——Controller的激活

關於上下文

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM