本篇主要講述MVC處理請求時創(chuàng)建Controller和執(zhí)行Action的完整過程。
創(chuàng)建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 { …… } }
再查看其中創(chuàng)建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創(chuàng)建,ControllerBuilder屬性定義如下。
internal ControllerBuilder ControllerBuilder { get { if (_controllerBuilder == null) { _controllerBuilder = ControllerBuilder.Current; } return _controllerBuilder; } set { _controllerBuilder = value; } }
可知ControllerBuilder默認(rèn)使用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"); }
可知默認(rèn)返回的ControllerFactory為DefaultControllerFactory(當(dāng)然我們也可以注冊默認(rèn)的自定義的ControllerFactory),這里我們可繼續(xù)查看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來創(chuàng)建
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就被創(chuàng)建出來了,這里我們看到了DependencyResolver.Current,這是MVC的默認(rèn)注入容器,如果設(shè)置了容器,Controller的創(chuàng)建就可以通過容器(GetService)來完成了,如果未實(shí)現(xiàn)DependencyResolver或DependencyResolver未注冊該Controller則通過反射來創(chuàng)建(使用Activator.CreateInstance,必須存在無參構(gòu)造函數(shù))。
Controller注入
下面來看對框架的第一個擴(kuò)展也是最基本的擴(kuò)展:為框架提供Ioc容器并注冊Controller。對于Ioc容器的起源和作用這里就不多講了。目前Ioc的思想已經(jīng)普遍地應(yīng)用于各種開發(fā)實(shí)踐當(dāng)中了,特別是企業(yè)應(yīng)用開發(fā)中,Spring已經(jīng)是Java開發(fā)事實(shí)上的基礎(chǔ)框架。Asp.net Mvc也深受影響,雖然框架本身沒有提供Ioc容器的實(shí)現(xiàn),但是提供了很方便的擴(kuò)展方式,通過擴(kuò)展我們不僅可以使用容器管理自定義的對象,甚至可以將對象注入到Mvc框架當(dāng)中(簡單的比如對Controller的注入)。因?yàn)镸vc框架默認(rèn)首先通過容器來獲取對象,然后才是框架提供的方式(一般是一種默認(rèn)實(shí)現(xiàn)),在以后的分析中可以看到許多的源碼都可以證實(shí)這一點(diǎn)。
下面我們通過添加Autofac來實(shí)現(xiàn)依賴注入。
首先通過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的注入,當(dāng)然以后可以AutofacConfig 的Registers方法中把我們需要注入的對象注入到Autofac容器中)。關(guān)于依賴注入需要注意的主要有兩點(diǎn):一個是ContainerBuilder的擴(kuò)展方法RegisterControllers,其參數(shù)類型為params Assembly[]可以傳入一個或多個Assembly然后注冊這些Assembly里的Controller,這樣我們就可以將Controller放到不同的工程里;另一個是DependencyResolver.SetResolver,這樣會替換掉默認(rèn)的DependencyResolver實(shí)現(xiàn),我們正是通過這樣把Autofac容器作為了Mvc的容器從而完成依賴注入。
下面通過一個簡單的例子說明Ioc容器的應(yīng)用。首先創(chuàng)建一個簡單的接口及其實(shí)現(xiàn)的類
public interface IIocTest { string Say(); } public class IocTest: IIocTest { public string Say() { return "IocTest"; } }
然后再HomeController中添加一個該接口的字段,并創(chuàng)建一個構(gòu)造函數(shù)用于注入(AutoFac默認(rèn)只支持構(gòu)造函數(shù)注入,但也可以開啟屬性注入)。
private IIocTest iocTestInsatnce; public HomeController(IIocTest iocTest) { iocTestInsatnce = iocTest; }
然后再一個Action中調(diào)用接口方法,然后通過ViewBag(或其它方法)將其傳到頁面并顯示,頁面顯示有多種方法,這里直接加到標(biāo)題中:
public ActionResult Index() { ViewBag.iocSays = iocTestInsatnce.Say(); return View(); }
@{ ViewBag.Title = "Home Page"+ ViewBag.iocSays; }
然后運(yùn)行程序,查看相應(yīng)頁面的標(biāo)題,驗(yàn)證注入是否成功。
執(zhí)行Action
創(chuàng)建好Controller之后我們再來看Controller是如何執(zhí)行請求的。
首先看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的執(zhí)行通過ActionInvoker. BeginInvokeAction實(shí)現(xiàn),ActionInvoker的獲取方式如下:
protected virtual IActionInvoker CreateActionInvoker() { return Resolver.GetService<IAsyncActionInvoker>() ?? Resolver.GetService<IActionInvoker>() ?? new AsyncControllerActionInvoker(); }