这里写自定义目录标题
MVC框架的原理详解
前言:最近一段时间在学习MVC源码,说实话,研读源码真是一个痛苦的过程,好多晦涩的语法搞得人晕晕乎乎。这两天算是理解了一小部分,这里先记录下来,也给需要的园友一个参考,奈何博主技术有限,如有理解不妥之处,还希望大家斧正,博主感激不尽!
一、MVC原理解析
最近园子里Asp.Net Core火了一阵,不管微软的开源动作有多么迟缓,还是希望微软能够给力一次。作为Core的主要Web框架——MVC,虽然已经开源,但是读起来着实费劲,并且感觉很多核心部件都找不到。于是只能通过Reflector去反编译MVC5的组件以及参考博客园Fish Li等大神的文章去学习下MVC5的原理。
————————————————
Asp.Net Core MVC的开源地址:https://github.com/aspnet/Mvc
Asp.net MVC的开源地址:http://aspnetwebstack.codeplex.com/SourceControl/latest
1、MVC原理
之前的文章有介绍MVC的路由机制,其实路由机制算是MVC的原理的核心之一。在此我们还是要不厌其烦再来谈谈整个过程,因为这是理解MVC原理不可逾越的鸿沟。当我们收到一个URL的请求时,服务端收到请求,主要经历以下几个步骤:
1.请求被UrlRoutingModule部件拦截
2.封装请求上下文HttpContext,成为HttpContextWrapper对象。
3.根据当前的HttpContext,从Routes集合中得到与当前请求URL相符合的RouteData对象。
4.将RouteData与HttpContext请求封装成一个RequestContext对象。
5.根据RequestContext对象,从RouteData的RouteHandler中获取IHttpHandler(MVC里面会有一个IHttpHandler的实现类MvcHandler)。
6.执行IHttpHandler(MvcHandler),然后就是通过反射激活具体的controller,执行具体的action。
二、HttpHandler
上文说过MvcHandler是继承至IHttpHandler接口的!为什么这里大标题会用HttpHandler而不是MvcHandler呢?因为博主觉得,HttpHandler实在是太重要了,首先得理解了HttpHandler这么一个大的东西,然后再来看具体的MvcHandler才有意义。
1、HttpHandler、IHttpHandler、MvcHandler的说明
1.HttpHandler指所有实现IHttpHandler接口一类类型的统称,它是一个大的称谓。这些类型有一个共同的功能,那就是可以用来处理Http请求。
2.IHttpHandler是微软定义的一类接口,用来约束所有能够处理Http请求的类型的接口规则。
3.MvcHandler是Mvc里面实现IHttpHandler接口的类型,也就是说,MvcHandler是Mvc里面处理Http请求的类型。
总而言之,HttpHandler只是一个逻辑称谓,它并不具体存在。而IHttpHandler和MvcHandler是.net framework里面具体存在的接口和实现类,是前者的表现形式。
2、IHttpHandler解析
2.1、Asp.net管线事件简易说明
在处理该请求时将由 HttpApplication 类执行以下事件。 希望扩展 HttpApplication 类的开发人员尤其需要注意这些事件。
- 对请求进行验证,将检查浏览器发送的信息,并确定其是否包含潜在恶意标记。 有关更多信息,请参见 ValidateRequest 和脚本侵入概述。
- 如果已在 Web.config 文件的 UrlMappingsSection 节中配置了任何 URL,则执行 URL 映射。
- 引发 BeginRequest 事件。
- 引发 AuthenticateRequest 事件。
- 引发 PostAuthenticateRequest 事件。
- 引发 AuthorizeRequest 事件。
- 引发 PostAuthorizeRequest 事件。
- 引发 ResolveRequestCache 事件。
- 引发 PostResolveRequestCache 事件。
- 根据所请求资源的文件扩展名(在应用程序的配置文件中映射),选择实现 IHttpHandler 的类,对请求进行处理。 如果该请求针对从 Page 类派生的对象(页),并且需要对该页进行编译,则 ASP.NET 会在创建该页的实例之前对其进行编译。
- 引发 PostMapRequestHandler 事件。
- 引发 AcquireRequestState 事件。
- 引发 PostAcquireRequestState 事件。
- 引发 PreRequestHandlerExecute 事件。
- 为该请求调用合适的 IHttpHandler 类的 ProcessRequest 方法(或异步版 IHttpAsyncHandler.BeginProcessRequest)。 例如,如果该请求针对某页,则当前的页实例将处理该请求。
- 引发 PostRequestHandlerExecute 事件。
- 引发 ReleaseRequestState 事件。
- 引发 PostReleaseRequestState 事件。
- 如果定义了 Filter 属性,则执行响应筛选。
- 引发 UpdateRequestCache 事件。
- 引发 PostUpdateRequestCache 事件。
- 引发 EndRequest 事件。
- 引发 PreSendRequestHeaders 事件。
- 引发 PreSendRequestContent 事件。
这里不可能把每个管线事件将清楚,但是在整个管线事件中,有两个重要的角色就是HttpHandler和HttpModule。在这些事件中,第10个事件【根据所请求资源的文件扩展名(在应用程序的配置文件中映射),选择实现 IHttpHandler 的类,对请求进行处理】 是HttpHandler创建的地方。
2.2、Asp.net中常见的HttpHandler类型
首先还是来看看IHttpHandler的定义
public interface IHttpHandler
{
// 定义一个处理当前http请求的方法
void ProcessRequest(HttpContext context);
// 指示当前实例是否可以再次使用
bool IsReusable {
get; }
}
接口的定义很简单,ProcessRequest()方法里面传一个当前请求的上下文对象去处理当前的http请求。
为了处理异步请求,Framework里面还定义了一个异步的IHttpHandler接口:
public interface IHttpAsyncHandler : IHttpHandler
{
// Methods
IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData);
void EndProcessRequest(IAsyncResult result);
}
接口的两个方法应该也不难理解。
我们已经说了,HttpHandler的主要作用是处理http请求,原来在做webform的时候应该都写过后缀ashx的一般处理程序吧,这个一般处理程序就是通过实现IHttpHandler接口去实现的。我们是否曾经也写过类似这样的代码,新建一个TestHttpHandler.ashx文件,代码如下:
public class TestHttpHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
var username = context.Request.QueryString["username"];
var password = context.Request.QueryString["password"];
if (username == "admin" && password == "admin")
{
context.Response.Write("用户admin登录成功");
}
else
{
context.Response.Write("用户名或者密码错误");
}
}
public bool IsReusable
{
get
{
return false;
}