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的激活

关于上下文

 

posted @ 2017-01-09 15:19  天马3798  阅读(5164)  评论(0编辑  收藏  举报