OWIN (Open Web Interface for .NET) avec ASP.NET Core

Par Steve Smith et Rick Anderson

ASP.NET Core :

  • Prend en charge l’interface Open Web pour .NET (OWIN).
  • Dispose de remplacements compatibles .NET Core pour les bibliothèques Microsoft.Owin.* (Katana).

OWIN permet que les applications web soient dissociées des serveurs web. Elle définit une façon standard d’utiliser un intergiciel (middleware) dans un pipeline pour gérer les requêtes et les réponses associées. Les applications ASP.NET Core et l’intergiciel peuvent interagir avec les applications OWIN, les serveurs et l’intergiciel.

OWIN fournit une couche de dissociation qui permet à deux frameworks ayant des modèles d’objets distincts d’être utilisés ensemble. Le package Microsoft.AspNetCore.Owin fournit deux implémentations d’adaptateurs :

  • ASP.NET Core sur OWIN
  • OWIN sur ASP.NET Core

Cela permet à ASP.NET Core d’être hébergé sur un serveur/hôte compatible OWIN, ou à d’autres composants compatibles OWIN d’être exécutés sur ASP.NET Core.

Notes

L’utilisation de ces adaptateurs a un impact sur les performances. Les applications utilisant uniquement des composants ASP.NET Core ne doivent pas utiliser les adaptateurs ou le package Microsoft.AspNetCore.Owin.

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)

Exécution de l’intergiciel (middleware) OWIN dans le pipeline ASP.NET Core

La prise en charge de l’interface OWIN d’ASP.NET Core est déployée dans le cadre du package Microsoft.AspNetCore.Owin. Vous pouvez importer la prise en charge d’OWIN dans votre projet en installant ce package.

L’intergiciel OWIN est conforme à la spécification OWIN, laquelle exige une interface Func<IDictionary<string, object>, Task> et la définition de clés spécifiques (comme owin.ResponseBody). L’intergiciel OWIN simple suivant affiche « 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);
}

L’exemple de signature retourne un Task et accepte un IDictionary<string, object>, comme l’exige OWIN.

Le code suivant montre comment ajouter le middleware OwinHello (présenté ci-dessus) au pipeline ASP.NET Core avec la méthode d’extension UseOwin.

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

Vous pouvez configurer d’autres actions pour qu’elles soient effectuées dans le pipeline OWIN.

Notes

Les en-têtes des réponses doivent être modifiés uniquement avant la première écriture dans le flux de réponse.

Notes

Pour des raisons de performance, il est déconseillé d’effectuer plusieurs appels à UseOwin. Les composants OWIN fonctionnent mieux s’ils sont regroupés.

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

Exécuter ASP.NET Core sur un serveur OWIN et utiliser sa prise en charge des WebSockets

L’accès à des fonctionnalités comme les WebSockets constitue un autre exemple de la façon dont les fonctionnalités de serveurs OWIN peuvent être exploitées par ASP.NET Core. Le serveur web .NET OWIN utilisé dans l’exemple précédent prend en charge les WebSockets intégrés, qui peuvent être exploités par une application ASP.NET Core. L’exemple ci-dessous montre une application web simple qui prend en charge les WebSockets et renvoie tout ce qui est envoyé au serveur via des 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);
    }
}

Environnement OWIN

Vous pouvez construire un environnement OWIN avec le HttpContext.


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

Clés OWIN

OWIN dépend d’un objet IDictionary<string,object> pour communiquer des informations tout au long d’un échange Requête HTTP/Réponse. ASP.NET Core implémente les clés répertoriées ci-dessous. Consultez la spécification principale, les extensions et les recommandations relatives aux clés OWIN et aux clés communes.

Données de requête (OWIN v1.0.0)

Clé Valeur (type) 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

Données de requête (OWIN v1.1.0)

Clé Valeur (type) Description
owin.RequestId String Facultatif

Données de réponse (OWIN v1.0.0)

Clé Valeur (type) Description
owin.ResponseStatusCode int Facultatif
owin.ResponseReasonPhrase String Facultatif
owin.ResponseHeaders IDictionary<string,string[]>
owin.ResponseBody Stream

Autres données (OWIN v1.0.0)

Clé Valeur (type) Description
owin.CallCancelled CancellationToken
owin.Version String

Clés communes

Clé Valeur (type) 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 v0.3.0

Clé Valeur (type) Description
sendfile.SendAsync Voir Signature du délégué Par requête

Opaque v0.3.0

Clé Valeur (type) Description
opaque.Version String
opaque.Upgrade OpaqueUpgrade Voir Signature du délégué
opaque.Stream Stream
opaque.CallCancelled CancellationToken

WebSocket v0.3.0

Clé Valeur (type) Description
websocket.Version String
websocket.Accept WebSocketAccept Voir Signature du délégué
websocket.AcceptAlt Non spécifiée
websocket.SubProtocol String Voir l’étape 5.5 de la RFC 6455 Section 4.2.2
websocket.SendAsync WebSocketSendAsync Voir Signature du délégué
websocket.ReceiveAsync WebSocketReceiveAsync Voir Signature du délégué
websocket.CloseAsync WebSocketCloseAsync Voir Signature du délégué
websocket.CallCancelled CancellationToken
websocket.ClientCloseStatus int Facultatif
websocket.ClientCloseDescription String Facultatif

Ressources supplémentaires