进入MVC处理通道
这一篇主要讲如何通过Asp.net处理管道把请求交给MVC进行处理的(进入MVC处理通道)。
首先来看一下经典的Asp.net处理管道的生命周期。

我们知道一个ASP.NET应用程序可以有多个HttpModule,但是只能有一个HttpHandler,并且通过这个HttpHandler的BeginProcessRequest(或ProcessRequest)来处理并返回请求,查看声明处理管道周期可知在MapHttpHandler这个周期将会根据请求的URL来查询对应的HttpHandler,那么它是如何查找的呢。
查找系统web.config中的httpModules配置节,在倒数第二行发现一个name为UrlRoutingModule-4.0的IHttpModule配置,这是查找HttpHandler的关键之处。下面分析一下UrlRoutingModule的代码:
protected virtual void Init(HttpApplication application) {
if (application.Context.Items[_contextKey] != null) {
return;
}
application.Context.Items[_contextKey] = _contextKey;
application.PostResolveRequestCache += OnApplicationPostResolveRequestCache;
}
private void OnApplicationPostResolveRequestCache(object sender, EventArgs e) {
HttpApplication app = (HttpApplication)sender;
HttpContextBase context = new HttpContextWrapper(app.Context);
PostResolveRequestCache(context);
}
public virtual void PostResolveRequestCache(HttpContextBase context) {
RouteData routeData = RouteCollection.GetRouteData(context);
……
IRouteHandler routeHandler = routeData.RouteHandler;
……
RequestContext requestContext = new RequestContext(context, routeData);
context.Request.RequestContext = requestContext;
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
……
context.RemapHandler(httpHandler);
}
可以看到UrlRoutingModule设置了一个PostResolveRequestCache事件处理方法,该方法从RouteCollection通过匹配找到请求对应的路由数据RouteData(包含如Mvc中的Controller名、Action名等),然后从RouteData的属性RouteHandler获取一个IRouteHandler的实例,再从IRouteHandler实例里获取对应的IHttpHandler实例,最后调用HttpContext的RemapHandler方法重新为HttpContext设置RemapHandlerInstance。
根据前面asp.net初始化流程分析2我们知道在获取Httphandler时经典模式和集成模式使用了不同的IExecutionStep,经典模式用的是MapHandlerExecutionStep集成模式用的是MaterializeHandlerExecutionStep,查看二者的执行方法Execute。
先看MaterializeHandlerExecutionStep。
void IExecutionStep.Execute() {
HttpContext context = _application.Context;
HttpRequest request = context.Request;
IHttpHandler handler = null;
string configType = null;
……
if (context.RemapHandlerInstance != null){
wr.SetScriptMapForRemapHandler();
context.Handler = context.RemapHandlerInstance;
}
……
}
可以看到MaterializeHandlerExecutionStep中如果UrlRoutingModule模块中在HttpContext设置了RemapHandlerInstance,则直接用RemapHandlerInstance设置HttpContext的Handler。
再看MapHandlerExecutionStep。
void IExecutionStep.Execute() {
HttpContext context = _application.Context;
HttpRequest request = context.Request;
……
context.Handler = _application.MapHttpHandler(context, request.RequestType, request.FilePathObject, request.PhysicalPathInternal, false /*useAppConfig*/);
……
}
在MapHandlerExecutionStep中会调用HttpApplication的MapHttpHandler方法来设置HttpContext的Handler。下面查看MapHttpHandler代码:
internal IHttpHandler MapHttpHandler(HttpContext context, String requestType, VirtualPath path, String pathTranslated, bool useAppConfig) {
IHttpHandler handler = (context.ServerExecuteDepth == ) ? context.RemapHandlerInstance : null;
using (new ApplicationImpersonationContext()) {
if (handler != null){
return handler;
}
……
}
从第一行代码就可以看到如果HttpContext的RemapHandlerInstance不为空则直接返回HttpContext的RemapHandlerInstance(context.ServerExecuteDepth是指页面是否使用了HttpServerUtility.Execute进行页面内跳转)。这样也就同样使用了UrlRoutingModule模块中在HttpContext设置的RemapHandlerInstance,至于HttpContext没有设置的RemapHandlerInstance的情况下如何根据默认的扩展名匹配查找HttpHandler就不在此讨论了。
通过上面的分析我们可以设想通过在UrlRoutingModule中的静态RouteCollection属性中注册RouteData而且设置该RouteData的IRouteHandler(一个接口,只有一个方法GetHttpHandler用来获取HttpHandler)来实现路由与HttpHandler的对应。下面来分析一下MvcHandler是如何通过路由注册的,首先来看RouteCollection的实现
public RouteCollection RouteCollection {
get {
if (_routeCollection == null) {
_routeCollection = RouteTable.Routes;
}
return _routeCollection;
}
set {
routeCollection = value;
}
}
可以看到RouteCollection其实是包装了RouteTable中的静态Routes,如果有Mvc项目经验的话应该很眼熟了,一般的Mvc程序在Global.asax中一般都有这么一段用来注册路由:
protected void Application_Start()
{
……
RouteConfig.RegisterRoutes(RouteTable.Routes);
……
} 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 }
);
}
}
而我们定义的路由设置MvcHandler的奥妙正在MapRoute方法里,这是一个扩展方法,定义在System.Web.Mvc.RouteCollectionExtensions里:
public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
{
……
Route route = new Route(url, new MvcRouteHandler())
{
Defaults = CreateRouteValueDictionaryUncached(defaults),
Constraints = CreateRouteValueDictionaryUncached(constraints),
DataTokens = new RouteValueDictionary()
};
……
routes.Add(name, route);
return route;
}
可以看到MapRoute注册路由是绑定了一个MvcRouteHandler作为IRouteHandler,下面看MvcRouteHandler是如何实现的:
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
{
requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));
return new MvcHandler(requestContext);
}
在这里终于看到了创建MvcHandler的代码。
至此,我们应该有一个清晰的认识了,我们通过全局静态属性集合(RouteTable.Routes)去添加各种各样的Route(但应该在HttpModule初始化周期之前,一般是利用HttpApplication创建的周期在Application_Start方法中添加了我们所需要的Route规则),当然在添加路由的时候带上了MvcHandler这个重要的HttpHandler。然后通过UrlRoutingModule在PostResolveRequestCache周期通过查找注册的Route获取请求的RouteData以及其属性IRouteHandler实例(至于路由是如何匹配的还要等后续的篇章继续讲),然后通过IRouteHandler实例可以通过GetHttpHandler获取IHttpHandler并将其设置到HttpContext的RemapHandlerInstance属性。最终在MapHttpHandler周期通过获取HttpContext的RemapHandlerInstance实现了不同的HttpHandler来接管匹配不同路由的URL。
至此对于进入MVC处理管道之前的一些处理基本讲完了,下面就正式进入MVC的旅程,同时分析的主要代码也进入了asp.net mvc项目。
进入MVC处理通道的更多相关文章
- C# mvc统一通道使用过滤器
问题描述 使用C#过滤器有一个最大的问题就是在过滤器转向后程序仍然会执行方法体 问题解决思路 使用统一通道执行方法 不直接进入控制器 通过反射调用 using System; using System ...
- C#净化版WebApi框架
前言 我们都知道WebApi是依赖于Asp.Net MVC的HttpRouteCollection进行路由 . 但WebApi和MVC之间是没有依赖关系的, WebApi的基类ApiControlle ...
- Paypal开发中遇到请求被中止: 未能创建 SSL/TLS 安全通道及解决方案
最近在基于ASP.NET上开发了Paypal支付平台,在ASP.NET开发的过程中没有遇到这个问题,但是引用到MVC开发模式中的时候就出现了"未能创建 SSL/TLS 安全通道及解决方案&q ...
- 使用 WPF+ ASP.NET MVC 开发 在线客服系统 (一)
近段时间利用业余时间开发了一套在线客服系统,期间遇到过大大小小不少问题,好在都一一解决,最终效果也还可以,打算写一个系列的文章把开发过程详细的记录下来. 希望能够和更多的开发人员互相交流学习,也希望有 ...
- 关于MVC EF架构及Repository模式的一点心得
一直都想写博客,可惜真的太懒了或者对自己的描述水平不太自信,所以...一直都是不想写的状态,关于领域驱动的东西看了不少,但是由于自己水平太差加上工作中实在用不到,所以一直处于搁置状态,最近心血来潮突然 ...
- Asp.NET MVC 使用 SignalR 实现推送功能一(Hubs 在线聊天室)
简介 ASP .NET SignalR 是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信.什么是实时通信的Web呢?就是让客户端(Web页面)和服务器端 ...
- asp.net mvc 模型验证注解,表单提交
一.添加模型 public class Account { public int ID { get; set; } [Display(Name = "姓名")] //设置要显示的字 ...
- 写自己的ASP.NET MVC框架(上)
http://www.cnblogs.com/fish-li/archive/2012/02/12/2348395.html 阅读目录 开始 ASP.NET程序的几种开发方式 介绍我的MVC框架 我的 ...
- 不用asp.net MVC,用WebForm照样可以实现MVC(请看最后一句话)
在<避开WebForm天坑,拥抱ASP.Net MVC吧>这篇博客中我讲到了ASP.net WebForm由于一些先天的“诱导犯罪”的缺陷,现在用ASP.net MVC的公司越来越多.但是 ...
随机推荐
- (转)详解JS位置、宽高属性之一:offset系列
很多初学者对于JavaScript中的offset.scroll.client一直弄不明白,虽然网上到处都可以看一张图(图1),但这张图太多太杂,并且由于浏览器差异性,图示也不完全正确. 图一 不知道 ...
- Oracle清除数据库中长时间占用资源的非活动的会话
1.启动资源计划 alter system set resource_limit=true scope=spfile; 2.设置非活动回话十五分钟断开,释放资源 alter profile defau ...
- 控制器controller与指令中的link、controller中变量作用域的关系
angjualrjs中的作用域与原生js中的函数嵌套原理一致,都是存在作用域的继承.若在子控制器(同样包括在指令中的link或是controllerding中定义变量,此时指令中必须未使用scope独 ...
- 腾讯IVWEB团队:前端 fetch 通信
欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~ 作者:villainthr 文章摘自: 前端小吉米 随着前端异步的发展, XHR 这种耦合方式的书写不利于前端 ...
- java内存模型3
数据竞争与顺序一致性保证 当程序未正确同步时,就会存在数据竞争.java内存模型规范对数据竞争的定义如下: 在一个线程中写一个变量, 在另一个线程读同一个变量, 而且写和读没有通过同步来排序. 当代码 ...
- C语言解析17monipdb.dat(http://www.ipip.net/)免费数据库
官方给的链接打不开,而且里面的逻辑,每次都会打开文件,所以自己做了点个修改,发上来,借大家参考: #include <stdio.h> #include <stdlib.h> ...
- 微信小程序demo
微信小程序demo github地址 去年小程序刚发布时特别火,赶潮流做了个demo.感觉小程序开发还是比较简单的,主要是官方文档写得比较好,遗憾的是很多API需要微信认证才能使用. 由于小程序包大小 ...
- More 3D Graphics (rgl) for Classification with Local Logistic Regression and Kernel Density Estimates (from The Elements of Statistical Learning)(转)
This post builds on a previous post, but can be read and understood independently. As part of my cou ...
- 微信小程序 生命周期函数详解
微信小程序 生命周期函数 小程序中 判断当前首页是从其他页面返回,还是由入口打开 由于小程序的数据在我们退出小程序时并没有得到释放,因此再次点击开来数据依然没有变成初始化 解决方法:在小程序 data ...
- WebService入门实例教程
什么是WebService 通过使用WebService,您的应用程序可以向全世界发布信息,或提供某项功能,它是基于Web的服务,通过Web进行发布.查找和使用. WebService脚本平台需支持X ...