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

Por Steve Smith e Rick Anderson

ASP.NET Core:

  • Dá suporte para OWIN (Open Web Interface para .NET).
  • Tem substituições compatíveis com o .NET Core para as bibliotecas Microsoft.Owin.* (Katana).

O OWIN permite que os aplicativos Web sejam separados dos servidores Web. Ele define uma maneira padrão de usar o middleware em um pipeline para manipular solicitações e respostas associadas. O middleware e os aplicativos ASP.NET Core podem interoperar com aplicativos, servidores e middleware baseados no OWIN.

O OWIN fornece uma camada de desacoplamento que permite duas estruturas com modelos de objeto diferentes para ser usadas juntas. O pacote Microsoft.AspNetCore.Owin fornece duas implementações de adaptador:

  • ASP.NET Core para OWIN
  • OWIN para 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.

Observação

O uso desses adaptadores implica um custo de desempenho. Os aplicativos que usam somente componentes do ASP.NET Core não devem usar o pacote Microsoft.AspNetCore.Owin ou os adaptadores.

Exibir ou baixar código de exemplo (como baixar)

Executando o middleware do OWIN no pipeline do ASP.NET Core

O suporte ao OWIN do ASP.NET Core é implantado como parte do pacote Microsoft.AspNetCore.Owin. Importe o suporte ao OWIN para seu projeto instalando esse pacote.

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). O seguinte middleware simples do OWIN exibe “Olá, Mundo”:

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.

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.

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

Configure outras ações a serem executadas no pipeline do OWIN.

Observação

Os cabeçalhos de resposta devem ser modificados apenas antes da primeira gravação no fluxo de resposta.

Observação

Não é recomendado fazer várias chamadas a UseOwin por motivos de desempenho. Os componentes do OWIN funcionarão melhor se forem agrupados.

app.UseOwin(pipeline =>
{
    pipeline(next =>
    {
        return async environment =>
        {
            // Do something before.
            await next(environment);
            // Do something after.
        };
    });
});

Executar o ASP.NET Core em um servidor baseado no OWIN e usar seu suporte do WebSockets

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. 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. 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.

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);
    }
}

Ambiente do OWIN

Você pode construir um ambiente do OWIN usando o HttpContext.


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

Chaves do OWIN

O OWIN depende de um objeto IDictionary<string,object> para transmitir informações em uma troca de Solicitação/Resposta HTTP. O ASP.NET Core implementa as chaves listadas abaixo. Consulte a especificação primária, extensões e as Diretrizes de chaves do OWIN e chaves comuns.

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

Chave Valor (tipo) Descrição
owin.RequestScheme String
owin.RequestMethod String
owin.RequestPathBase String
owin.RequestPath String
owin.RequestQueryString String
owin.RequestProtocol String
owin.RequestHeaders IDictionary<string,string[]>
owin.RequestBody Stream

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

Chave Valor (tipo) Descrição
owin.RequestId String Opcional

Dados de resposta (OWIN v1.0.0)

Chave Valor (tipo) Descrição
owin.ResponseStatusCode int Opcional
owin.ResponseReasonPhrase String Opcional
owin.ResponseHeaders IDictionary<string,string[]>
owin.ResponseBody Stream

Outros dados (OWIN v1.0.0)

Chave Valor (tipo) Descrição
owin.CallCancelled CancellationToken
owin.Version String

Chaves comuns

Chave Valor (tipo) Descrição
ssl.ClientCertificate X509Certificate
ssl.LoadClientCertAsync Func<Task>
server.RemoteIpAddress String
server.RemotePort String
server.LocalIpAddress String
server.LocalPort String
server.OnSendingHeaders Action<Action<object>,object>

SendFiles v0.3.0

Chave Valor (tipo) Descrição
sendfile.SendAsync Consulte Assinatura do delegado Por solicitação

Opaque v0.3.0

Chave Valor (tipo) Descrição
opaque.Version String
opaque.Upgrade OpaqueUpgrade Consulte Assinatura do delegado
opaque.Stream Stream
opaque.CallCancelled CancellationToken

WebSocket v0.3.0

Chave Valor (tipo) Descrição
websocket.Version String
websocket.Accept WebSocketAccept Consulte Assinatura do delegado
websocket.AcceptAlt Sem especificação
websocket.SubProtocol String Consulte a etapa 5.5 RFC6455 Seção 4.2.2
websocket.SendAsync WebSocketSendAsync Consulte Assinatura do delegado
websocket.ReceiveAsync WebSocketReceiveAsync Consulte Assinatura do delegado
websocket.CloseAsync WebSocketCloseAsync Consulte Assinatura do delegado
websocket.CallCancelled CancellationToken
websocket.ClientCloseStatus int Opcional
websocket.ClientCloseDescription String Opcional

Recursos adicionais