ASP.NET Web API WebHost宿主环境中管道、路由
ASP.NET Web API WebHost宿主环境中管道、路由
前言
上篇中说到ASP.NET Web API框架在SelfHost环境中管道、路由的一个形态,本篇就来说明一下在WebHost环境中ASP.NET Web API框架中的管道、路由又是哪一种形态。
ASP.NET Web API路由、管道
- ASP.NET Web API 开篇介绍示例
- ASP.NET Web API 路由对象介绍
- ASP.NET Web API 管道模型
- ASP.NET Web API selfhost宿主环境中管道、路由
- ASP.NET Web API webhost宿主环境中管道、路由
ASP.NET Web API webhost宿主环境中管道、路由
下面将会主要讲解路由的注册执行过程(WebHost环境),对于管道不会去刻意的说明,都会包含在路由的讲解中,拆开来说明效果不太好。
HttpRoute->HostedHttpRoute->HttpWebRoute->Route
想要清楚的了解路由的执行过程以及管道的形态,就必须对路由对象熟知,然而在前面的《ASP.NET Web API 路由对象介绍》篇幅中只是分别的对各个环境下的路由对象类型进行了说明,并没有说明转变的过程。
现在就来讲解路由对象的“转变”过程。
示例代码1-1
protected void Application_Start(object sender, EventArgs e)
{
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
"DefaultAPI", "api/{controller}/{id}", new { controller="product",id = RouteParameter.Optional });
}
示例代码1-1中是在WebHost环境下进行的路由注册,根据MapHttpRoute()方法我们转定义过去应该是一个HttpRouteCollection类型的扩展方法类型HttpRouteCollectionExtensions,既然是HttpRouteCollectionExtensions类型里的实现那我们就过去看看到底啥情况。
示例代码1-2
public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, HttpMessageHandler handler)
{
if (routes == null)
{
throw System.Web.Http.Error.ArgumentNull("routes");
}
HttpRouteValueDictionary dictionary = new HttpRouteValueDictionary(defaults);
HttpRouteValueDictionary dictionary2 = new HttpRouteValueDictionary(constraints);
IDictionary<string, object> dataTokens = null;
HttpMessageHandler handler2 = handler;
IHttpRoute route = routes.CreateRoute(routeTemplate, dictionary, dictionary2, dataTokens, handler2);
routes.Add(name, route);
return route;
}
我们可以看到返回类型是IHttpRoute,生成则是由HttpRouteCollection类型的实例调用其中的CreateRoute()方法来实现,这里有的朋友要问了,这不是SelfHost中的路由注册实现方式吗?回答是对的,只不过在WebHost中利用多态来实现返回成其他的类型,接着往下看。
既然都看到了在这里发生的变化,那说明是有继承了HttpRouteCollection类型的这么一个类型然后创建的路由对象。这样一理就清晰多了,在SelfHost环境中HttpRouteCollection类型是存在于HttpConfiguration类型的对象中,并不单独使用。而在WebHost中也是。
这个时候我们再回过头来看一下代码1-1中的GlobalConfiguration类型中的定义。
示例代码1-3
private static Lazy<HttpConfiguration> _configuration = new Lazy<HttpConfiguration>(delegate {
HttpConfiguration configuration = new HttpConfiguration(new HostedHttpRouteCollection(RouteTable.Routes));
configuration.Services.Replace(typeof(IAssembliesResolver), new WebHostAssembliesResolver());
configuration.Services.Replace(typeof(IHttpControllerTypeResolver), new WebHostHttpControllerTypeResolver());
configuration.Services.Replace(typeof(IHostBufferPolicySelector), new WebHostBufferPolicySelector());
return configuration;
});
public static HttpConfiguration Configuration
{
get
{
return _configuration.Value;
}
}
从代码1-3中我们可以看到_configuration静态变量使用了延迟加载,啥意思呢就是下面的那个HttpConfiguration类型的Configuration属性如果使用了才会去实例化,跑偏了这不是重点。
重点是在实例化静态变量_configuration中可以清楚的看到使用了HostedHttpRouteCollection类型的路由集合类型对象作为构造函数参数。可以自行的去看一下HostedHttpRouteCollection的内部结构。
现在再回到创建路由的那会,也就是代码1-1和代码1-2中所示的那样,实际也就是HostedHttpRouteCollection类型在创建路由对象,按照老规矩直接看实现代码。
示例代码1-4
public override IHttpRoute CreateRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler)
{
return new HostedHttpRoute(uriTemplate, defaults, constraints, dataTokens, handler);
}
从代码1-4中可以清楚的看到是返回的是HostedHttpRoute路由对象,我们可以看一下构造函数,只有这样才能知道“转变”的过程。
public HostedHttpRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler)
{
RouteValueDictionary dictionary = (defaults != null) ? new RouteValueDictionary(defaults) : null;
RouteValueDictionary dictionary2 = (constraints != null) ? new RouteValueDictionary(constraints) : null;
RouteValueDictionary dictionary3 = (dataTokens != null) ? new RouteValueDictionary(dataTokens) : null;
this.OriginalRoute = new HttpWebRoute(uriTemplate, dictionary, dictionary2, dictionary3, HttpControllerRouteHandler.Instance, this);
this.Handler = handler;
}
在代码1-4中我们只需要关注OriginalRoute属性的赋值,OriginalRoute属性是HostedHttpRoute类型里的一个属性,是用来设置对Route对象的引用,示例代码1-4中也就是HttpWebRoute类型的对象,对于HttpWebRoute对象的构造函数这里就不例举了。这个时候可以看到是将HttpControllerRouteHandler类型的对象作为Route(HttpWebRoute)对象的RouteHandler(路由处理程序)。
大家都知道ASP.NET Web API框架在WebHost环境中是依赖于ASP.NET的,实则也是通过IHttpModule来进行前期的消息拦截,下面我们看一下在HttpModule中的代码(我想应该是这样的,如果有误请指点。)
示例代码1-5
public class WebAPIHttpModule:IHttpModule
{ public void Dispose()
{
throw new NotImplementedException();
} public void Init(HttpApplication context)
{
context.PostResolveRequestCache += context_PostResolveRequestCache;
} void context_PostResolveRequestCache(object sender, EventArgs e)
{
HttpApplication context = sender as HttpApplication;
HttpContextWrapper contextWrapper = new HttpContextWrapper(context.Context);
RouteData routeData = RouteTable.Routes.GetRouteData(contextWrapper);
RequestContext requestContext=new RequestContext(contextWrapper,routeData);
IHttpHandler httpHandler = routeData.RouteHandler.GetHttpHandler(requestContext);
IHttpAsyncHandler httpAsyncHandler = httpHandler as IHttpAsyncHandler;
httpAsyncHandler.BeginProcessRequest(context.Context, null, null);
}
}
在代码1-5中我们可以看到首先是获取了RouteData对象实例,以此获取RouteHandler,然后根据RequestContext获取IHttpHandler,再转换为IHttpAsyncHandler类型的实例,然后调用其BeginProcessRequest()方法来执行操作。
上面这段话描述的是上述代码的执行过程,有的朋友可能会疑问了,怎么就获取RouteData了?
这里我给大家解释一下,在我们的代码1-2中,有这样的代码:
IHttpRoute route = routes.CreateRoute(routeTemplate, dictionary, dictionary2, dataTokens, handler2);
routes.Add(name, route);
首先我们看第一句,这里的route上面说过了是HostedHttpRoute对象,这里毫无疑问直接过,然后我们再看第二句,这里的routes是HostedHttpRouteCollection对象不假,但是这个Add()方法添加的方向不是HostedHttpRouteCollection,而是由我们一开始在GlobalConfiguration类型中说过的RouteTable.Routes,当前环境是什么?ASP.NET框架环境对吧!毫无疑问这个Add()方法把上面所说的route(HostedHttpRoute对象)添加到了当前环境的RouteTable.Routes中,有的朋友会问了类型不对。确实是不对的在添加的时候route(HostedHttpRoute对象)会转换成HttpWebRoute对象,HttpWebRoute对象继承自Route,可以看前面的篇幅,想必说到这里大家应该明白了。这里我就不多说了。
我们接着回到代码1-5中,在获取了RouteData之后通过RouteHandler的GetHttphandler()方法获取IHttpHandler实例,在RouteData中的这个RouteHandler毫无疑问就是HttpControllerRouteHandler类型。
我们来看下HttpControllerRouteHandler类型中的GetHttphandler()方法:
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new HttpControllerHandler(requestContext.RouteData);
}
可以看到是由HttpControllerHandler这个对象类型来执行最后的操作,那我们就来看一下这个类型的定义:
public class HttpControllerHandler : IHttpAsyncHandler, IHttpHandler
现在大家明白为什么要转成IHttpAsyncHandler了吧,因为如果调用了实现了IHttpHandler接口的函数是会报出异常的,因为在HttpControllerHandler类型中并没有实现IHttpHandler接口只是一个空壳,然后我们再看一下HttpControllerHandler类型的静态构造函数:
图1
这个_server是Lazy<HttpMessageInvoker>类型,在BeginProcessRequest()方法中会执行SendAsync()以此进入ASP.NET Web API的管道。
下面我们看一下整体的一个示意图,
图2
最后对于HttpControllerDispatcher类型在控制器部分讲解。
作者:金源
出处:http://www.cnblogs.com/jin-yuan/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面
ASP.NET Web API WebHost宿主环境中管道、路由的更多相关文章
- ASP.NET Web API Selfhost宿主环境中管道、路由
ASP.NET Web API Selfhost宿主环境中管道.路由 前言 前面的几个篇幅对Web API中的路由和管道进行了简单的介绍并没有详细的去说明一些什么,然而ASP.NET Web API这 ...
- 使用 OWIN 作为 ASP.NET Web API 的宿主
使用 OWIN 作为 ASP.NET Web API 的宿主 ASP.NET Web API 是一种框架,用于轻松构建可以访问多种客户端(包括浏览器和移动 设备)的 HTTP 服务. ASP.NET ...
- Global Error Handling in ASP.NET Web API 2(webapi2 中的全局异常处理)
目前,在Web API中没有简单的方法来记录或处理全局异常(webapi1中).一些未处理的异常可以通过exception filters进行处理,但是有许多情况exception filters无法 ...
- ASP.NET Web API实践系列05,消息处理管道
ASP.NET Web API的消息处理管道可以理解为请求到达Controller之前.Controller返回响应之后的处理机制.之所以需要了解消息处理管道,是因为我们可以借助它来实现对请求和响应的 ...
- 如何使用ASP.NET Web API OData在Oracle中使用Entity Framework 6.x Code-First方式开发 OData V4 Service
环境: Visual Studio 2013 + .Net Framework 4.5.2 1.新建项目 2.安装OData,ODP.NET 安装的包: 下面是部分代码: using System; ...
- ASP.NET Web API 管道模型
ASP.NET Web API 管道模型 前言 ASP.NET Web API是一个独立的框架,也有着自己的一套消息处理管道,不管是在WebHost宿主环境还是在SelfHost宿主环境请求和响应都是 ...
- ASP.NET Web API 路由对象介绍
ASP.NET Web API 路由对象介绍 前言 在ASP.NET.ASP.NET MVC和ASP.NET Web API这些框架中都会发现有路由的身影,它们的原理都差不多,只不过在不同的环境下作了 ...
- How ASP.NET Web API 2.0 Works?[持续更新中…]
一.概述 RESTful Web API [Web标准篇]RESTful Web API [设计篇] 在一个空ASP.NET Web项目上创建一个ASP.NET Web API 2.0应用 二.路由 ...
- ASP.NET Web API中的依赖注入
什么是依赖注入 依赖,就是一个对象需要的另一个对象,比如说,这是我们通常定义的一个用来处理数据访问的存储,让我们用一个例子来解释,首先,定义一个领域模型如下: namespace Pattern.DI ...
随机推荐
- LINUX篇,设置MYSQL远程访问实用版
每次设置root和远程访问都容易出现问题, 总结了个通用方法, 关键在于实用 step1: # mysql -u root mysql mysql> Grant all privileges o ...
- DBImport V3.7版本发布及软件稳定性(自动退出问题)解决过程分享
DBImport V3.7介绍: 1:先上图,再介绍亮点功能: 主要的升级功能为: 1:增加(Truncate Table)清表再插入功能: 清掉再插,可以保证两个库的数据一致,自己很喜欢这个功能. ...
- ABP文档 - 导航
文档目录 本节内容: 创建菜单 注册导航供应器 显示菜单 每个web应用都有一些菜单用来在页面/屏幕之间导航,ABP提供了一个通用的基础框架创建并显示菜单给用户. 创建菜单 一个应用可能由不同模块组成 ...
- Mysql事务探索及其在Django中的实践(一)
前言 很早就有想开始写博客的想法,一方面是对自己近期所学知识的一些总结.沉淀,方便以后对过去的知识进行梳理.追溯,一方面也希望能通过博客来认识更多相同技术圈的朋友.所幸近期通过了博客园的申请,那么今天 ...
- InnoDB体系结构学习笔记
后台线程 Master Thread 核心的后台线程,主要负责将缓冲池的数据异步刷新到磁盘,保证数据的一致性,包括(脏页的刷新).合并插入缓冲.(UNDO页的回收)等 IO Thread 4个writ ...
- 【初学python】使用python调用monkey测试
目前公司主要开发安卓平台的APP,平时测试经常需要使用monkey测试,所以尝试了下用python调用monkey,代码如下: import os apk = {'j': 'com.***.test1 ...
- NET Core-TagHelper实现分页标签
这里将要和大家分享的是学习总结使用TagHelper实现分页标签,之前分享过一篇使用HtmlHelper扩展了一个分页写法地址可以点击这里http://www.cnblogs.com/wangrudo ...
- 读python源码--对象模型
学python的人都知道,python中一切皆是对象,如class生成的对象是对象,class本身也是对象,int是对象,str是对象,dict是对象....所以,我很好奇,python是怎样实现这些 ...
- ASP.Net MVC——使用 ITextSharp 完美解决HTML转PDF(中文也可以)
前言: 最近在做老师交代的一个在线写实验报告的小项目中,有这么个需求:把学生提交的实验报告(HTML形式)直接转成PDF,方便下载和打印. 以前都是直接用rdlc报表实现的,可这次牵扯到图片,并且更为 ...
- Oracle使用触发器和mysql中使用触发器的比较——学习笔记
一.触发器 1.触发器在数据库里以独立的对象存储, 2.触发器不需要调用,它由一个事件来触发运行 3.触发器不能接收参数 --触发器的应用 举个例子:校内网.开心网.facebook,当你发一个日志, ...