浅从System.Web.Http.Owin的HttpMessageHandlerAdapter看适配器模式

一.写在前面

适配器模式(Adapter)

可用来在现有接口和不兼容的类之间进行适配。有助于避免大规模改写现有客户代码,其工作机制是对现有类的接口进行包装,这样客户程序就能使用这个并非为其量身打造的类而又无需为此大动手术。                  ----《JS设计模式》

将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。

                       ----《Head First设计模式》

这两本书中对适配器模式定义如此,适配器模式在多种设计模式当中属于比较容易理解的一种,其目的或者说可以解决的问题是新功能/新类型,不受原有类型/方法/功能的兼容,有了适配器这种巧妙地经验,我们可以保证对修改封闭,对拓展开放。而达到此目的,正需要面向接口,并保持职责的单一性。也许对C#开发者来说,见的最多的就是SqlDataAdapter。

                  

二.认识UseWebApi

本文所涉及OWIN,.NetFramework,Webapi 开源源码下载地址为:

ht t p s : / /g i t h u b. c o m / as p n e t/ A s p N et K a ta n a

htt p s: / / g i th u b. c o m / AS P - N E T- M V C /a s p n e tw e b s t a ck

h t t p s : / /g i t h u b . c om / d o t ne t / c or e f x

熟悉OWIN体系的小伙伴们,一定都在Startup.cs中见过也使用过app.UseWebApi吧。app是IAppBuilder的对象

Startup.cs是OWIN katana实现的启动类,刚说的UseWebApi顾名思义,就是将WebApi作为一个OWIN中间件放在整个处理流程中。app是IAppBuilder的对象,其创建由IAppBuilderFactory负责。IAppBuilder定义了三个方法,分别为Build,New和Use.   这三个方法分别负责什么呢?

Build,返回OWIN管道入口点的一个实例,由 Microsoft.Owin.Host.SystemWeb中的Init方法调用。其返回实例将被转换为AppFun类型,AppFun( using AppFunc = Func<IDictionary<string, object>, Task>;)是什么呢?它是OWIN服务器与应用程序交互的应用程序委托,我们看到这个方法在OWIN.Host中调用,应该就能大概猜到个所以然。

New,用于返回一个AppBuilder实例,由IAppBuilderFactory调用并返回。

Use,就是我们在OWIN体系中,经常使用到的方法,我们可以定义自己的OWIN中间件,按照其定义规范,并Use到处理管道中,比如用户操作日志中间件,用户身份校验中间件等。

说到这里,我们应该很清晰的了解到WebApi是OWIN的一个中间件而已了吧。举个栗子:

 1 public partial class Startup 2     { 3  4         public void Configuration(IAppBuilder app) 5         { 6             // This must happen FIRST otherwise CORS will not work. 
 7             // 引入OWin.Cors 解决跨域访问问题 8             app.UseCors(CorsOptions.AllowAll); 9 10             GlobalConfiguration.Configure(WebApiConfig.Register);11             FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);12             13             ConfigureAuth(app);14 15             app.Use<UserContextMiddleware>();16             app.Use<UserOperationMiddleware>();17             app.UseWebApi(GlobalConfiguration.Configuration);18         }19     }

三.UseWebApi的实现

看到这里你一定会问,为什么IAppBuilder中没有定义UseWebapi方法呢,UseWebapi的实现在System.Web.Http.Owin的WebApiAppBuilderExtensions.cs中,UseWebApi是一个C# this拓展方法,和你所想到的答案并无差。在其实现中,调用了  builder.Use(typeof(HttpMessageHandlerAdapter), options);

到这里,一定要啰嗦几句不要怪我,Adapter的实现步骤:为了使一个类或者一个功能,兼容已有类/接口,那么

1.被适配器实现目标客户的接口或抽象方法,以便参数的传入

2.所实现接口/抽象类的方法中调用目标客户的方法

HttpMessageHandlerAdapter 这个主角终于出现了,对Adapter模式了解后的小伙伴们也一定能想得到,既然是HttpMessageHandler的Adapter,那么 在其类中 一定定义了一个private的字段,并且类型为HttpMessageHandler,你也一定能想得到这个Adapter继承了OwinMiddleware这个抽象类型并且实现其Invoke抽象方法,在HttpMessageHandlerAdapter的一个方法中一定调用了HttpMessageHandler的方法。那么通过源码我们了解到HttpMessageHandler的字段名为_messageHandler。(是不是和上面所说的Adapter实现方式类似呢,实现方式可能概括的不好,建议参阅更多文章和范例)

Asp.Net Webapi的消息处理管道是由HttpMessageHandler的委托链所组成的处理管道

HttpMessageHandler抽象类当中顶一个一个唯一的抽象方法用于实现,其入参为HttpRequestMessage,其出参为HttpResponseMessage。

1 protected internal abstract Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);

DelegatingHandler实现了HttpMessageHandler,其构造函数中传入HttpMessageHandler,并由同类对象innerHandler构成委托链。

推荐一篇MS文档 https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/http-message-handlers,有兴趣可以稍微参照下。

 1         protected DelegatingHandler(HttpMessageHandler innerHandler) 2         { 3             InnerHandler = innerHandler; 4         } 5  6         protected internal override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 7         { 8             if (request == null) 9             {10                 throw new ArgumentNullException(nameof(request), SR.net_http_handler_norequest);11             }12             SetOperationStarted();13             return _innerHandler.SendAsync(request, cancellationToken);14         }

中间啰嗦了一串,为了说明HttpMessageHandler的作用,这样我们能进一步理解,为什么要有HttpMessageHandlerAdapter的存在,并在Use (WebApi中间件)的时候,将该类型传入。

在HttpMessageHandlerAdapter构造函数中,_messageHandler被包装为HttpMessageInvoker类型,这个类型的目的是提供一个专门的类,用于调用SendAsync方法。

刚才我们已经了解到HttpMessageHandlerAdapter实现了OWinMiddleware, 那么我们从源码中了解下,在其实现的抽象方法Invoke中,做了什么事情:其调用同类下的InvokeCore方法,InvokeCore中Create了HttpRequestMessage,并将其对象作为SendAsync的入参,最后得到HttpResponseMessage对象。

时间: 2024-11-01 06:38:05

浅从System.Web.Http.Owin的HttpMessageHandlerAdapter看适配器模式的相关文章

从System.Web.Http.Owin的HttpMessageHandlerAdapter看适配器模式

.mytitle { background: #2B6695; color: white; font-family: "微软雅黑", "宋体", "黑体", Arial; font-size: 18px; font-weight: bold; height: 25px; line-height: 25px; margin: 15px 0 !important; padding: 5px 0 5px 20px; width: 97% } .arti

配置错误定义了重复的“system.web.extensions/scripting/scriptResourceHandler” 解决办法

今天遇到了这个问题, 电脑系统:vs2010 win7系统 iis7 我运行在iis中配置的那个网站后,报错:错误代码 0x800700b7 配置错误定义了重复的"system.web.extensions/scripting/scriptResourceHandler"节 这个问题原因在于window7的IIS默认用的是ASP.NET v4.0应用程序池. 解决方法:把这个网站的应用程序池的.netframework版本改为 v2.0的,如图: 1:选中应用程序池-->在右侧右

System.Web.Mvc 和 using System.Net.Http 的 Filter

在尝试给webapi增加 ExceptionFilter时,出现了错误,经查询区别如下: System.Web.Mvc.Filters 是给mvc用的 System.Web.Http.Filters 是给webapi用的. MVC用的Filter在如下代码里增加新的filter: using System.Web; using System.Web.Mvc; namespace API { public class FilterConfig { public static void Regist

[转] ASP.NET WEB API程序在VS启动或发布到IIS后启动后发生 - Could not load file or assembly &#39;System.Web.Http.WebHost’异常,无法正常访问

Just do Copy Local = true in the properties for the assembly(System.Web.Http.WebHost) and then do a redeploy, it should work fine. http://stackoverflow.com/questions/20323107/could-not-load-file-or-assembly-system-web-http-webhost-after-published-to-

System.Web.HttpCompileException (0x80004005): (0): error CS0016: 未能写入输出文件

重新系统后,iis asp.net站点老是出现: System.Web.HttpCompileException (0x80004005): (0): error CS0016: 未能写入输出文件“c:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\8a066f10\5b61ede0\App_Web_index.aspx.cdcab7d2.m4fr5omv.dll”--“拒绝访问. ” 第一感觉

&quot;命名空间&quot;system.web&quot;中不存在类型或命名空间名称security&quot;错误解决方法

using System; using System.Collections.Generic; using System.Text; using System.Web; namespace 求md5 { class Program { static void Main(string[] args) { string str = GetMd5("xuwei"); Console.WriteLine(str); } public static string GetMd5(string st

System.Web.Mvc 3.0.0.1 和 3.0.0.0 有什么区别?被 Microsoft ASP.NET MVC 的一次安全更新害惨了!!!

今天更新站点时,发现网站竟然报错 ... uses 'System.Web.Mvc, Version=3.0.0.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35' which has a higher version than referenced assembly 'System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' 最终发现

System.Web.Optimization找不到引用

在MVC4的开发中,如果创建的项目为空MVC项目,那么在App_Start目录下没有BundleConfig.cs项的内容,在手动添加时在整个库中都找不到:System.Web.Optimization命名空间.如下图所示, 那么如何找到System.Web.Optimization命名空间,完成BundleConfig.cs内容的添加.方法如下:打开程序包管理控制台,在控制台中输入: Install-Package Microsoft.AspNet.Web.Optimization按回车.在控

【解决】System.Web.Http.Description 缺失

一.问题描述 使用visual studio 2013创建mvc4 api模板,然后build,run,broken,出错如下: Error 1 The type or namespace name 'Description' does not exist in the namespace 'System.Web.Http' (are you missing an assembly reference?) 二.分析 System.Web.Http.Description 缺失 三.解决 右键项目