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宿主环境中管道、路由的更多相关文章

  1. ASP.NET Web API Selfhost宿主环境中管道、路由

    ASP.NET Web API Selfhost宿主环境中管道.路由 前言 前面的几个篇幅对Web API中的路由和管道进行了简单的介绍并没有详细的去说明一些什么,然而ASP.NET Web API这 ...

  2. 使用 OWIN 作为 ASP.NET Web API 的宿主

    使用 OWIN 作为 ASP.NET Web API 的宿主 ASP.NET Web API 是一种框架,用于轻松构建可以访问多种客户端(包括浏览器和移动 设备)的 HTTP 服务. ASP.NET ...

  3. Global Error Handling in ASP.NET Web API 2(webapi2 中的全局异常处理)

    目前,在Web API中没有简单的方法来记录或处理全局异常(webapi1中).一些未处理的异常可以通过exception filters进行处理,但是有许多情况exception filters无法 ...

  4. ASP.NET Web API实践系列05,消息处理管道

    ASP.NET Web API的消息处理管道可以理解为请求到达Controller之前.Controller返回响应之后的处理机制.之所以需要了解消息处理管道,是因为我们可以借助它来实现对请求和响应的 ...

  5. 如何使用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; ...

  6. ASP.NET Web API 管道模型

    ASP.NET Web API 管道模型 前言 ASP.NET Web API是一个独立的框架,也有着自己的一套消息处理管道,不管是在WebHost宿主环境还是在SelfHost宿主环境请求和响应都是 ...

  7. ASP.NET Web API 路由对象介绍

    ASP.NET Web API 路由对象介绍 前言 在ASP.NET.ASP.NET MVC和ASP.NET Web API这些框架中都会发现有路由的身影,它们的原理都差不多,只不过在不同的环境下作了 ...

  8. How ASP.NET Web API 2.0 Works?[持续更新中…]

    一.概述 RESTful Web API [Web标准篇]RESTful Web API [设计篇] 在一个空ASP.NET Web项目上创建一个ASP.NET Web API 2.0应用 二.路由 ...

  9. ASP.NET Web API中的依赖注入

    什么是依赖注入 依赖,就是一个对象需要的另一个对象,比如说,这是我们通常定义的一个用来处理数据访问的存储,让我们用一个例子来解释,首先,定义一个领域模型如下: namespace Pattern.DI ...

随机推荐

  1. EntityFramework Core Raw SQL

    前言 本节我们来讲讲EF Core中的原始查询,目前在项目中对于简单的查询直接通过EF就可以解决,但是涉及到多表查询时为了一步到位就采用了原始查询的方式进行.下面我们一起来看看. EntityFram ...

  2. 移动端之Android开发的几种方式的初步体验

    目前越来越多的移动端混合开发方式,下面列举的大多数我都略微的尝试过,就初步的认识写个简单的心得: 开发方式 开发环境 是否需要AndroidSDK 支持跨平台 开发语言&技能 MUI Win+ ...

  3. [高并发]Java高并发编程系列开山篇--线程实现

    Java是最早开始有并发的语言之一,再过去传统多任务的模式下,人们发现很难解决一些更为复杂的问题,这个时候我们就有了并发. 引用 多线程比多任务更加有挑战.多线程是在同一个程序内部并行执行,因此会对相 ...

  4. 聊聊Unity项目管理的那些事:Git-flow和Unity

    0x00 前言 目前所在的团队实行敏捷开发已经有了一段时间了.敏捷开发中重要的一个话题便是如何对项目进行恰当的版本管理.项目从最初使用svn到之后的Git One Track策略再到现在的GitFlo ...

  5. javascript动画系列第三篇——碰撞检测

    前面的话 前面分别介绍了拖拽模拟和磁性吸附,当可视区域内存在多个可拖拽元素,就出现碰撞检测的问题,这也是javascript动画的一个经典问题.本篇将详细介绍碰撞检测 原理介绍 碰撞检测的方法有很多, ...

  6. C#4.0泛型的协变,逆变深入剖析

    C#4.0中有一个新特性:协变与逆变.可能很多人在开发过程中不常用到,但是深入的了解他们,肯定是有好处的. 协变和逆变体现在泛型的接口和委托上面,也就是对泛型参数的声明,可以声明为协变,或者逆变.什么 ...

  7. mysql 学习总结

    MYSQL的增.删.查.改   注册.授权 #创建一个对数据库中的表有一些操作权限的用户,其中OPERATION可以用all privileges替换,DBNAME.TABLENAME可以用*替换,表 ...

  8. 【NLP】揭秘马尔可夫模型神秘面纱系列文章(一)

    初识马尔可夫和马尔可夫链 作者:白宁超 2016年7月10日20:34:20 摘要:最早接触马尔可夫模型的定义源于吴军先生<数学之美>一书,起初觉得深奥难懂且无什么用场.直到学习自然语言处 ...

  9. 微信小程序IDE(微信web开发者工具)安装、破解手册

    1.IDE下载 微信web开发者工具,本人是用的windows 10 x64系统,用到以下两个版本的IDE安装工具与一个破解工具包: wechat_web_devtools_0.7.0_x64.exe ...

  10. 关于SMARTFORMS文本编辑器出错

    最近在做ISH的一个打印功能,SMARTFORM的需求本身很简单,但做起来则一波三折. 使用环境是这样的:Windows 7 64bit + SAP GUI 740 Patch 5 + MS Offi ...