Открытый веб-интерфейс для .NET (OWIN) в ASP.NET Core

Авторы: Стив Смит (Steve Smith) и Рик Андерсон (Rick Anderson)

ASP.NET Core:

  • поддерживает открытый веб-интерфейс для .NET (OWIN);
  • имеет совместимые с .NET Core замены для библиотек Microsoft.Owin.* (Katana).

OWIN позволяет ослабить зависимость веб-приложений от веб-сервера. Он определяет стандартный способ использования ПО промежуточного в конвейере для обработки запросов и связанных с ними откликов. Приложения ASP.NET Core и ПО промежуточного слоя могут взаимодействовать с приложениями, серверами и ПО промежуточного слоя, основанными на OWIN.

OWIN обеспечивает разделительный уровень, позволяющий совместно использовать две платформы с разнородными объектными моделями. Пакет Microsoft.AspNetCore.Owin содержит две реализации адаптера:

  • ASP.NET Core в OWIN
  • OWIN в ASP.NET Core

Это позволяет размещать ASP.NET Core поверх сервера или узла, совместимого с OWIN, а также запускать другие совместимые с OWIN компоненты поверх ASP.NET Core.

Примечание.

Использование этих адаптеров сопряжено с потерями производительности. Приложениям, использующим только компоненты ASP.NET Core, не следует использовать адаптеры или пакет Microsoft.AspNetCore.Owin.

Просмотреть или скачать образец кода (описание загрузки)

Выполнение ПО промежуточного слоя OWIN в конвейере ASP.NET Core

Поддержка OWIN для ASP.NET Core развертывается в составе пакета Microsoft.AspNetCore.Owin. Вы можете импортировать поддержку OWIN в проект, установив этот пакет.

ПО промежуточного слоя OWIN соответствует спецификации OWIN, где требуется задать интерфейс Func<IDictionary<string, object>, Task> и определенные ключи (такие как owin.ResponseBody). Следующее простое ПО промежуточного слоя OWIN отображает сообщение "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);
}

Сигнатура примера возвращает Task и принимает IDictionary<string, object>, как того требует OWIN.

Приведенный ниже код показывает, как добавить ПО промежуточного слоя OwinHello (показано выше) в конвейер ASP.NET Core с помощью метода расширения UseOwin.

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

В конвейере OWIN можно настроить и другие действия.

Примечание.

Заголовки отклика можно изменять только до первой записи в поток отклика.

Примечание.

Из соображений производительности не рекомендуется выполнять несколько вызовов UseOwin. Компоненты OWIN лучше всего работают, когда сгруппированы друг с другом.

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

Запуск ASP.NET Core на основанном на OWIN сервере и использование его поддержки WebSocket

Другим примером того, как ASP.NET Core может использовать функции сервера на основе OWIN, является доступ к таким функциям, как WebSocket. Веб-сервер OWIN .NET, используемый в предыдущем примере, имеет встроенную поддержку веб-сокетов, что может использовать приложение ASP.NET Core. Приведенный ниже пример показывает простое веб-приложение, которое поддерживает веб-сокеты и выводит обратно все данные, отправляемые на сервер через WebSocket.

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

Среда OWIN

Вы можете создать среду OWIN с помощью HttpContext.


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

Ключи OWIN

OWIN использует объект IDictionary<string,object> для передачи сведений через систему обмена запросами и откликами HTTP. ASP.NET Core реализует указанные ниже ключи. См. основную спецификацию, расширения, а также статью Рекомендации по ключам OWIN и общие ключи.

Данные запроса (OWIN версии 1.0.0)

Ключ Значение (тип) Description
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

Данные запроса (OWIN версии 1.1.0)

Ключ Значение (тип) Description
owin.RequestId String Необязательно

Данные отклика (OWIN версии 1.0.0)

Ключ Значение (тип) Description
owin.ResponseStatusCode int Необязательно
owin.ResponseReasonPhrase String Необязательно
owin.ResponseHeaders IDictionary<string,string[]>
owin.ResponseBody Stream

Другие данные (OWIN версии 1.0.0)

Ключ Значение (тип) Description
owin.CallCancelled CancellationToken
owin.Version String

Общие ключи

Ключ Значение (тип) Description
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 версии 0.3.0

Ключ Значение (тип) Description
sendfile.SendAsync См. описание сигнатуры делегата Для каждого запроса

Opaque версии 0.3.0

Ключ Значение (тип) Description
opaque.Version String
opaque.Upgrade OpaqueUpgrade См. описание сигнатуры делегата
opaque.Stream Stream
opaque.CallCancelled CancellationToken

WebSocket версии 0.3.0

Ключ Значение (тип) Description
websocket.Version String
websocket.Accept WebSocketAccept См. описание сигнатуры делегата
websocket.AcceptAlt Нет в спецификации
websocket.SubProtocol String См. раздел 4.2.2 RFC6455, шаг 5.5
websocket.SendAsync WebSocketSendAsync См. описание сигнатуры делегата
websocket.ReceiveAsync WebSocketReceiveAsync См. описание сигнатуры делегата
websocket.CloseAsync WebSocketCloseAsync См. описание сигнатуры делегата
websocket.CallCancelled CancellationToken
websocket.ClientCloseStatus int Необязательно
websocket.ClientCloseDescription String Необязательно

Дополнительные ресурсы