本篇主要讲述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();

        }

http://www.cnblogs.com/ssxg/p/7149450.html