Interfaz web abierta para .NET (OWIN) con ASP.NET Core
Por Steve Smith y Rick Anderson
ASP.NET Core:
- Es compatible con la interfaz web abierta para .NET (OWIN).
- Tiene reemplazos compatibles con .NET Core para las bibliotecas
Microsoft.Owin.*
(Katana).
OWIN permite que las aplicaciones web se desacoplen de los servidores web. Define una manera estándar para usar software intermedio en una canalización a fin de controlar las solicitudes y las respuestas asociadas. El software intermedio y las aplicaciones de ASP.NET Core pueden interoperar con aplicaciones, servidores y software intermedio basados en OWIN.
OWIN proporciona una capa de desacoplamiento que permite que dos marcos de trabajo con modelos de objetos dispares se usen juntos. El paquete Microsoft.AspNetCore.Owin
proporciona dos implementaciones del adaptador:
- De ASP.NET Core a OWIN
- De OWIN a ASP.NET Core
Esto permite que ASP.NET Core se hospede sobre un servidor/host compatible con OWIN, o bien que otros componentes compatibles con OWIN se ejecuten sobre ASP.NET Core.
Nota
El uso de estos adaptadores conlleva un costo de rendimiento. Las aplicaciones que solo usan componentes de ASP.NET Core no deben usar el paquete o adaptadores de Microsoft.AspNetCore.Owin
.
Consulta o descarga el código de ejemplo (cómo descargarlo)
Ejecución de software intermedio de OWIN en la canalización de ASP.NET Core
La compatibilidad con OWIN de ASP.NET Core se implementa como parte del paquete Microsoft.AspNetCore.Owin
. Puedes importar compatibilidad con OWIN en el proyecto mediante la instalación de este paquete.
El software intermedio de OWIN cumple la especificación de OWIN, que requiere una interfaz Func<IDictionary<string, object>, Task>
y el establecimiento de determinadas claves (como owin.ResponseBody
). En el siguiente software intermedio simple de OWIN se muestra "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);
}
La firma de ejemplo devuelve un valor Task
y acepta un valor IDictionary<string, object>
, según los requisitos de OWIN.
En el código siguiente se muestra cómo agregar el software intermedio OwinHello
(mostrado arriba) a la canalización ASP.NET Core con el método de extensión UseOwin
.
public void Configure(IApplicationBuilder app)
{
app.UseOwin(pipeline =>
{
pipeline(next => OwinHello);
});
}
Puedes configurar la realización de otras acciones en la canalización de OWIN.
Nota
Los encabezados de respuesta solo deben modificarse antes de la primera escritura en la secuencia de respuesta.
Nota
No se recomienda la realización de varias llamadas a UseOwin
por motivos de rendimiento. Los componentes de OWIN funcionarán mejor si se agrupan.
app.UseOwin(pipeline =>
{
pipeline(next =>
{
return async environment =>
{
// Do something before.
await next(environment);
// Do something after.
};
});
});
Ejecución de ASP.NET Core en un servidor basado en OWIN y uso de su compatibilidad con WebSockets
Otro ejemplo de la manera en que ASP.NET Core puede aprovechar las características de los servidores basados en OWIN es el acceso a funciones como WebSockets. El servidor web de OWIN de .NET que se usa en el ejemplo anterior cuenta con compatibilidad integrada con WebSockets, cuyas ventajas puede aprovechar la aplicación ASP.NET Core. En el ejemplo siguiente se muestra una aplicación web simple que admite WebSockets y devuelve todo lo que se envía al servidor a través de 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);
}
}
Entorno de OWIN
Puedes construir un entorno de OWIN por medio de HttpContext
.
var environment = new OwinEnvironment(HttpContext);
var features = new OwinFeatureCollection(environment);
Claves de OWIN
OWIN depende de un objeto IDictionary<string,object>
para comunicar información mediante un intercambio de solicitud/respuesta HTTP. ASP.NET Core implementa las claves que se enumeran a continuación. Consulta las extensiones de la especificación principal y las directrices principales y claves comunes de OWIN.
Datos de solicitud (OWIN v1.0.0)
Key | Valor (tipo) | Descripción |
---|---|---|
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 |
Datos de solicitud (OWIN v1.1.0)
Key | Valor (tipo) | Descripción |
---|---|---|
owin.RequestId | String |
Optional |
Datos de respuesta (OWIN v1.0.0)
Key | Valor (tipo) | Descripción |
---|---|---|
owin.ResponseStatusCode | int |
Optional |
owin.ResponseReasonPhrase | String |
Optional |
owin.ResponseHeaders | IDictionary<string,string[]> |
|
owin.ResponseBody | Stream |
Otros datos (OWIN v1.0.0)
Key | Valor (tipo) | Descripción |
---|---|---|
owin.CallCancelled | CancellationToken |
|
owin.Version | String |
Claves comunes
Key | Valor (tipo) | Descripción |
---|---|---|
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
Key | Valor (tipo) | Descripción |
---|---|---|
sendfile.SendAsync | Vea Delegate signature (Signatura de delegado) | Por solicitud |
Opaque v0.3.0
Key | Valor (tipo) | Descripción |
---|---|---|
opaque.Version | String |
|
opaque.Upgrade | OpaqueUpgrade |
Vea Delegate signature (Signatura de delegado) |
opaque.Stream | Stream |
|
opaque.CallCancelled | CancellationToken |
WebSocket v0.3.0
Key | Valor (tipo) | Descripción |
---|---|---|
websocket.Version | String |
|
websocket.Accept | WebSocketAccept |
Vea Delegate signature (Signatura de delegado) |
websocket.AcceptAlt | Sin especificaciones | |
websocket.SubProtocol | String |
Vea la sección 4.2.2 de RFC6455, paso 5.5 |
websocket.SendAsync | WebSocketSendAsync |
Vea Delegate signature (Signatura de delegado) |
websocket.ReceiveAsync | WebSocketReceiveAsync |
Vea Delegate signature (Signatura de delegado) |
websocket.CloseAsync | WebSocketCloseAsync |
Vea Delegate signature (Signatura de delegado) |
websocket.CallCancelled | CancellationToken |
|
websocket.ClientCloseStatus | int |
Optional |
websocket.ClientCloseDescription | String |
Optional |
Recursos adicionales
- Consulte el origen en GitHub acerca de las claves OWIN admitidas en la capa de traducción.
- Middleware
- Servidores