在知道asp.net mvc 流程之前,必须知道完整的http请求在asp.net framework中的处理流程:
HttpRequest-->inetinfo.exe->ASPNET_ISAPI.DLL-->Http Pipeline-->ASPNET_WP.EXE-->HttpRuntime-->HttpApplication Factory-->HttpApplication-->HttpModule-->HttpHandler Factory-->HttpHandler-->HttpHandler.ProcessRequest()
具体参考过程
ASP.NET必须知道的:HttpModule,HttpHandler
下面简要描述下 asp.net mvc 处理流程:
1、在Web. config中 注册
Code
<modules>
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</modules>
2、在Global中设置 System.Web.Routing.RouteTable.Routes 的值,应用于解析Url,得到相应的Controller,Action,和RouteData
Code
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Contact", action = "Index", id = "" } // Parameter defaults
);
}
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
}
在MVC对RouteCollection 的扩展方法中,有MapRoute
Code
public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) {
if (routes == null) {
throw new ArgumentNullException("routes");
}
if (url == null) {
throw new ArgumentNullException("url");
}
Route route = new Route(url, new MvcRouteHandler()) {
Defaults = new RouteValueDictionary(defaults),
Constraints = new RouteValueDictionary(constraints)
};
if ((namespaces != null) && (namespaces.Length > 0)) {
route.DataTokens = new RouteValueDictionary();
route.DataTokens["Namespaces"] = namespaces;
}
routes.Add(name, route);
return route;
}
3、发送Http请求,因为在第1部注册了System.Web.Routing.UrlRoutingModule ,在执行到 HttpModule 时就调用IHttpModule接口的 Init 方法
Code
protected virtual void Init(HttpApplication application)
{
application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
application.PostMapRequestHandler += new EventHandler(this.OnApplicationPostMapRequestHandler);
}
1)我们看 Init 中的调用 application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);下的代码
Code
private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)
{
HttpContextBase context = new HttpContextWrapper(((HttpApplication) sender).Context);
this.PostResolveRequestCache(context);
}
再看this.PostResolveRequestCache(context);的调用
Code
public virtual void PostResolveRequestCache(HttpContextBase context)
{
RouteData routeData = this.RouteCollection.GetRouteData(context);
if (routeData != null)
{
IRouteHandler routeHandler = routeData.RouteHandler;
if (routeHandler == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoRouteHandler, new object[0]));
}
if (!(routeHandler is StopRoutingHandler))
{
RequestContext requestContext = new RequestContext(context, routeData);
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
if (httpHandler == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoHttpHandler, new object[] { routeHandler.GetType() }));
}
context.Items[_requestDataKey] = new RequestData { OriginalPath = context.Request.Path, HttpHandler = httpHandler };
context.RewritePath("~/UrlRouting.axd");
}
}
}
我们发现 IRouteHandler routeHandler = routeData.RouteHandler; 行把routeHandler赋了具体值。但 routeData.RouteHandler如何来的? 在第2部MapRoute的调用中,我们得到了它。通过routeHandler,我们得到了 IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);然后,通过context.Items[_requestDataKey] = new RequestData { OriginalPath = context.Request.Path, HttpHandler = httpHandler };我们把httpHandler 存入context.Items字段中。
2) 我们看 Init 中的调用 application.PostMapRequestHandler += new EventHandler(this.OnApplicationPostMapRequestHandler); 下的代码
Code
private void OnApplicationPostMapRequestHandler(object sender, EventArgs e)
{
HttpContextBase context = new HttpContextWrapper(((HttpApplication) sender).Context);
this.PostMapRequestHandler(context);
}
Code
public virtual void PostMapRequestHandler(HttpContextBase context)
{
RequestData data = (RequestData) context.Items[_requestDataKey];
if (data != null)
{
context.RewritePath(data.OriginalPath);
context.Handler = data.HttpHandler;
}
}
我们通过 RequestData data = (RequestData) context.Items[_requestDataKey];得到了存入 RequestData的RequestData 对象,再通过 context.Handler = data.HttpHandler;设置处理Http请求的IhttpHandler对象,也就是MvcRouteHandler对象。
可以看出:1)我们得到了 MvcRouteHandler对象。2)我们把MvcRouteHandler对象赋给了context.Handler
4)进入出来http请求的 MvcRouteHandler对象
Code
public class MvcRouteHandler : IRouteHandler {
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) {
return new MvcHandler(requestContext);
}
#region IRouteHandler Members
IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext) {
return GetHttpHandler(requestContext);
}
#endregion
}
通过 return new MvcHandler(requestContext); 我们发现,MvcRouteHandler 的作用是选择执行控制器操作的 IHttpHandler。
5、我们看MvcHandler的处理代码
Code
protected internal virtual void ProcessRequest(HttpContextBase httpContext) {
AddVersionHeader(httpContext);
// Get the controller type
string controllerName = RequestContext.RouteData.GetRequiredString("controller");
// Instantiate the controller and call Execute
IControllerFactory factory = ControllerBuilder.GetControllerFactory();
IController controller = factory.CreateController(RequestContext, controllerName);
if (controller == null) {
throw new InvalidOperationException(
String.Format(
CultureInfo.CurrentUICulture,
MvcResources.ControllerBuilder_FactoryReturnedNull,
factory.GetType(),
controllerName));
}
try {
controller.Execute(RequestContext);
}
finally {
factory.ReleaseController(controller);
}
}
6、controller.Execute(RequestContext);这一步是关键,它的作用是得到控制器,并执行。
我们发现, controller实现了IController接口,具体看看它的继承关系:
原来 controller.Execute(RequestContext) 执行的是ControllerBase的Execute,我们进入看看:
Code
protected virtual void Execute(RequestContext requestContext) {
if (requestContext == null) {
throw new ArgumentNullException("requestContext");
}
Initialize(requestContext);
ExecuteCore();
}
7、 在Execute方法中,调用了ExecuteCore,看看ExecuteCore的调用:
Code
protected abstract void ExecuteCore();
可以看出 ExecuteCore ,执行的是 Controller 中的方法。
Code
protected override void ExecuteCore() {
TempData.Load(ControllerContext, TempDataProvider);
try {
string actionName = RouteData.GetRequiredString("action");
if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) {
HandleUnknownAction(actionName);
}
}
finally {
TempData.Save(ControllerContext, TempDataProvider);
}
}
附近说明:【 ActionInvoker 的实际对象是实现 IActionInvoker 接口的对象,默认为 ControllerActionInvoker对象。
看看代码:
Code
public IActionInvoker ActionInvoker {
get {
if (_actionInvoker == null) {
_actionInvoker = new ControllerActionInvoker();
}
return _actionInvoker;
}
set {
_actionInvoker = value;
}
}
】
在ExecuteCore中,我们得到了action,并调用 ActionInvoker.InvokeAction(ControllerContext, actionName) 执行。
8、看看 InvokeAction的代码:
Code
public virtual bool InvokeAction(ControllerContext controllerContext, string actionName) {
if (controllerContext == null) {
throw new ArgumentNullException("controllerContext");
}
if (String.IsNullOrEmpty(actionName)) {
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 {
AuthorizationContext authContext = InvokeAuthorizationFilters(controllerContext, filterInfo.AuthorizationFilters, actionDescriptor);
if (authContext.Result != null) {
// the auth filter signaled that we should let it short-circuit the request
InvokeActionResult(controllerContext, authContext.Result);
}
else {
if (controllerContext.Controller.ValidateRequest) {
ValidateRequest(controllerContext.HttpContext.Request);
}
IDictionary<string, object> parameters = GetParameterValues(controllerContext, actionDescriptor);
ActionExecutedContext postActionContext = InvokeActionMethodWithFilters(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters);
InvokeActionResultWithFilters(controllerContext, filterInfo.ResultFilters, 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;
}
9. InvokeActionResult 其实就是反射调用 ActionResult 的 public abstract void ExecuteResult(ControllerContext context); 方法。
我们看看 ViewResultBase 对 ExecuteResult 的实现:
Code
public override void ExecuteResult(ControllerContext context) {
if (context == null) {
throw new ArgumentNullException("context");
}
if (String.IsNullOrEmpty(ViewName)) {
ViewName = context.RouteData.GetRequiredString("action");
}
ViewEngineResult result = null;
if (View == null) {
result = FindView(context);
View = result.View;
}
ViewContext viewContext = new ViewContext(context, View, ViewData, TempData);
View.Render(viewContext, context.HttpContext.Response.Output);
if (result != null) {
result.ViewEngine.ReleaseView(context, View);
}
}
1)进入 result = FindView(context); 其实 调用的是ViewResult的FindView的实现:
Code
protected override ViewEngineResult FindView(ControllerContext context) {
ViewEngineResult result = ViewEngineCollection.FindView(context, ViewName, MasterName);
if (result.View != null) {
return result;
}
// we need to generate an exception containing all the locations we searched
StringBuilder locationsText = new StringBuilder();
foreach (string location in result.SearchedLocations) {
locationsText.AppendLine();
locationsText.Append(location);
}
throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture,
MvcResources.Common_ViewNotFound, ViewName, locationsText));
}
2) 看看 FindView中的第一行代码 ViewEngineResult result = ViewEngineCollection.FindView(context, ViewName, MasterName);
在进入ViewEngineCollection.FindView看看:
Code
public virtual ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName) {
if (controllerContext == null) {
throw new ArgumentNullException("controllerContext");
}
if (string.IsNullOrEmpty(viewName)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "viewName");
}
Func<IViewEngine, ViewEngineResult> cacheLocator = e => e.FindView(controllerContext, viewName, masterName, true);
Func<IViewEngine, ViewEngineResult> locator = e => e.FindView(controllerContext, viewName, masterName, false);
return Find(cacheLocator, locator);
}
3)再看看看 ViewEngineCollection.FindView 中的Find调用:
Code
private ViewEngineResult Find(Func<IViewEngine, ViewEngineResult> cacheLocator, Func<IViewEngine, ViewEngineResult> locator) {
ViewEngineResult result;
foreach (IViewEngine engine in Items) {
if (engine != null) {
result = cacheLocator(engine);
if (result.View != null) {
return result;
}
}
}
List<string> searched = new List<string>();
foreach (IViewEngine engine in Items) {
if (engine != null) {
result = locator(engine);
if (result.View != null) {
return result;
}
searched.AddRange(result.SearchedLocations);
}
}
return new ViewEngineResult(searched);
}
10) 最后看看 从控制器到输出的流程 (注:Model 随 ControllerContext 传递)