zoukankan      html  css  js  c++  java
  • 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的激活

    关于上下文

  • 相关阅读:
    Excel中substitute替换函数的使用方法
    如何在Excel中提取小数点后面的数字?
    提升单元测试体验的利器--Mockito使用总结
    SpringMVC项目读取不到外部CSS文件的解决办法及总结
    java8 Lambda表达式的新手上车指南(1)--基础语法和函数式接口
    Spring-data-redis操作redis知识总结
    优雅高效的MyBatis-Plus工具快速入门使用
    Thrift入门初探(2)--thrift基础知识详解
    Thrift入门初探--thrift安装及java入门实例
    spring事件驱动模型--观察者模式在spring中的应用
  • 原文地址:https://www.cnblogs.com/tianma3798/p/6265374.html
Copyright © 2011-2022 走看看