我们在开发完Asp.Net WebAPI程序后,可以使用WebHost寄宿方式或者SelfHost寄宿方式来部署Asp.Net WebAPI。所谓WebHost寄宿就是通过Asp.Net来实现;所谓SelfHost就是可以通过控制台、WinForm、WPF等方式寄宿。下面我们通过简单的例子来看看WebHost方式和SelfHost方式。
该Demo中包含一个类库项目、一个控制台项目以及一个空的WebForm项目。其中类库项目有一个继承自ApiController的名为HomeController的类;控制台项目实现SelfHost;WebForm项目实现WebHost:
WebAPI代码:
public class HomeController : ApiController { public string Get(string fromStr) { return $"The request is from {fromStr}"; } }
WebHost寄宿方式:
WebHost项目的Global文件代码:
public class Global : System.Web.HttpApplication { protected void Application_Start(object sender, EventArgs e) { GlobalConfiguration.Configuration.Routes.MapHttpRoute(name: "default", routeTemplate: "api/{controller}/{fromStr}"); } }
启动运行WebHost项目,浏览器输入地址http://localhost:34827/api/home/webhost:
SelfHost寄宿方式:
SelfHost项目中的Program文件代码:
static void Main(string[] args) { Assembly.Load("WebAPI,Version=1.0.0.1,Culture=neutral,PublicKeyToken=null"); HttpSelfHostConfiguration configuration = new HttpSelfHostConfiguration("http://localhost:34827/"); using (HttpSelfHostServer server = new HttpSelfHostServer(configuration)) { server.Configuration.Routes.MapHttpRoute(name: "default", routeTemplate: "api/{controller}/{fromStr}"); server.OpenAsync(); Console.Read(); } }
启动运行SelfHost项目,浏览器输入地址http://localhost:34827/api/home/from_selfhost:
从上面的例子可以看到Asp.Net WebAPI可以有多重寄宿方式,而Asp.Net WebAPI可以实现多种寄宿方式的原因在于:Asp.Net WebAPI有一个独立于寄宿环境的抽象管道,这个抽象管道是Asp.Net WebAPI的消息处理管道。
下面正式进入今天的主题:Asp.Net WebAPI消息处理管道。Asp.Net WebAPI的消息处理管道是一组HttpMessageHandler的有序组合。在这个消息处理管道中,除了最后一个HttpMessageHandler外,其他的都是由DelegatingHandler这个类型组成的委托链,最后一个HttpMessageHandler是最终处理请求(查找Controller、执行Action)的地方。下面我们通过翻看源码来看看组成消息处理管道的这个有序组合都是哪些类型:
在了解完组成Asp.NetWebAPI消息处理管道的类型后,我们通过一个例子来看看是怎么组成的。我们改一下前面的例子,在WebAPI项目中添加两个自定义的HttpMessageHandler和自定义的HttpServer作为“龙头”:
public class MyHttpMessageHanlder1 : DelegatingHandler { } public class MyHttpMessageHanlder2 : DelegatingHandler { } public class MyHttpServer:HttpServer { public MyHttpServer(HttpConfiguration configuration):base(configuration) { } public new void Initialize() { base.Initialize(); } }
修改HomeController的代码:
public class HomeController : ApiController { public Tuple<IEnumerable<string>, IEnumerable<string>> Get(string fromStr) { HttpConfiguration configuration = new HttpConfiguration(); configuration.MessageHandlers.Add(new MyHttpMessageHanlder1()); configuration.MessageHandlers.Add(new MyHttpMessageHanlder1()); MyHttpServer server = new MyHttpServer(configuration); IEnumerable<string> handler1 = GetHandlers(server).ToArray(); server.Initialize(); IEnumerable<string> handler2 = GetHandlers(server).ToArray(); return new Tuple<IEnumerable<string>, IEnumerable<string>>(handler1, handler2); } private IEnumerable<string> GetHandlers(DelegatingHandler handler) { yield return handler.GetType().Name; while (handler.InnerHandler != null) { yield return handler.InnerHandler.GetType().Name; handler = handler.InnerHandler as DelegatingHandler; if (handler == null) break; } } }
运行程序后输入地址http://localhost:34827/api/home/from:
由上面的例子,我们验证了HttpServer为消息处理管道的“龙头”,HttpRoutingDispatcher为管道的“龙尾”,我们自定义的委托链接点是保存在HttpConfiguration类型的MessageHanlers属性中,在HttpServer调用Initialize方法时把MessageHandlers中的委托链节点和“龙头”、“龙尾”组成一个消息处理管道委托链。
通过上面的实例我们知道了组成Asp.Net WebAPI消息处理管道的类型和验证了Asp.Net WebAPI消息处理管道的创建,下面我们继续看看作为消息处理管道的“龙头”和“龙尾”内部都做了些什么。
当请求流转到消息处理管道的最后一个节点时,通过源码,如下,我们可以看到在最后的节点中完成的动作是:根据RouteData找到对应的Controller和Action,然后执行Action,将得到的响应数据逆序流转到“龙头”HttpServer中,在有HttpServer返回给客户端。
总结:
通过前面的剖析,我们知道Asp.Net WebAPI有多种寄宿方式,是因为它有一个独立于寄宿环境的消息处理管道,然后我们也对组成Asp.Net WebAPI消息处理管道的各种类型进行了剖析,并从中发现了消息处理管道是如何创建、请求是如何在管道中流转以及各个管道的作用。
至此,我们对Asp.Net WebAPI消息处理管道进行了一个简单的剖析,由于个人能力有限,如有不对,欢迎指正。