您好,登錄后才能下訂單哦!
適配器模式(Adapter)
可用來在現有接口和不兼容的類之間進行適配。有助于避免大規模改寫現有客戶代碼,其工作機制是對現有類的接口進行包裝,這樣客戶程序就能使用這個并非為其量身打造的類而又無需為此大動手術。 ----《JS設計模式》
將一個類的接口,轉換成客戶期望的另一個接口。適配器讓原本接口不兼容的類可以合作無間。
----《Head First設計模式》
這兩本書中對適配器模式定義如此,適配器模式在多種設計模式當中屬于比較容易理解的一種,其目的或者說可以解決的問題是新功能/新類型,不受原有類型/方法/功能的兼容,有了適配器這種巧妙地經驗,我們可以保證對修改封閉,對拓展開放。而達到此目的,正需要面向接口,并保持職責的單一性。也許對C#開發者來說,見的最多的就是SqlDataAdapter。
本文所涉及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 }
看到這里你一定會問,為什么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對象。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。