Open Web Interface for .NET (OWIN)

Original author: Steve Smith and Rick Anderson
  • Transfer
Hello, Habr! ASP.NET Core supports the open web interface for .NET (OWIN), and OWIN allows you to untie web applications from web servers. It defines a standard way to use middleware in processing requests and corresponding responses. ASP.NET Core applications and middleware are compatible with OWIN-based applications, servers, and middleware. Read more about this pair under the cut.



View or download sample code

Executing middleware in an ASP.NET process


OWIN support from ASP.NET Core is deployed as part of the package Microsoft.AspNetCore.Owin. To import OWIN support into your project, add the package as a dependency to the file project.json:

"dependencies": {
  "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
  "Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
  "Microsoft.AspNetCore.Owin": "1.0.0"
},

OWIN middleware complies with the OWIN specification , which requires an interface and the configuration of certain keys (for example, ). The following is an example of OWIN middleware that displays Hello World text:Func, Task>owin.ResponseBody

public Task OwinHello(IDictionary environment)
{
    string responseText = "Hello World via OWIN";
    byte[] responseBytes = Encoding.UTF8.GetBytes(responseText);
    // OWIN Environment Keys: http://owin.org/spec/spec/owin-1.0.0.html
    var responseStream = (Stream)environment["owin.ResponseBody"];
    var responseHeaders = (IDictionary)environment["owin.ResponseHeaders"];
    responseHeaders["Content-Length"] = new string[] { responseBytes.Length.ToString(CultureInfo.InvariantCulture) };
    responseHeaders["Content-Type"] = new string[] { "text/plain" };
    return responseStream.WriteAsync(responseBytes, 0, responseBytes.Length);
}

A signature sample is issued Task and accepted in accordance with OWIN requirements. The following code shows how to add middleware (see above) to an ASP.NET process using the extension method .IDictionary

OwinHelloUseOwin

public void Configure(IApplicationBuilder app)
{
    app.UseOwin(pipeline =>
    {
        pipeline(next => OwinHello);
    });
}

You can configure other actions for the OWIN process.

The response headers should only be changed before the first entry into the response stream.

No need to make many calls to UseOwin: this reduces performance. OWIN components work better when combined.

app.UseOwin(pipeline =>
{
    pipeline(next =>
    {
        // do something before
        return OwinHello;
        // do something after
    });
});

ASP.NET hosting on an OWIN server


OWIN servers can host ASP.NET applications. One such server is Nowin, the .NET OWIN web server. As an example for this article, we added a project that references Nowin and uses it to create one IServerthat can host ASP.NET Core on its own.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
namespace NowinSample
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = new WebHostBuilder()
                .UseNowin()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup()
                .Build();
            host.Run();
        }
    }
}

IServerIs an interface that requires a property Featuresand method Start.

Startresponsible for setting up and starting the server. To do this, use a series of API calls that configure the addresses that were parsed from IServerAddressesFeature. Note: the configuration of the variable _builderindicates that the request will be processed by the parameter appFuncpreviously configured in the method. This function is called for each request to process incoming requests.

We will also add an extension IWebHostBuilderto simplify the addition and configuration of the Nowin server.

using System;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.Extensions.DependencyInjection;
using Nowin;
using NowinSample;
namespace Microsoft.AspNetCore.Hosting
{
    public static class NowinWebHostBuilderExtensions
    {
        public static IWebHostBuilder UseNowin(this IWebHostBuilder builder)
        {
            return builder.ConfigureServices(services =>
            {
                services.AddSingleton();
            });
        }
        public static IWebHostBuilder UseNowin(this IWebHostBuilder builder, Action configure)
        {
            builder.ConfigureServices(services =>
            {
                services.Configure(configure);
            });
            return builder.UseNowin();
        }
    }
}

Then you need to call the extension in Program.cs to run the ASP.NET application using this user server:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
namespace NowinSample
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = new WebHostBuilder()
                .UseNowin()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup()
                .Build();
            host.Run();
        }
    }
}

Learn more about ASP.NET servers .

Run ASP.NET Core on the OWIN server and use WebSockets support


Another way to use OWIN servers in ASP.NET Core is to access features like WebSockets. The .NET OWIN web server from the previous example supports embedded web sockets that can be used in an ASP.NET Core application. The example below shows a simple web application that supports web sockets and returns to the sender all the data sent to servers via web sockets.

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.Use(async (context, next) =>
        {
            if (context.WebSockets.IsWebSocketRequest)
            {
                WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
                await EchoWebSocket(webSocket);
            }
            else
            {
                await next();
            }
        });
        app.Run(context =>
        {
            return context.Response.WriteAsync("Hello World");
        });
    }
    private async Task EchoWebSocket(WebSocket webSocket)
    {
        byte[] buffer = new byte[1024];
        WebSocketReceiveResult received = await webSocket.ReceiveAsync(
            new ArraySegment(buffer), CancellationToken.None);
        while (!webSocket.CloseStatus.HasValue)
        {
            // Echo anything we receive
            await webSocket.SendAsync(new ArraySegment(buffer, 0, received.Count), 
                received.MessageType, received.EndOfMessage, CancellationToken.None);
            received = await webSocket.ReceiveAsync(new ArraySegment(buffer), 
                CancellationToken.None);
        }
        await webSocket.CloseAsync(webSocket.CloseStatus.Value, 
            webSocket.CloseStatusDescription, CancellationToken.None);
    }
}

This pattern is configured using the same NowinServeras the previous one; the only difference is the way the application is configured in the method Configure. The test using a simple web socket client demonstrates the application:



OWIN Environment


You can create an OWIN environment with HttpContext.

var environment = new OwinEnvironment(HttpContext);
   var features = new OwinFeatureCollection(environment);

OWIN keys


An OWIN HTTP request / response is required to transmit information through data exchange . ASP.NET Core implements the keys listed below. See the basic specification , extensions, and OWIN General Rules.IDictionary

Data Request (OWIN v1.0.0)

KeyValue (type)Description
owin.RequestSchemeLine
owin.RequestMethodLine
owin.RequestPathBaseLine
owin.RequestPathLine
owin.RequestQueryStringLine
owin.RequestProtocolLine
owin.RequestHeadersIDictionary
owin.RequestBodyFlow

Data Request (OWIN v1.1.0)

KeyValue (type)Description
owin.RequestIdLineNot necessary

Response Data (OWIN v1.0.0)

KeyValue (type)Description
owin.ResponseStatusCodeintNot necessary
owin.ResponseReasonPhraseLineNot necessary
owin.ResponseHeadersIDictionary
owin.ResponseBodyFlow

Other data (OWIN v1.0.0)

KeyValue (type)Description
owin.CallCancelledCancellationToken
owin.VersionLine

Shared Keys

KeyValue (type)Description
ssl.ClientCertificateX509Certificate
ssl.LoadClientCertAsyncFunctask
server.RemoteIpAddressLine
server.RemotePortLine
server.LocalIpAddressLine
server.LocalPortLine
server.IsLocalbool
server.OnSendingHeadersActionActionobject, object

SendFiles v0.3.0

KeyValue (type)Description
sendfile.SendAsyncSee Signature TransferUpon request

Opaque v0.3.0

KeyValue (type)Description
opaque.VersionLine
opaque.UpgradeOpaqueupgradeSee Signature Transfer
opaque.StreamFlow
opaque.CallCancelledCancellationToken

WebSocket v0.3.0

KeyValue (type)Description
websocket.VersionLine
websocket.AcceptWebSocketAcceptSee Signature Transfer
websocket.AcceptAltNot indicated
websocket.SubProtocolLineSee step 5.5 in Section 4.2.2 of RFC6455
websocket.SendAsyncWebSocketSendAsyncSee Signature Transfer
websocket.ReceiveAsyncWebSocketReceiveAsyncSee Signature Transfer
websocket.CloseAsyncWebSocketCloseAsyncSee Signature Transfer
websocket.CallCancelledCancellationToken
websocket.ClientCloseStatusintNot necessary
websocket.ClientCloseDescriptionLineNot necessary

Additional Resources



Also popular now: