[Перевод] Открытый веб-интерфейс для .NET (OWIN)
Привет, Хабр! ASP.NET Core поддерживает открытый веб-интерфейс для .NET (OWIN), а OWIN позволяет отвязывать веб-приложения от веб-серверов. Он определяет стандартный способ использования связующего ПО при обработке запросов и соответствующих ответов. Приложения ASP.NET Core и связующее ПО совместимы с приложениями, серверами и связующим ПО на базе OWIN. Подробнее об этой паре читайте под катом.
Просмотрите или скачайте образец кода
Выполнение связующего ПО в процессе ASP.NET
Поддержка OWIN со стороны ASP.NET Core развертывается в рамках пакета Microsoft.AspNetCore.Owin
. Чтобы импортировать поддержку OWIN в свой проект, добавьте пакет в виде зависимости в файл project.json
:
"dependencies": {
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
"Microsoft.AspNetCore.Owin": "1.0.0"
},
Связующее ПО OWIN соответствует спецификации OWIN, которая требует использовать интерфейс Func
и настроить определенные ключи (например, owin.ResponseBody
). Ниже приведен пример связующего ПО OWIN, которое отображает текст Hello World:
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);
}
Образец подписи выдает Task
и принимает IDictionary
в соответствии с требованиями OWIN.
В следующем коде показано, как добавить связующее ПО OwinHello
(см. выше) в процесс ASP.NET с помощью метода расширения UseOwin
.
public void Configure(IApplicationBuilder app)
{
app.UseOwin(pipeline =>
{
pipeline(next => OwinHello);
});
}
Вы можете настроить и другие действия для процесса OWIN.
Заголовки ответов следует менять только перед первой записью в поток ответов.
Не нужно выполнять много вызовов к UseOwi
n: это снижает производительность. Компоненты OWIN работают лучше, если их объединить.
app.UseOwin(pipeline =>
{
pipeline(next =>
{
// do something before
return OwinHello;
// do something after
});
});
Хостинг ASP.NET на OWIN-сервере
На OWIN-серверах можно размещать приложения ASP.NET. Один из таких серверов — Nowin, веб-сервер .NET OWIN. В пример для этой статьи мы добавили проект, который ссылается на Nowin и использует его для создания IServer
, способного самостоятельно размещать 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()
.Build();
host.Run();
}
}
}
IServer
— это интерфейс, который требует свойство Features
и метод Start
.
Start
отвечает за настройку и запуск сервера. Для этого используется серия вызовов API, настраивающих адреса, которые были проанализированы из IServerAddressesFeature. Обратите внимание: конфигурация переменной _builder
указывает, что запросы будет обрабатывать параметр appFunc
, ранее настроенный в методе. Эта функция вызывается по каждому запросу для обработки входящих запросов.
Также мы добавим расширение IWebHostBuilder
, чтобы упростить добавление и настройку сервера Nowin.
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();
}
}
}
Затем необходимо вызвать расширение в Program.cs, чтобы выполнить приложение ASP.NET с помощью этого пользовательского сервера:
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();
}
}
}
Подробнее о серверах ASP.NET.
Выполните ASP.NET Core на OWIN-сервере и воспользуйтесь поддержкой WebSockets
Еще один способ использовать OWIN-серверы в ASP.NET Core — получить доступ к функциям типа WebSockets. Веб-сервер .NET OWIN из предыдущего примера поддерживает встроенные веб-сокеты, которые можно использовать в приложении ASP.NET Core. В примере ниже показано простое веб-приложение, которое поддерживает веб-сокеты и возвращает отправителю все данные, отправленные на серверы через веб-сокеты.
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);
}
}
Этот образец настраивается с помощью того же NowinServer
, что и предыдущий; единственное различие заключается в способе настройки приложения в методе Configure
. Тест с помощью простого клиента веб-сокета демонстрирует приложение:
Среда OWIN
Среду OWIN можно создать с помощью HttpContext
.
var environment = new OwinEnvironment(HttpContext);
var features = new OwinFeatureCollection(environment);
Ключи OWIN
Для передачи информации через обмен данными HTTP-запрос/ответ OWIN необходим объект IDictionary
. ASP.NET Core реализует ключи, указанные ниже. См. основную спецификацию, расширения и Основные правила работы с OWIN.
Запрос данных (OWIN v1.0.0)
Ключ | Значение (тип) | Описание |
---|---|---|
owin.RequestScheme | Строка | |
owin.RequestMethod | Строка | |
owin.RequestPathBase | Строка | |
owin.RequestPath | Строка | |
owin.RequestQueryString | Строка | |
owin.RequestProtocol | Строка | |
owin.RequestHeaders | IDictionary |
|
owin.RequestBody | Поток |
Запрос данных (OWIN v1.1.0)
Ключ | Значение (тип) | Описание |
---|---|---|
owin.RequestId | Строка | Необязательно |
Ответные данные (OWIN v1.0.0)
Ключ | Значение (тип) | Описание |
---|---|---|
owin.ResponseStatusCode | int | Необязательно |
owin.ResponseReasonPhrase | Строка | Необязательно |
owin.ResponseHeaders | IDictionary |
|
owin.ResponseBody | Поток |
Другие данные (OWIN v1.0.0)
Ключ | Значение (тип) | Описание |
---|---|---|
owin.CallCancelled | CancellationToken | |
owin.Version | Строка |
Общие ключи
Ключ | Значение (тип) | Описание |
---|---|---|
ssl.ClientCertificate | X509Certificate | |
ssl.LoadClientCertAsync | FuncTask | |
server.RemoteIpAddress | Строка | |
server.RemotePort | Строка | |
server.LocalIpAddress | Строка | |
server.LocalPort | Строка | |
server.IsLocal | bool | |
server.OnSendingHeaders | ActionActionobject, object |
SendFiles v0.3.0
Ключ | Значение (тип) | Описание |
---|---|---|
sendfile.SendAsync | См. Передача подписи | По запросу |
Opaque v0.3.0
Ключ | Значение (тип) | Описание |
---|---|---|
opaque.Version | Строка | |
opaque.Upgrade | OpaqueUpgrade | См. Передача подписи |
opaque.Stream | Поток | |
opaque.CallCancelled | CancellationToken |
WebSocket v0.3.0
Ключ | Значение (тип) | Описание |
---|---|---|
websocket.Version | Строка | |
websocket.Accept | WebSocketAccept | См. Передача подписи |
websocket.AcceptAlt | Не указано | |
websocket.SubProtocol | Строка | См. шаг 5.5 в Разделе 4.2.2 RFC6455 |
websocket.SendAsync | WebSocketSendAsync | См. Передача подписи |
websocket.ReceiveAsync | WebSocketReceiveAsync | См. Передача подписи |
websocket.CloseAsync | WebSocketCloseAsync | См. Передача подписи |
websocket.CallCancelled | CancellationToken | |
websocket.ClientCloseStatus | int | Необязательно |
websocket.ClientCloseDescription | Строка | Необязательно |
Дополнительные ресурсы
- Связующее ПО
- Серверы