⑦根据IsapiWorkerRequest对象,HttpRuntime创建HttpContext对象
![7 技术分享](http://image.mamicode.com/info/201508/20180925214400472531.png)
⑧HttpApplicationFactory创建新的或者从HttpApplication池获取现有的、可用的HttpApplication对象
HttpApplication的工作包括:
● 初始化的时候加载全部的HttpModule
● 接收请求
● 在不同阶段引发不同的事件,使得HttpModule通过订阅事件的方式加入到请求的处理过程中
● 在一个特定阶段获取一个IHttpHandler实例,最终将请求交给具体的IHttpHandler来实现
![8 技术分享](http://image.mamicode.com/info/201508/20180925214400728426.png)
⑨接下来,就是HttpModules发挥作用的时候
![9 技术分享](http://image.mamicode.com/info/201508/20180925214400969671.png)
所有的HttpModules都实现了IHttpModule接口:
public interface IHttpModule
{
void Init(HttpApplication app);
void Dispose();
}
可见,HttoModules正是由Init方法,根据传入的HttpApplication类型参数,订阅了HttpApplication的所有事件。
我们自定义一个HttpModule:
public class TestModule : IHttpModule
{
public void Dispose(){}
public void Init(HttpApplication app)
{
app.PostAcquireRequestState += new EventHandler(app_PostAcuiredRequestState);
app.PreRequestHandlerExecute += new EventHandler(app_PreRequestHandlerExecute);
}
void app_PreRequestHandlerExecute(object sender, EventArgs e)
{
//TODO:
}
void app_PostAcquiredRequestState(object sender, EventArgs e)
{
//TODO:
}
}
⑩当某个请求与一个规则匹配后,ASP.NET会调用匹配的HttpHandlerFactory的GetHandler方法来获取一个HttpHandler实例, 最后由一个HttpHandler实例来处理当前请求,生成响应内容
![10 技术分享](http://image.mamicode.com/info/201508/20180925214401345701.png)
所有的HttpHandlers都实现了IHttpHandler接口:
public interface IHttpHandler
{
bool IsReusable{get;}
void ProcessRequest(HttpContext context);
}
比如我们可以自定义一个HttpHandler来响应一类特定的请求:
public class Login : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
string username = context.Request.Form["name"];
string password = context.Request.Form["password"];
if(password="sth")
{
System.Web.Security.FormsAuthentication.SetAuthCookie(username, false);
context.Response.Write("ok");
}
else
{
context.Response.Write("用户名和密码不正确");
}
}
}
⑾ASP.NET MVC的入口在UrlRoutingModule,即订阅了HttpApplication的第7个管道事件PostResolveRequestCahce,换句话说,是在HtttpApplication的第7个管道事件处对请求进行了拦截
![11 技术分享](http://image.mamicode.com/info/201508/20180925214401592806.png)
UrlRouteModlue实现了IHttpModule:
![技术分享](/img/fz.gif)
public class UrlRoutingModule : IHttpModule
{
// Fields
private static readonly object _contextKey = new object();
private static readonly object _requestDataKey = new object();
private RouteCollection _routeCollection;
// Methods
protected virtual void Dispose()
{
}
protected virtual void Init(HttpApplication application)
{
if (application.Context.Items[_contextKey] == null)
{
application.Context.Items[_contextKey] = _contextKey;
application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
}
}
private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)
{
HttpContextBase context = new HttpContextWrapper(((HttpApplication) sender).Context);
this.PostResolveRequestCache(context);
}
[Obsolete("This method is obsolete. Override the Init method to use the PostMapRequestHandler event.")]
public virtual void PostMapRequestHandler(HttpContextBase context)
{
}
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, SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0]));
}
if (!(routeHandler is StopRoutingHandler))
{
RequestContext requestContext = new RequestContext(context, routeData);
context.Request.RequestContext = requestContext;
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
if (httpHandler == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[] { routeHandler.GetType() }));
}
if (httpHandler is UrlAuthFailureHandler)
{
if (!FormsAuthenticationModule.FormsAuthRequired)
{
throw new HttpException(0x191, SR.GetString("Assess_Denied_Description3"));
}
UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this);
}
else
{
context.RemapHandler(httpHandler);
}
}
}
}
void IHttpModule.Dispose()
{
this.Dispose();
}
void IHttpModule.Init(HttpApplication application)
{
this.Init(application);
}
// Properties
public RouteCollection RouteCollection
{
get
{
if (this._routeCollection == null)
{
this._routeCollection = RouteTable.Routes;
}
return this._routeCollection;
}
set
{
this._routeCollection = value;
}
}
}
![技术分享](/img/fz.gif)
UrlRoutingModule是在Web.config或默认的web.config中配置:
<httpModules>
......
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />
</httpModules>
⑿而在请求到达UrlRoutingModule之前,我们在全局文件中做了如下配置
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
......
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
这意味着:在HttpApplication的第一个管道事件BeginRequest处,通过MapRoute()方法把路由注册到了RouteCollection中。在实际使用中,UrlRoutingModule是通过RouteTable的静态属性RouteCollection获取路由。
![12 技术分享](http://image.mamicode.com/info/201508/20180925214401996183.png)
⒀当请求到达UrlRoutingModule的时候,UrlRoutingModule取出请求中的Controller、Action等RouteData信息,与路由表中的所有规则进行匹配,若匹配,把请求交给IRouteHandler,即MVCRouteHandler
![13 技术分享](http://image.mamicode.com/info/201508/20180925214402295053.png)
MVCRouteHandler是用来生成实现IHttpHandler接口的MvcHandler:
namespace System.Web.Routing
{
public interface IRouteHandler
{
IHttpHandler GetHttpHandler(RequestContext requestContext);
}
}
UrlRoutingModule如何把请求交给MVCRouteHandler?
通过分析UrlRoutingModule的源码可以看到:
//通过RouteCollection的静态方法GetRouteData获取到封装路由信息的RouteData实例
RouteData routeData = this.RouteCollection.GetRouteData(context);
//再从RouteData中获取MVCRouteHandler
IRouteHandler routeHandler = routeData.RouteHandler;
为什么可以从RouteData中拿到MVCRouteHadnler呢?
因为当我们在HttpApplication的第一个管道事件,使用MapRoute()方法注册路由的时候,已经通过Route类的构造函数把MVCRouteHandler注入到路由中了。
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),
DataTokens = new RouteValueDictionary()
};
if ((namespaces != null) && (namespaces.Length > 0)) {
route.DataTokens["Namespaces"] = namespaces;
}
routes.Add(name, route);
return route;
}
⒁MVCRouteHandler把请求交给MvcHandler
还是从UrlRoutingModule的源码可以看到,通过HttpHandler的GetHttpHandler()方法获取到了实现了IHttpHandler接口的MVCHandler:
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
context.RemapHandler(httpHandler);
![14 技术分享](http://image.mamicode.com/info/201508/20180925214402759962.png)
MvcHandler的部分源码为:
![技术分享](/img/fz.gif)
public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState
{
protected internal virtual void ProcessRequest(HttpContextBase httpContext)
{
SecurityUtil.ProcessInApplicationTrust(() =>
{
IController controller;
IControllerFactory factory;
ProcessRequestInit(httpContext, out controller, out factory);//初始化了ControllerFactory
try
{
controller.Execute(RequestContext);
}
finally
{
factory.ReleaseController(controller);
}
});
}
private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory) {
bool? isRequestValidationEnabled = ValidationUtility.IsValidationEnabled(HttpContext.Current);
if (isRequestValidationEnabled == true) {
ValidationUtility.EnableDynamicValidation(HttpContext.Current);
}
AddVersionHeader(httpContext);
RemoveOptionalRoutingParameters();
string controllerName = RequestContext.RouteData.GetRequiredString("controller");
factory = ControllerBuilder.GetControllerFactory();
controller = factory.CreateController(RequestContext, controllerName);
if (controller == null) {
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,MvcResources.ControllerBuilder_FactoryReturnedNull,factory.GetType(),controllerName));
}
}
}
![技术分享](/img/fz.gif)
⒂从以上可以看出:首先通过ControllerBuilder的静态方法GetControllerFactory获取到实现IControllerFactory接口的ControllerFactory,然后根据从上下文中的路由数据中拿到controller名称,并据此创建实现IController接口的Controller
![15 技术分享](http://image.mamicode.com/info/201508/20180925214403179943.png)
Controller派生于ControllerBase, 而ControllerBase实现了IController接口。ControllerBase的部分源码如下:
public abstract class ControllerBase : IController
{
protected virtual void Execute(RequestContext requestContext)
{
if (requestContext == null)
{
throw new ArgumentNullException("requestContext");
}
if (requestContext.HttpContext == null)
{
throw new ArgumentException(
MvcResources.ControllerBase_CannotExecuteWithNullHttpContext,
"requestContext");
}
VerifyExecuteCalledOnce();
Initialize(requestContext);
using (ScopeStorage.CreateTransientScope())
{
ExecuteCore();
}
}
protected abstract void ExecuteCore();
......
}
从中可以看成:
● 每次调用controller,都会执行基类ControllerBase的Execute()方法
● Execute()方法又会调用ExecuteCore()这个抽象方法
● ExecuteCore()这个抽象方法的实现被定义在Controller中
● 在Controller中的ExecuteCore()方法会调用ActionInvoker的InvokeAction()方法
⒃ActionInvoker激发Action方法
![16 技术分享](http://image.mamicode.com/info/201508/20180925214403483697.png)
ActionInvoker实现了IActionInvoker接口:
public interface IActionInvoker
{
bool InvokeAction(ControllerContext controllerContext, string actionName);
}
MVC默认的ActionInvoker是ControllerActionInvoker。
在Controller类中,提供了类型为IActionInvoker的属性ActionInvoker,当执行ExecuteCore()方法时会让这个ActionInvoker调用InvokeAction()方法激发Action。如下:
public class Controller
{
......
private IActionInvoker _actionInvoker;
public IActionInvoker ActionInvoker
{
get
{
if(_actionInvoker == null)
{
_actionInvoker = CreateActionInvoker();
}
return _actionInvoker;
}
set
{
_actionInvoker = value;
}
}
protected virtual IActionInvoker CreateActionInvoker()
{
return new ControllerActionInvoker();
}
public override void ExecuteCore()
{
ActionInvoker.InvokeAction(...);
}
.....
}
ActionInvoker在执行InvokeAction()方法时会需要有关Controller和Action的相关信息,实际上,Controller信息(比如Controller的名称、类型、包含的Action等)被封装在ControllerDescriptor这个类中,Action信息(比如Action的名称、参数、属性、过滤器等)被封装在ActionDescriptor中。
另外,ActionDescriptor还提供了一个FindAction()方法,用来找到需要被执行的Action。
⒄ActionInvoker在执行InvokeAction()方法返回ActionResult
![17 技术分享](http://image.mamicode.com/info/201508/20180925214403839216.png)
ActionResult是一个抽象类:
public abstract class ActionResult
{
public abstract void ExecuteResult(ControllerContext context);
}
如果ActionResult是非ViewResult,比如JsonResult, ContentResult,这些内容将直接被输送到Response响应流中,显示给客户端;如果是ViewResult,就会进入下一个渲染视图环节。
⒅ViewEngine找到需要被渲染的视图
![18 技术分享](http://image.mamicode.com/info/201508/20180925214404131249.png)
默认的有Razor View Engine和Web Form View Engine,实现IViewEngine接口。
IViewEngine接口方法:
● FindPartialView
● FindView
● ReleaseView
如果要创建自定义View Engine,只需要派生于VirtualPathProviderViewEngine这个类。
⒆View被加载成WebViewPage<TModel>类型,并渲染生成Html
![19 技术分享](http://image.mamicode.com/info/201508/20180925214404436956.png)
调用ViewResult的ExecuteResult()方法,通过IView的Render()方法渲染成Html。
public abstract class ViewResultBase : ActionResult
{
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)
{
//通过视图引擎获取到ViewEngineResult ,此时模板页面【aspx】被加载成了WebViewPage<TModel>
result = FindView(context);
View = result.View;
}
TextWriter writer = context.HttpContext.Response.Output;
ViewContext viewContext = new ViewContext(context, View, ViewData, TempData, writer);
View.Render(viewContext, writer);
if (result != null)
{
result.ViewEngine.ReleaseView(context, View);
}
}
}
![技术分享](/img/fz.gif)