當前位置:
首頁 > 知識 > Asp.net MVC-3-執行過程

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 serviceResolver)

{

_serviceResolver = serviceResolver ?? new SingleServiceResolver( => _factoryThunk,new DefaultControllerFactory { ControllerBuilder = this }, "ControllerBuilder.GetControllerFactory");

}

可知默認返回的ControllerFactory為DefaultControllerFactory(當然我們也可以註冊默認的自定義的ControllerFactory),這裡我們可繼續查看DefaultControllerFactory

internal DefaultControllerFactory(……)

{

……

_activatorResolver = activatorResolver ?? new SingleServiceResolver(

=> 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 beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState, ExecuteCoreState innerState)

{

return innerState.AsyncInvoker.BeginInvokeAction(innerState.Controller.ControllerContext, innerState.ActionName, asyncCallback, asyncState);

};

EndInvokeVoidDelegate 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 ?? Resolver.GetService ?? 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 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 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的處理過程圖

Asp.net MVC-3-執行過程

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 科技優家 的精彩文章:

Java 逆變與協變的名詞說明
Jenkins的安裝配置
webpack的Hot Module Replacement運行機制

TAG:科技優家 |

您可能感興趣

MongoDB系統CentOS 7.1 crash的排障過程
Nature Chemistry:Na2/3Mg0.28Mn0.72O2中無過量鹼金屬離子的氧的氧化還原化學過程
《idol MOMS》Kang Ta公開H.O.T.重組籌備過程
NBA 2019 全明星賽 Team LeBron 及 Team Giannis 隊長選人過程完整公開
SHINee Key-log6日出擊 公開專輯製作過程
OceanBase 0.4 自舉時庫表創建過程
HttpURLConnection使用過程中踩的坑
MapReduce中源碼分析(map端的過程)
HackTheBox Writeup之拿下Mantis主機許可權過程
NASA將直播OSIRIS-REx在小行星Bennu著陸過程
SAP Fiori實施之Transactional Apps實施全過程
IPhone X在升級IOS 12.1的過程中 爆! 炸! 了!
Biomaterials:肺上皮再生過程中,Fibrillin-2和Tenascin-C消除了年齡差距的影響
IPhone X在升級IOS 12.1的過程中 爆!炸!了!
四方框框|Lidia Springer~「GIRL IN MASK」 精彩插圖繪製過程
DeepLab v2及調試過程
89年巴西小哥Tullius Heuer的創作過程
Ultimaker Cura集成了HP 3D掃描軟體,以簡化3D列印過程!
Ryan Reynolds 談論《Pokémon: Detective Pikachu》角色 Pikachu 學習過程
Magic Leap 首次對外講述產品演化過程 | GDC 2018