The relationship between ASP. NET Core and OWIN, asp. netowin
Preface
In addition to work, all the time has been porting an Owin framework that I previously implemented. If it is migrated to Core, there will certainly be many pitfalls. Everyone understands this, in the next few articles, we may refer to Dotnet Core as a pitfall for the time being.
Next, I will summarize some of the problems I found during the porting process. Today I will focus on Owin. When talking about Owin, we can't help but mention the Katana project and Tinyfox of the great god of the universe. Of course, this article will not cover these two topics, you can search for many articles about Owin in your blog.
Owin
ASP. NET vNext was just launched, known as an implementation of Owin, In the http://owin.org, until now still keep such a description.
Implementations
- Katana
- Freya
- ASP.NET vNext
Many developers have implemented their own Owin frameworks and have written many applications into the actual production environment. Of course, I am also a member of them.
ASP. NET Core
During the porting process, we will find that there are many differences and new APIs do not know how to use them. At this time, it is better to view the source code directly.
After reading the AspCore. after Mvc, I found that I didn't have any content about Owin. But it is obvious that the official document says it supports the Owin protocol. Later, I looked at the KestrelHttpServer and httpjavasactions projects, later, I found that there was really no such thing as the Owin protocol (MS must be negative ).
Well, we can only look at how MS supports Owin. Microsoft was found in the http?actions project. aspNetCore. after reading a sub-project such as Owin, I just want to say, "What do you mean is backward compatibility?" , Forget it. Now, you only need to add Microsoft. AspNet. Owin dependency to the Asp.net core project, and you can call the Owin middleware by using the extended method UseOwin of the IApplicationBuilder interface. As follows:
Add dependency:
"dependencies": { "Microsoft.AspNet.Server.Kestrel": "1.0.0-*", "Microsoft.AspNet.Owin": "1.0.0-*" },
Add UseOwin to Startup:
1 public void Configure(IApplicationBuilder app)2 {3 app.UseOwin(pipeline =>4 {5 pipeline(next => OwinHello);6 });7 }
Of course, the content of OwinHello must be the content of a standard Owin middleware:
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
Since the new server no longer supports the Owin protocol, how does it communicate?
This issue has been mentioned in the ASP. NET Core pipeline deep analysis series. In fact, every HttpContext created depends on an IFeatureCollection set.
IFeatureCollection interface is used to describe a set of features of an object, which is composed of a set of Feature interfaces.
Lists one of the IHttpConnectionFeature interfaces to obtain the Http connection information:
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; }}
Read the kestrel source code and find that every time a tcp connection is accepted, the Http stream is encapsulated in a Frame, which is described as a one-way or two-way request and response. And assembled into a feature set for upper-layer applications to use.
Last
Finally, let's send the source code of the Feature corresponding to the Owin dictionary:
_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) },
It can only be said that it is okay. The performance does not have much loss, and the viscosity is incomplete. You can see it for yourself :)
Of course, MS is also useful. They do not like the dictionary method, so they use Feature to "strongly typed" the content ". This allows the underlying Server to quickly develop a set of middleware to support ASP. NET Core based on this set of features. Of course, the performance will be higher directly within the Server.
It can only be said that API changes are a little quick, but for open source, the source code will be completely clear after several days. This is a great thing for our dotnet developers.