在Web API的中,微软为了更好的进行架构扩展,采用的了一套管道设计----HttpMessageHander(其实WCF也有类似架构).
在整个管道中的头与尾分别是HttpServer、HttpRoutingDispatcher,它们都继承HttpMessageHandler,其中ASP.NET 为我们预留了可扩展的DelegatingHandler,下面我们就来看看几个类之前的关系。
SendAsync为处理请求的方法。在DelegatingHandler中有一类型为HttpMessageHandler的属性InnerHandler。它是构成管道的关键。因为有了这个属性所以的DelegatingHandler都能够串联起来,逐步去经过管道中的每个DelegatingHandler
在HttpServer有两个新添加的属性Configuration与Dispatcher,其中Dispatcher指向管道的尾HttpRoutingDispatcher.在HttpConfiguration有一类型为Collection< DelegatingHandler>的属性MessageHandlers,我们这个集合中添加自定义的DelegatingHandler就可以添加到整个管道中。所以我们可以看出HttpServer中基本已经定义的整个HttpMessagHandler管道。
下面我们定义一个可以进行请求方式Post与Put(当然这只是个例子)
public class HttpMethodChangeHandler : DelegatingHandler { protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { var method = request.Method; if(request.Method == HttpMethod.Post) { request.Method = HttpMethod.Put; } else if(request.Method == HttpMethod.Put) { request.Method = HttpMethod.Post; } return base.SendAsync(request, cancellationToken); } }
我们在HttpApplication.Application_Start中加添加如下语句
GlobalConfiguration.Configure(t => t.MessageHandlers.Add(new HttpMethodChangeHandler()));
在DemoController中定义了Put,Post方法
[HttpPost] public string Post() { return "这是一个Post方法"; } [HttpPut] public string Put() { return "这是一个Put方法"; }
下面是这四种测试结果:
url:http://localhost:41666/api/Demo/Put Method:Post
结果:"这是一个Put方法"
url: http://localhost:41666/api/Demo/Put Method:Put
结果:{"Message":"请求的资源不支持 http 方法"POST"。"}
url:http://localhost:41666/api/Demo/Post Method:Put
结果:"这是一个Post方法"
url: http://localhost:41666/api/Demo/Post Method:Post
结果:{"Message":"请求的资源不支持 http 方法"PUT"。"}
另外我们再在DemoController定义一个获取自定义DelegatingHandler的方法GetChains
public IEnumerable<string> GetChains() { IEnumerable<string> result = GetChains(GlobalConfiguration.DefaultServer); return result; } private IEnumerable<string> GetChains(DelegatingHandler handler) { yield return handler.GetType().FullName; var innerHander = handler.InnerHandler as DelegatingHandler; if (innerHander != null) { yield return innerHander.GetType().FullName; } }
Github: https://github.com/BarlowDu/WebAPI (API_6)