zoukankan      html  css  js  c++  java
  • Asp.net MVC-3-执行过程

    本篇主要讲述MVC处理请求时创建Controller和执行Action的完整过程。

    创建Controller

    先查看MvcHandler中处理请求的方法BeginProcessRequest:

            protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
    
            {
    
                IController controller;
    
                IControllerFactory factory;
    
                ProcessRequestInit(httpContext, out controller, out factory);
    
                IAsyncController asyncController = controller as IAsyncController;
    
                if (asyncController != null)
    
                {
    
                    ……
    
                }
    
                else
    
                {
    
                    ……
    
                }
    
         }

    再查看其中创建Controller的方法ProcessRequestInit

            private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
    
            {
    
                HttpContext currentContext = HttpContext.Current;
    
                ……
    
                AddVersionHeader(httpContext);
    
                RemoveOptionalRoutingParameters();
    
                string controllerName = RequestContext.RouteData.GetRequiredString("controller");
    
                factory = ControllerBuilder.GetControllerFactory();
    
                controller = factory.CreateController(RequestContext, controllerName);
    
                ……
    
            }

    Controller通过ControllerBuilder属性的方法GetControllerFactory获取到ControllerFactory对象然后由ControllerFactory创建,ControllerBuilder属性定义如下。

            internal ControllerBuilder ControllerBuilder
    
            {
    
                get
    
                {
    
                    if (_controllerBuilder == null)
    
                    {
    
                        _controllerBuilder = ControllerBuilder.Current;
    
                    }
    
                    return _controllerBuilder;
    
                }
    
                set { _controllerBuilder = value; }
    
            }

    可知ControllerBuilder默认使用ControllerBuilder.Current,查看ControllerBuilder类的代码:

            public IControllerFactory GetControllerFactory()
    
            {
    
                return _serviceResolver.Current;
    
            }
    
            internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver)
    
            {
    
                _serviceResolver = serviceResolver ?? new SingleServiceResolver<IControllerFactory>( () => _factoryThunk(),new DefaultControllerFactory { ControllerBuilder = this },   "ControllerBuilder.GetControllerFactory");
    
            }

    可知默认返回的ControllerFactory为DefaultControllerFactory(当然我们也可以注册默认的自定义的ControllerFactory),这里我们可继续查看DefaultControllerFactory

            internal DefaultControllerFactory(……)
    
            {
    
                ……
    
                    _activatorResolver = activatorResolver ?? new SingleServiceResolver<IControllerActivator>(
    
                                                                  () => null,
    
                                                                  new DefaultControllerActivator(dependencyResolver),
    
                                                                  "DefaultControllerFactory constructor");
    
                }
    
            }
    
            private IControllerActivator ControllerActivator
    
            {
    
                get
    
                {
    
                    if (_controllerActivator != null)
    
                    {
    
                        return _controllerActivator;
    
                    }
    
                    _controllerActivator = _activatorResolver.Current;
    
                    return _controllerActivator;
    
                }
    
            }
    
            public virtual IController CreateController(RequestContext requestContext, string controllerName)
    
            {
    
                ……
    
                Type controllerType = GetControllerType(requestContext, controllerName);
    
                IController controller = GetControllerInstance(requestContext, controllerType);
    
                return controller;
    
            }
    
            protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    
            {
    
                ……
    
                return ControllerActivator.Create(requestContext, controllerType);
    
            }

    可以看到最终Controller由DefaultControllerActivator来创建

                public DefaultControllerActivator(IDependencyResolver resolver)
    
                {
    
                    if (resolver == null)
    
                    {
    
                        _resolverThunk = () => DependencyResolver.Current;
    
                    }
    
                    else
    
                    {
    
                        _resolverThunk = () => resolver;
    
                    }
    
                }
    
     
    
                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就被创建出来了,这里我们看到了DependencyResolver.Current,这是MVC的默认注入容器,如果设置了容器,Controller的创建就可以通过容器(GetService)来完成了,如果未实现DependencyResolver或DependencyResolver未注册该Controller则通过反射来创建(使用Activator.CreateInstance,必须存在无参构造函数)。

    Controller注入

    下面来看对框架的第一个扩展也是最基本的扩展:为框架提供Ioc容器并注册Controller。对于Ioc容器的起源和作用这里就不多讲了。目前Ioc的思想已经普遍地应用于各种开发实践当中了,特别是企业应用开发中,Spring已经是Java开发事实上的基础框架。Asp.net Mvc也深受影响,虽然框架本身没有提供Ioc容器的实现,但是提供了很方便的扩展方式,通过扩展我们不仅可以使用容器管理自定义的对象,甚至可以将对象注入到Mvc框架当中(简单的比如对Controller的注入)。因为Mvc框架默认首先通过容器来获取对象,然后才是框架提供的方式(一般是一种默认实现),在以后的分析中可以看到许多的源码都可以证实这一点。

    下面我们通过添加Autofac来实现依赖注入。

    首先通过nuget添加Autofac和Autofac.Mvc5的引用。

    在App_Start目录下添加Autofac的初始化类如下:

    public class AutofacConfig
    
    {
    
            public static IDependencyResolver GeResolver()
    
            {
    
                var builder = new ContainerBuilder();
    
                Registers(builder);
    
                builder.RegisterControllers(Assembly.GetExecutingAssembly());
    
                return new AutofacDependencyResolver(builder.Build());
    
            }
    
     
    
            private static void Registers(ContainerBuilder builder)
    
            {
    
     
    
            }
    
    }

    然后在Global.asax的Application_Start方法中添加代码如下:

    DependencyResolver.SetResolver(AutofacConfig.GeResolver());

    这样我们就完成了依赖注入(目前只是Controller的注入,当然以后可以AutofacConfig 的Registers方法中把我们需要注入的对象注入到Autofac容器中)。关于依赖注入需要注意的主要有两点:一个是ContainerBuilder的扩展方法RegisterControllers,其参数类型为params Assembly[]可以传入一个或多个Assembly然后注册这些Assembly里的Controller,这样我们就可以将Controller放到不同的工程里;另一个是DependencyResolver.SetResolver,这样会替换掉默认的DependencyResolver实现,我们正是通过这样把Autofac容器作为了Mvc的容器从而完成依赖注入。

    下面通过一个简单的例子说明Ioc容器的应用。首先创建一个简单的接口及其实现的类

    public interface IIocTest
    
        {
    
            string Say();
    
        }
    
        public class IocTest: IIocTest
    
        {
    
            public string Say()
    
            {
    
                return "IocTest";
    
            }
    
    }

    然后再HomeController中添加一个该接口的字段,并创建一个构造函数用于注入(AutoFac默认只支持构造函数注入,但也可以开启属性注入)。    

        private IIocTest iocTestInsatnce;
    
        public HomeController(IIocTest iocTest)
    
        {
    
            iocTestInsatnce = iocTest;
    
        }

    然后再一个Action中调用接口方法,然后通过ViewBag(或其它方法)将其传到页面并显示,页面显示有多种方法,这里直接加到标题中:

        public ActionResult Index()
    
        {
    
            ViewBag.iocSays = iocTestInsatnce.Say();
    
            return View();
    
        }
    @{
    
            ViewBag.Title = "Home Page"+ ViewBag.iocSays;
    
    }

    然后运行程序,查看相应页面的标题,验证注入是否成功。

    执行Action

    创建好Controller之后我们再来看Controller是如何执行请求的。

    首先看ControllerBase,这是所有Controller的基类,查看它的处理方法BeginExecuteCore。

            protected virtual IAsyncResult BeginExecuteCore(AsyncCallback callback, object state)
    
            {
    
                ……
    
                try
    
                {
    
                    string actionName = GetActionName(RouteData);
    
                    IActionInvoker invoker = ActionInvoker;
    
                    IAsyncActionInvoker asyncInvoker = invoker as IAsyncActionInvoker;
    
                    if (asyncInvoker != null)
    
                    {
    
                        BeginInvokeDelegate<ExecuteCoreState> beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState, ExecuteCoreState innerState)
    
                        {
    
                            return innerState.AsyncInvoker.BeginInvokeAction(innerState.Controller.ControllerContext, innerState.ActionName, asyncCallback, asyncState);
    
                        };
    
                        EndInvokeVoidDelegate<ExecuteCoreState> endDelegate = delegate(IAsyncResult asyncResult, ExecuteCoreState innerState)
    
                        {
    
                            if (!innerState.AsyncInvoker.EndInvokeAction(asyncResult))
    
                            {
    
                                innerState.Controller.HandleUnknownAction(innerState.ActionName);
    
                            }
    
                        };
    
                        ExecuteCoreState executeState = new ExecuteCoreState() { Controller = this, AsyncInvoker = asyncInvoker, ActionName = actionName };
    
                        return AsyncResultWrapper.Begin(callback, state, beginDelegate, endDelegate, executeState, _executeCoreTag);
    
                    }
    
                    else
    
                    {
    
                         ……
    
                    }
    
                }
    
                ……
    
            }

    可以看到Action的执行通过ActionInvoker. BeginInvokeAction实现,ActionInvoker的获取方式如下:

            protected virtual IActionInvoker CreateActionInvoker()
    
            {
    
                return Resolver.GetService<IAsyncActionInvoker>() ?? Resolver.GetService<IActionInvoker>() ?? new AsyncControllerActionInvoker();
    
            }

    这里也看到了Resolver即可以通过Ioc容器来提供IAsyncActionInvoker或IActionInvoker,如果未提供则使用默认的AsyncControllerActionInvoker,再查看默认的实现AsyncControllerActionInvoker的处理方法BeginInvokeAction。

            public virtual IAsyncResult BeginInvokeAction(ControllerContext controllerContext, string actionName, AsyncCallback callback, object state)
            {
                if (controllerContext == null)
                {
                    throw new ArgumentNullException("controllerContext");
                }
                Contract.Assert(controllerContext.RouteData != null);
                if (String.IsNullOrEmpty(actionName) && !controllerContext.RouteData.HasDirectRouteMatch())
                {
                    throw Error.ParameterCannotBeNullOrEmpty("actionName");
                }
                ControllerDescriptor controllerDescriptor = GetControllerDescriptor(controllerContext);
                ActionDescriptor actionDescriptor = FindAction(controllerContext, controllerDescriptor, actionName);
                if (actionDescriptor != null)
                {
                    FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor);
                    Action continuation = null; 
                    BeginInvokeDelegate beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState)
                    {
                        try
                        {
                            AuthenticationContext authenticationContext = InvokeAuthenticationFilters(controllerContext,
                                filterInfo.AuthenticationFilters, actionDescriptor);
                            if (authenticationContext.Result != null)
                            {
                                AuthenticationChallengeContext challengeContext =
                                    InvokeAuthenticationFiltersChallenge(controllerContext,
                                    filterInfo.AuthenticationFilters, actionDescriptor, authenticationContext.Result);
                                continuation = () => InvokeActionResult(controllerContext,
                                    challengeContext.Result ?? authenticationContext.Result);
                            }
                            else
                            {
                                AuthorizationContext authorizationContext = InvokeAuthorizationFilters(controllerContext, filterInfo.AuthorizationFilters, actionDescriptor);
                                if (authorizationContext.Result != null)
                                {
                                    AuthenticationChallengeContext challengeContext =
                                        InvokeAuthenticationFiltersChallenge(controllerContext,
                                        filterInfo.AuthenticationFilters, actionDescriptor, authorizationContext.Result);
                                    continuation = () => InvokeActionResult(controllerContext,
                                        challengeContext.Result ?? authorizationContext.Result);
                                }
                                else
                                {
                                    if (controllerContext.Controller.ValidateRequest)
                                    {
                                        ValidateRequest(controllerContext);
                                    }
    
                                    IDictionary<string, object> parameters = GetParameterValues(controllerContext, actionDescriptor);
                                    IAsyncResult asyncResult = BeginInvokeActionMethodWithFilters(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters, asyncCallback, asyncState);
                                    continuation = () =>
                                    {
                                        ActionExecutedContext postActionContext = EndInvokeActionMethodWithFilters(asyncResult);
                                        AuthenticationChallengeContext challengeContext =
                                            InvokeAuthenticationFiltersChallenge(controllerContext,
                                            filterInfo.AuthenticationFilters, actionDescriptor,
                                            postActionContext.Result);
                                        InvokeActionResultWithFilters(controllerContext, filterInfo.ResultFilters,
                                            challengeContext.Result ?? postActionContext.Result);
                                    };
                                    return asyncResult;
                                }
                            }
                        }
                        catch (ThreadAbortException)
                        {
                            throw;
                        }
                        catch (Exception ex)
                        {
                            ExceptionContext exceptionContext = InvokeExceptionFilters(controllerContext, filterInfo.ExceptionFilters, ex);
                            if (!exceptionContext.ExceptionHandled)
                            {
                                throw;
                            }
                            continuation = () => InvokeActionResult(controllerContext, exceptionContext.Result);
                        }
                        return BeginInvokeAction_MakeSynchronousAsyncResult(asyncCallback, asyncState);
                    };
                    EndInvokeDelegate<bool> endDelegate = delegate(IAsyncResult asyncResult)
                    {
                        try
                        {
                            continuation();
                        }
                        catch (ThreadAbortException)
                        {
                            throw;
                        }
                        catch (Exception ex)
                        {
                            ExceptionContext exceptionContext = InvokeExceptionFilters(controllerContext, filterInfo.ExceptionFilters, ex);
                            if (!exceptionContext.ExceptionHandled)
                            {
                                throw;
                            }
                            InvokeActionResult(controllerContext, exceptionContext.Result);
                        }
    
                        return true;
                    };
                    return AsyncResultWrapper.Begin(callback, state, beginDelegate, endDelegate, _invokeActionTag);
                }
                else
                {
                    return BeginInvokeAction_ActionNotFound(callback, state);
                }
            }

    这是一个非常重要的方法,也是我们后续分析的基础,它描述了我们主要的处理流程。此方法中关联了相当多的类,但是其主要处理流程是容易清晰明白的。大致是先获取ControllerDescriptor和ActionDescriptor,然后依次执行Action中的过滤器AuthenticationFilters、AuthorizationFilters来进行验证和授权检查,然后是页面安全检查、获取参数,然后执行ActionFilter和Action,整个过程中如果设置了Result会直接执行AuthenticationFilters的AuthenticationFiltersChallenge,然后执行ResultFilters对结果进行过滤,当然如果处理过程中抛出异常会调用ExceptionFilter进行处理。如果要理解处理的细节需要查看大量的源码,这里提供一点小小的参考ReflectedActionDescriptor、ReflectedControllerDescriptor为ActionDescriptor和ControllerDescriptor的默认实现,Action、过滤器等的查找实际都是通过反射类获取的。

    下面为BeginInvokeAction的处理过程图

  • 相关阅读:
    ArrayBlockingQueue和LinkedBlockingQueue
    hibernate中保存一个对象后再设置此对象的属性为什么不需要调用update方法了
    Hello World!
    org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction;
    jquery的attr在浏览器发生错误,checkbox的属性总是为undefined
    如何解决设置maven时Could not read settings.xml
    iOS与HTML交互问题
    一个苹果证书怎么多次使用——导出p12文件
    Mac Chrome-点击书签页在新的标签打开之方法
    iOS 开发者中的个人账号与组织账号之间区别
  • 原文地址:https://www.cnblogs.com/ssxg/p/7149450.html
Copyright © 2011-2022 走看看