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

Par Steve Smith et Rick AndersonBy Steve Smith and Rick Anderson

ASP.NET Core prend en charge l’interface Open Web pour .NET (OWIN).ASP.NET Core supports the Open Web Interface for .NET (OWIN). OWIN permet que les applications web soient dissociées des serveurs web.OWIN allows web apps to be decoupled from web servers. 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.It defines a standard way for middleware to be used in a pipeline to handle requests and associated responses. Les applications ASP.NET Core et l’intergiciel peuvent interagir avec les applications OWIN, les serveurs et l’intergiciel.ASP.NET Core applications and middleware can interoperate with OWIN-based applications, servers, and middleware.

OWIN fournit une couche de dissociation qui permet à deux frameworks ayant des modèles d’objets distincts d’être utilisés ensemble.OWIN provides a decoupling layer that allows two frameworks with disparate object models to be used together. Le package Microsoft.AspNetCore.Owin fournit deux implémentations d’adaptateurs :The Microsoft.AspNetCore.Owin package provides two adapter implementations:

  • ASP.NET Core sur OWINASP.NET Core to OWIN
  • OWIN sur ASP.NET CoreOWIN to 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.This allows ASP.NET Core to be hosted on top of an OWIN compatible server/host or for other OWIN compatible components to be run on top of ASP.NET Core.

Notes

L’utilisation de ces adaptateurs a un impact sur les performances.Using these adapters comes with a performance cost. Les applications utilisant uniquement des composants ASP.NET Core ne doivent pas utiliser les adaptateurs ou le package Microsoft.AspNetCore.Owin.Apps using only ASP.NET Core components shouldn't use the Microsoft.AspNetCore.Owin package or adapters.

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)View or download sample code (how to download)

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

La prise en charge de l’interface OWIN d’ASP.NET Core est déployée dans le cadre du package Microsoft.AspNetCore.Owin.ASP.NET Core's OWIN support is deployed as part of the Microsoft.AspNetCore.Owin package. Vous pouvez importer la prise en charge d’OWIN dans votre projet en installant ce package.You can import OWIN support into your project by installing this 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).OWIN middleware conforms to the OWIN specification, which requires a Func<IDictionary<string, object>, Task> interface, and specific keys be set (such as owin.ResponseBody). L’intergiciel OWIN simple suivant affiche « Hello World » :The following simple OWIN middleware displays "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.The sample signature returns a Task and accepts an IDictionary<string, object> as required by 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.The following code shows how to add the OwinHello middleware (shown above) to the ASP.NET Core pipeline with the UseOwin extension method.

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.You can configure other actions to take place within the OWIN pipeline.

Notes

Les en-têtes des réponses doivent être modifiés uniquement avant la première écriture dans le flux de réponse.Response headers should only be modified prior to the first write to the response stream.

Notes

Pour des raisons de performance, il est déconseillé d’effectuer plusieurs appels à UseOwin.Multiple calls to UseOwin is discouraged for performance reasons. Les composants OWIN fonctionnent mieux s’ils sont regroupés.OWIN components will operate best if grouped together.

app.UseOwin(pipeline =>
{
    pipeline(async (next) =>
    {
        // do something before
        await OwinHello(new OwinEnvironment(HttpContext));
        // do something after
    });
});

Utilisation de l’hébergement ASP.NET Core sur un serveur OWINUsing ASP.NET Core Hosting on an OWIN-based server

Les serveurs OWIN peuvent héberger des applications ASP.NET Core.OWIN-based servers can host ASP.NET Core apps. Nowin, serveur web OWIN .NET, est l’un de ces serveurs.One such server is Nowin, a .NET OWIN web server. Dans l’exemple de cet article, j’ai inclus un projet qui fait référence à Nowin et qui l’utilise pour créer un IServer capable d’auto-héberger ASP.NET Core.In the sample for this article, I've included a project that references Nowin and uses it to create an IServer capable of self-hosting 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<Startup>()
                .Build();

            host.Run();
        }
    }
}

IServer est une interface qui nécessite une propriété Features et une méthode Start.IServer is an interface that requires a Features property and a Start method.

Start est chargé de configurer et de démarrer le serveur, ce qui, dans le cas présent, s’effectue à l’aide d’une série d’appels d’API Fluent qui définissent des adresses analysées à partir d’IServerAddressesFeature.Start is responsible for configuring and starting the server, which in this case is done through a series of fluent API calls that set addresses parsed from the IServerAddressesFeature. Notez que la configuration Fluent de la variable _builder spécifie que les requêtes seront traitées par le appFunc défini précédemment dans la méthode.Note that the fluent configuration of the _builder variable specifies that requests will be handled by the appFunc defined earlier in the method. Ce Func est appelé sur chaque requête pour traiter les requêtes entrantes.This Func is called on each request to process incoming requests.

Nous allons également ajouter une extension IWebHostBuilder pour faciliter l’ajout et la configuration du serveur Nowin.We'll also add an IWebHostBuilder extension to make it easy to add and configure the Nowin server.

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<IServer, NowinServer>();
            });
        }

        public static IWebHostBuilder UseNowin(this IWebHostBuilder builder, Action<ServerBuilder> configure)
        {
            builder.ConfigureServices(services =>
            {
                services.Configure(configure);
            });
            return builder.UseNowin();
        }
    }
}

Ceci étant en place, appelez l’extension dans Program.cs pour exécuter une application ASP.NET Core avec ce serveur personnalisé :With this in place, invoke the extension in Program.cs to run an ASP.NET Core app using this custom server:

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<Startup>()
                .Build();

            host.Run();
        }
    }
}

Découvrez des informations supplémentaires sur les serveurs ASP.NET Core.Learn more about ASP.NET Core Servers.

Exécuter ASP.NET Core sur un serveur OWIN et utiliser sa prise en charge des WebSocketsRun ASP.NET Core on an OWIN-based server and use its WebSockets support

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.Another example of how OWIN-based servers' features can be leveraged by ASP.NET Core is access to features like WebSockets. 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.The .NET OWIN web server used in the previous example has support for Web Sockets built in, which can be leveraged by an ASP.NET Core application. 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.The example below shows a simple web app that supports Web Sockets and echoes back everything sent to the server through 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);
    }
}

Cet exemple est configuré avec le même NowinServer que le précédent ; la seule différence réside dans la façon dont l’application est configurée dans sa méthode Configure.This sample is configured using the same NowinServer as the previous one - the only difference is in how the application is configured in its Configure method. Un test utilisant un client WebSocket simple présente l’application :A test using a simple websocket client demonstrates the application:

Client test WebSocket

Environnement OWINOWIN environment

Vous pouvez construire un environnement OWIN avec le HttpContext.You can construct an OWIN environment using the HttpContext.


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

Clés OWINOWIN keys

OWIN dépend d’un objet IDictionary<string,object> pour communiquer des informations tout au long d’un échange Requête HTTP/Réponse.OWIN depends on an IDictionary<string,object> object to communicate information throughout an HTTP Request/Response exchange. ASP.NET Core implémente les clés répertoriées ci-dessous.ASP.NET Core implements the keys listed below. Consultez la spécification principale, les extensions et les recommandations relatives aux clés OWIN et aux clés communes.See the primary specification, extensions, and OWIN Key Guidelines and Common Keys.

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

ToucheKey Valeur (type)Value (type) DescriptionDescription
owin.RequestSchemeowin.RequestScheme String
owin.RequestMethodowin.RequestMethod String
owin.RequestPathBaseowin.RequestPathBase String
owin.RequestPathowin.RequestPath String
owin.RequestQueryStringowin.RequestQueryString String
owin.RequestProtocolowin.RequestProtocol String
owin.RequestHeadersowin.RequestHeaders IDictionary<string,string[]>
owin.RequestBodyowin.RequestBody Stream

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

ToucheKey Valeur (type)Value (type) DescriptionDescription
owin.RequestIdowin.RequestId String FacultatifOptional

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

ToucheKey Valeur (type)Value (type) DescriptionDescription
owin.ResponseStatusCodeowin.ResponseStatusCode int FacultatifOptional
owin.ResponseReasonPhraseowin.ResponseReasonPhrase String FacultatifOptional
owin.ResponseHeadersowin.ResponseHeaders IDictionary<string,string[]>
owin.ResponseBodyowin.ResponseBody Stream

Autres données (OWIN v1.0.0)Other data (OWIN v1.0.0)

ToucheKey Valeur (type)Value (type) DescriptionDescription
owin.CallCancelledowin.CallCancelled CancellationToken
owin.Versionowin.Version String

Clés communesCommon keys

ToucheKey Valeur (type)Value (type) DescriptionDescription
ssl.ClientCertificatessl.ClientCertificate X509Certificate
ssl.LoadClientCertAsyncssl.LoadClientCertAsync Func<Task>
server.RemoteIpAddressserver.RemoteIpAddress String
server.RemotePortserver.RemotePort String
server.LocalIpAddressserver.LocalIpAddress String
server.LocalPortserver.LocalPort String
server.IsLocalserver.IsLocal bool
server.OnSendingHeadersserver.OnSendingHeaders Action<Action<object>,object>

SendFiles v0.3.0SendFiles v0.3.0

ToucheKey Valeur (type)Value (type) DescriptionDescription
sendfile.SendAsyncsendfile.SendAsync Voir Signature du déléguéSee delegate signature Par requêtePer Request

Opaque v0.3.0Opaque v0.3.0

ToucheKey Valeur (type)Value (type) DescriptionDescription
opaque.Versionopaque.Version String
opaque.Upgradeopaque.Upgrade OpaqueUpgrade Voir Signature du déléguéSee delegate signature
opaque.Streamopaque.Stream Stream
opaque.CallCancelledopaque.CallCancelled CancellationToken

WebSocket v0.3.0WebSocket v0.3.0

ToucheKey Valeur (type)Value (type) DescriptionDescription
websocket.Versionwebsocket.Version String
websocket.Acceptwebsocket.Accept WebSocketAccept Voir Signature du déléguéSee delegate signature
websocket.AcceptAltwebsocket.AcceptAlt Non spécifiéeNon-spec
websocket.SubProtocolwebsocket.SubProtocol String Voir l’étape 5.5 de la RFC 6455 Section 4.2.2See RFC6455 Section 4.2.2 Step 5.5
websocket.SendAsyncwebsocket.SendAsync WebSocketSendAsync Voir Signature du déléguéSee delegate signature
websocket.ReceiveAsyncwebsocket.ReceiveAsync WebSocketReceiveAsync Voir Signature du déléguéSee delegate signature
websocket.CloseAsyncwebsocket.CloseAsync WebSocketCloseAsync Voir Signature du déléguéSee delegate signature
websocket.CallCancelledwebsocket.CallCancelled CancellationToken
websocket.ClientCloseStatuswebsocket.ClientCloseStatus int FacultatifOptional
websocket.ClientCloseDescriptionwebsocket.ClientCloseDescription String FacultatifOptional

Ressources supplémentairesAdditional resources