OWIN (Open Web Interface para .NET) com o ASP.NET CoreOpen Web Interface for .NET (OWIN) with ASP.NET Core

Por Steve Smith e Rick AndersonBy Steve Smith and Rick Anderson

O ASP.NET Core dá suporte para OWIN (Open Web Interface para .NET).ASP.NET Core supports the Open Web Interface for .NET (OWIN). O OWIN permite que os aplicativos Web sejam separados dos servidores Web.OWIN allows web apps to be decoupled from web servers. Ele define uma maneira padrão de usar o middleware em um pipeline para manipular solicitações e respostas associadas.It defines a standard way for middleware to be used in a pipeline to handle requests and associated responses. O middleware e os aplicativos ASP.NET Core podem interoperar com aplicativos, servidores e middleware baseados no OWIN.ASP.NET Core applications and middleware can interoperate with OWIN-based applications, servers, and middleware.

O OWIN fornece uma camada de desacoplamento que permite duas estruturas com modelos de objeto diferentes para ser usadas juntas.OWIN provides a decoupling layer that allows two frameworks with disparate object models to be used together. O pacote Microsoft.AspNetCore.Owin fornece duas implementações de adaptador:The Microsoft.AspNetCore.Owin package provides two adapter implementations:

  • ASP.NET Core para OWINASP.NET Core to OWIN
  • OWIN para ASP.NET CoreOWIN to ASP.NET Core

Isso permite que o ASP.NET Core seja hospedado em um servidor/host compatível com OWIN ou que outros componentes compatíveis com OWIN sejam executados no ASP.NET Core.This allows ASP.NET Core to be hosted on top of an OWIN compatible server/host or for other OWIN compatible components to be run on top of ASP.NET Core.

Observação

O uso desses adaptadores implica um custo de desempenho.Using these adapters comes with a performance cost. Os aplicativos que usam somente componentes do ASP.NET Core não devem usar o pacote Microsoft.AspNetCore.Owin ou os adaptadores.Apps using only ASP.NET Core components shouldn't use the Microsoft.AspNetCore.Owin package or adapters.

Exibir ou baixar código de exemplo (como baixar)View or download sample code (how to download)

Executando o middleware do OWIN no pipeline do ASP.NET CoreRunning OWIN middleware in the ASP.NET Core pipeline

O suporte ao OWIN do ASP.NET Core é implantado como parte do pacote Microsoft.AspNetCore.Owin.ASP.NET Core's OWIN support is deployed as part of the Microsoft.AspNetCore.Owin package. Importe o suporte ao OWIN para seu projeto instalando esse pacote.You can import OWIN support into your project by installing this package.

O middleware do OWIN está em conformidade com a especificação do OWIN, que exige uma interface Func<IDictionary<string, object>, Task> e a definição de chaves específicas (como owin.ResponseBody).OWIN middleware conforms to the OWIN specification, which requires a Func<IDictionary<string, object>, Task> interface, and specific keys be set (such as owin.ResponseBody). O seguinte middleware simples do OWIN exibe “Olá, Mundo”:The following simple OWIN middleware displays "Hello World":

public Task OwinHello(IDictionary<string, object> environment)
{
    string responseText = "Hello World via OWIN";
    byte[] responseBytes = Encoding.UTF8.GetBytes(responseText);

    // OWIN Environment Keys: https://owin.org/spec/spec/owin-1.0.0.html
    var responseStream = (Stream)environment["owin.ResponseBody"];
    var responseHeaders = (IDictionary<string, string[]>)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 assinatura de exemplo retorna uma Task e aceita uma IDictionary<string, object>, conforme solicitado pelo OWIN.The sample signature returns a Task and accepts an IDictionary<string, object> as required by OWIN.

O código a seguir mostra como adicionar o middleware OwinHello (mostrado acima) ao pipeline do ASP.NET Core com o método de extensão UseOwin.The following code shows how to add the OwinHello middleware (shown above) to the ASP.NET Core pipeline with the UseOwin extension method.

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

Configure outras ações a serem executadas no pipeline do OWIN.You can configure other actions to take place within the OWIN pipeline.

Observação

Os cabeçalhos de resposta devem ser modificados apenas antes da primeira gravação no fluxo de resposta.Response headers should only be modified prior to the first write to the response stream.

Observação

Não é recomendado fazer várias chamadas a UseOwin por motivos de desempenho.Multiple calls to UseOwin is discouraged for performance reasons. Os componentes do OWIN funcionarão melhor se forem agrupados.OWIN components will operate best if grouped together.

app.UseOwin(pipeline =>
{
    pipeline(async (next) =>
    {
        // do something before
        await OwinHello(new OwinEnvironment(HttpContext));
        // do something after
    });
});

Usando a hospedagem do ASP.NET Core em um servidor baseado no OWINUsing ASP.NET Core Hosting on an OWIN-based server

Os servidores baseados no OWIN podem hospedar aplicativos ASP.NET Core.OWIN-based servers can host ASP.NET Core apps. Um desses servidores é o Nowin, um servidor Web do OWIN no .NET.One such server is Nowin, a .NET OWIN web server. Na amostra para este artigo, incluí um projeto que referencia o Nowin e usa-o para criar um IServer com capacidade de auto-hospedar o ASP.NET Core.In the sample for this article, I've included a project that references Nowin and uses it to create an IServer capable of self-hosting ASP.NET Core.

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<Startup>()
                .Build();

            host.Run();
        }
    }
}

O IServer é uma interface que requer uma propriedade Features e um método Start.IServer is an interface that requires a Features property and a Start method.

Start é responsável por configurar e iniciar o servidor, que, nesse caso, é feito por meio de uma série de chamadas à API fluente que definem endereços analisados do IServerAddressesFeature.Start is responsible for configuring and starting the server, which in this case is done through a series of fluent API calls that set addresses parsed from the IServerAddressesFeature. Observe que a configuração fluente da variável _builder especifica que as solicitações serão manipuladas pelo appFunc definido anteriormente no método.Note that the fluent configuration of the _builder variable specifies that requests will be handled by the appFunc defined earlier in the method. Esse Func é chamado em cada solicitação para processar as solicitações de entrada.This Func is called on each request to process incoming requests.

Adicionaremos também uma extensão IWebHostBuilder para facilitar a adição e configuração do servidor Nowin.We'll also add an IWebHostBuilder extension to make it easy to add and configure 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<IServer, NowinServer>();
            });
        }

        public static IWebHostBuilder UseNowin(this IWebHostBuilder builder, Action<ServerBuilder> configure)
        {
            builder.ConfigureServices(services =>
            {
                services.Configure(configure);
            });
            return builder.UseNowin();
        }
    }
}

Com isso em vigor, invoque a extensão no Program.cs para executar um aplicativo ASP.NET Core usando este servidor personalizado:With this in place, invoke the extension in Program.cs to run an ASP.NET Core app using this custom 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<Startup>()
                .Build();

            host.Run();
        }
    }
}

Saiba mais sobre os Servidores ASP.NET Core.Learn more about ASP.NET Core Servers.

Executar o ASP.NET Core em um servidor baseado no OWIN e usar seu suporte do WebSocketsRun ASP.NET Core on an OWIN-based server and use its WebSockets support

Outro exemplo de como os recursos dos servidores baseados no OWIN podem ser aproveitados pelo ASP.NET Core é o acesso a recursos como o WebSockets.Another example of how OWIN-based servers' features can be leveraged by ASP.NET Core is access to features like WebSockets. O servidor Web do OWIN no .NET usado no exemplo anterior tem suporte para Soquetes da Web internos, que podem ser aproveitados por um aplicativo ASP.NET Core.The .NET OWIN web server used in the previous example has support for Web Sockets built in, which can be leveraged by an ASP.NET Core application. O exemplo abaixo mostra um aplicativo Web simples que dá suporte a Soquetes da Web e repete tudo o que foi enviado ao servidor por meio do WebSockets.The example below shows a simple web app that supports Web Sockets and echoes back everything sent to the server through WebSockets.

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<byte>(buffer), CancellationToken.None);

        while (!webSocket.CloseStatus.HasValue)
        {
            // Echo anything we receive
            await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, received.Count), 
                received.MessageType, received.EndOfMessage, CancellationToken.None);

            received = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), 
                CancellationToken.None);
        }

        await webSocket.CloseAsync(webSocket.CloseStatus.Value, 
            webSocket.CloseStatusDescription, CancellationToken.None);
    }
}

Essa amostra é configurada usando o mesmo NowinServer que o anterior – a única diferença está em como o aplicativo é configurado em seu método Configure.This sample is configured using the same NowinServer as the previous one - the only difference is in how the application is configured in its Configure method. Um teste usando um cliente simples do WebSocket demonstra o aplicativo:A test using a simple websocket client demonstrates the application:

Cliente de teste de Soquete da Web

Ambiente do OWINOWIN environment

Você pode construir um ambiente do OWIN usando o HttpContext.You can construct an OWIN environment using the HttpContext.


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

Chaves do OWINOWIN keys

O OWIN depende de um objeto IDictionary<string,object> para transmitir informações em uma troca de Solicitação/Resposta HTTP.OWIN depends on an IDictionary<string,object> object to communicate information throughout an HTTP Request/Response exchange. O ASP.NET Core implementa as chaves listadas abaixo.ASP.NET Core implements the keys listed below. Consulte a especificação primária, extensões e as Diretrizes de chaves do OWIN e chaves comuns.See the primary specification, extensions, and OWIN Key Guidelines and Common Keys.

Dados de solicitação (OWIN v1.0.0)Request data (OWIN v1.0.0)

ChaveKey Valor (tipo)Value (type) DESCRIÇÃODescription
owin.RequestSchemeowin.RequestScheme String
owin.RequestMethodowin.RequestMethod String
owin.RequestPathBaseowin.RequestPathBase String
owin.RequestPathowin.RequestPath String
owin.RequestQueryStringowin.RequestQueryString String
owin.RequestProtocolowin.RequestProtocol String
owin.RequestHeadersowin.RequestHeaders IDictionary<string,string[]>
owin.RequestBodyowin.RequestBody Stream

Dados de solicitação (OWIN v1.1.0)Request data (OWIN v1.1.0)

ChaveKey Valor (tipo)Value (type) DESCRIÇÃODescription
owin.RequestIdowin.RequestId String OpcionalOptional

Dados de resposta (OWIN v1.0.0)Response data (OWIN v1.0.0)

ChaveKey Valor (tipo)Value (type) DESCRIÇÃODescription
owin.ResponseStatusCodeowin.ResponseStatusCode int OpcionalOptional
owin.ResponseReasonPhraseowin.ResponseReasonPhrase String OpcionalOptional
owin.ResponseHeadersowin.ResponseHeaders IDictionary<string,string[]>
owin.ResponseBodyowin.ResponseBody Stream

Outros dados (OWIN v1.0.0)Other data (OWIN v1.0.0)

ChaveKey Valor (tipo)Value (type) DESCRIÇÃODescription
owin.CallCancelledowin.CallCancelled CancellationToken
owin.Versionowin.Version String

Chaves comunsCommon keys

ChaveKey Valor (tipo)Value (type) DESCRIÇÃODescription
ssl.ClientCertificatessl.ClientCertificate X509Certificate
ssl.LoadClientCertAsyncssl.LoadClientCertAsync Func<Task>
server.RemoteIpAddressserver.RemoteIpAddress String
server.RemotePortserver.RemotePort String
server.LocalIpAddressserver.LocalIpAddress String
server.LocalPortserver.LocalPort String
server.IsLocalserver.IsLocal bool
server.OnSendingHeadersserver.OnSendingHeaders Action<Action<object>,object>

SendFiles v0.3.0SendFiles v0.3.0

ChaveKey Valor (tipo)Value (type) DESCRIÇÃODescription
sendfile.SendAsyncsendfile.SendAsync Consulte Assinatura do delegadoSee delegate signature Por solicitaçãoPer Request

Opaque v0.3.0Opaque v0.3.0

ChaveKey Valor (tipo)Value (type) DESCRIÇÃODescription
opaque.Versionopaque.Version String
opaque.Upgradeopaque.Upgrade OpaqueUpgrade Consulte Assinatura do delegadoSee delegate signature
opaque.Streamopaque.Stream Stream
opaque.CallCancelledopaque.CallCancelled CancellationToken

WebSocket v0.3.0WebSocket v0.3.0

ChaveKey Valor (tipo)Value (type) DESCRIÇÃODescription
websocket.Versionwebsocket.Version String
websocket.Acceptwebsocket.Accept WebSocketAccept Consulte Assinatura do delegadoSee delegate signature
websocket.AcceptAltwebsocket.AcceptAlt Sem especificaçãoNon-spec
websocket.SubProtocolwebsocket.SubProtocol String Consulte a etapa 5.5 RFC6455 Seção 4.2.2See RFC6455 Section 4.2.2 Step 5.5
websocket.SendAsyncwebsocket.SendAsync WebSocketSendAsync Consulte Assinatura do delegadoSee delegate signature
websocket.ReceiveAsyncwebsocket.ReceiveAsync WebSocketReceiveAsync Consulte Assinatura do delegadoSee delegate signature
websocket.CloseAsyncwebsocket.CloseAsync WebSocketCloseAsync Consulte Assinatura do delegadoSee delegate signature
websocket.CallCancelledwebsocket.CallCancelled CancellationToken
websocket.ClientCloseStatuswebsocket.ClientCloseStatus int OpcionalOptional
websocket.ClientCloseDescriptionwebsocket.ClientCloseDescription String OpcionalOptional

Recursos adicionaisAdditional resources