細說ASP.NET Core與OWIN的關系


  前言

  最近這段時間除了工作,所有的時間都是在移植我以前實現的一個Owin框架,相當移植到到Core的話肯定會有很多坑,這個大家都懂,以后幾篇文章可能會圍繞這個說下,暫時就叫《Dotnet Core踩坑記》吧,呵呵。

  接下來我對我在移植過程中發現的一些問題進行了總結,今天主要說說Owin。說到Owin就不能不提Katana項目和宇內大神的Tinyfox了,當然關於這兩塊內容這篇文章就不多涉及了,博友可以自己在博客園內搜索關於Owin的文章還是挺多的。

  Owin

  ASP.NET vNext剛推出的時候,號稱是Owin的一個實現,在 http://owin.org 上,直到現在還保留着這樣一段描述。

  Implementations

  •     Katana
  •     Freya
  •     ASP.NET vNext

  很多開發者紛紛實現着自己的Owin框架,也寫很多應用到了實際的生產環境中,當然我也是其中一員。

  ASP.NET Core

  移植過程中,會發現有很多的不同,還有遇到新的API不知道怎么使用,這時候看文檔還不如直接看源碼來的痛快。

  在看完AspCore.Mvc后才發現,一點關於Owin的內容都沒有;但很明顯官方文檔上說是支持Owin協議的,后來我硬着頭皮去看了看KestrelHttpServerHttpAbstractions兩個項目,后來才發現原來真的沒有一點點的Owin協議內容啊(一定要給MS差評)。

  好吧,只能看看MS是怎么支持Owin的,在HttpAbstractions項目里發現了Microsoft.AspNetCore.Owin這樣一個子項目,看完只是想說:“你這意思這叫向下兼容?” ,算了。 現在只要在Asp.net core項目里加入依賴Microsoft.AspNet.Owin就可以IApplicationBuilder接口的擴展方法UseOwin進行Owin中間件的調用。如下:

  添加依賴:

 "dependencies": { "Microsoft.AspNet.Server.Kestrel": "1.0.0-*", "Microsoft.AspNet.Owin": "1.0.0-*" },

  在Startup中加入UseOwin:

 

1 public void Configure(IApplicationBuilder app) 2 { 3     app.UseOwin(pipeline =>
4  { 5         pipeline(next => OwinHello); 6  }); 7 }

 

  當然OwinHello的內容一定是一個標准Owin中間件的內容了:

 1 public Task OwinHello(IDictionary<string, object> environment)  2 {  3     string responseText = "Hello World via OWIN";  4     byte[] responseBytes = Encoding.UTF8.GetBytes(responseText);  5     var responseStream = (Stream)environment["owin.ResponseBody"];  6     var responseHeaders = (IDictionary<string, string[]>)environment["owin.ResponseHeaders"];  7     responseHeaders["Content-Length"] = new string[] { responseBytes.Length.ToString(CultureInfo.InvariantCulture) };  8     responseHeaders["Content-Type"] = new string[] { "text/plain" };  9     return responseStream.WriteAsync(responseBytes, 0, responseBytes.Length); 10 }

  Kestrel

  既然新的服務器已經不在支持Owin協議了,那個是怎么通信的?

  這個問題在ASP.NET Core管道深度剖析系列文章中被提到過一些,其實每一個HttpContext在被創建出來都會依賴一個IFeatureCollection集合。

  IFeatureCollection這個接口用於描述某個對象所具有的一組特征,由一組Feature接口組成。

  列出其中一個IHttpConnectionFeature接口,用於獲得Http的連接信息:

public class HttpConnectionFeature : IHttpConnectionFeature { public string ConnectionId { get; set; } public IPAddress LocalIpAddress { get; set; } public int LocalPort { get; set; } public IPAddress RemoteIpAddress { get; set; } public int RemotePort { get; set; } }

  閱讀kestrel源碼,發現每一次接受tcp連接,都會將Http流,封裝在一個幀Frame,它被描述成一個單向或雙向的request和response。 並組裝成特征集合供上層應用進行使用。

  最后

  最后就發一段Owin字典對應Feature的源碼吧:

 _entries = new Dictionary<string, FeatureMap>() { { OwinConstants.RequestProtocol, new FeatureMap<IHttpRequestFeature>(feature => feature.Protocol, () => string.Empty, (feature, value) => feature.Protocol = Convert.ToString(value)) }, { OwinConstants.RequestScheme, new FeatureMap<IHttpRequestFeature>(feature => feature.Scheme, () => string.Empty, (feature, value) => feature.Scheme = Convert.ToString(value)) }, { OwinConstants.RequestMethod, new FeatureMap<IHttpRequestFeature>(feature => feature.Method, () => string.Empty, (feature, value) => feature.Method = Convert.ToString(value)) }, { OwinConstants.RequestPathBase, new FeatureMap<IHttpRequestFeature>(feature => feature.PathBase, () => string.Empty, (feature, value) => feature.PathBase = Convert.ToString(value)) }, { OwinConstants.RequestPath, new FeatureMap<IHttpRequestFeature>(feature => feature.Path, () => string.Empty, (feature, value) => feature.Path = Convert.ToString(value)) }, { OwinConstants.RequestQueryString, new FeatureMap<IHttpRequestFeature>(feature => Utilities.RemoveQuestionMark(feature.QueryString), () => string.Empty, (feature, value) => feature.QueryString = Utilities.AddQuestionMark(Convert.ToString(value))) }, { OwinConstants.RequestHeaders, new FeatureMap<IHttpRequestFeature>(feature => Utilities.MakeDictionaryStringArray(feature.Headers), (feature, value) => feature.Headers = Utilities.MakeHeaderDictionary((IDictionary<string, string[]>)value)) }, { OwinConstants.RequestBody, new FeatureMap<IHttpRequestFeature>(feature => feature.Body, () => Stream.Null, (feature, value) => feature.Body = (Stream)value) }, { OwinConstants.RequestUser, new FeatureMap<IHttpAuthenticationFeature>(feature => feature.User, () => null, (feature, value) => feature.User = (ClaimsPrincipal)value) }, { OwinConstants.ResponseStatusCode, new FeatureMap<IHttpResponseFeature>(feature => feature.StatusCode, () => 200, (feature, value) => feature.StatusCode = Convert.ToInt32(value)) }, { OwinConstants.ResponseReasonPhrase, new FeatureMap<IHttpResponseFeature>(feature => feature.ReasonPhrase, (feature, value) => feature.ReasonPhrase = Convert.ToString(value)) }, { OwinConstants.ResponseHeaders, new FeatureMap<IHttpResponseFeature>(feature => Utilities.MakeDictionaryStringArray(feature.Headers), (feature, value) => feature.Headers = Utilities.MakeHeaderDictionary((IDictionary<string, string[]>)value)) }, { OwinConstants.ResponseBody, new FeatureMap<IHttpResponseFeature>(feature => feature.Body, () => Stream.Null, (feature, value) => feature.Body = (Stream)value) },

  只能說還好,性能並沒有太多的損耗,粘的不全,全的自己看吧 : ) 

  當然MS這樣做也是有用意義的,他們不太喜歡字典的方式,於是用Feature這種方式將這些內容,"強類型化了"。這對於底層的Server來說,很快能基於這組特征二次開發出一套中間件來支持ASP.NET Core,當然直接在Server內實現這樣性能也會更高。

  只能說API變化有點快吧,但是對於開源,看幾天源碼就全明白了,這對於我們dotnet開發者來說,真是大大的好事兒。

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM