具有 ASP.NET Core 的 Open Web Interface for .NET (OWIN)Open Web Interface for .NET (OWIN) with ASP.NET Core

作者:Steve SmithRick AndersonBy Steve Smith and Rick Anderson

ASP.NET Core 支援Open Web Interface for .NET (OWIN)。ASP.NET Core supports the Open Web Interface for .NET (OWIN). OWIN 可讓 Web 應用程式獨立於網頁伺服器。OWIN allows web apps to be decoupled from web servers. 它會定義中介軟體要在管線中用來處理要求和相關聯回應的標準方式。It defines a standard way for middleware to be used in a pipeline to handle requests and associated responses. ASP.NET Core 應用程式和中介軟體可以與以 OWIN 為基礎的應用程式、伺服器及中介軟體進行交互操作。ASP.NET Core applications and middleware can interoperate with OWIN-based applications, servers, and middleware.

OWIN 提供分離層,可讓兩個利用不同物件模型的架構一起使用。OWIN provides a decoupling layer that allows two frameworks with disparate object models to be used together. Microsoft.AspNetCore.Owin 套件提供兩個配接器實作:The Microsoft.AspNetCore.Owin package provides two adapter implementations:

  • ASP.NET Core 至 OWINASP.NET Core to OWIN
  • OWIN 至 ASP.NET CoreOWIN to ASP.NET Core

這可讓 ASP.NET Core 裝載在 OWIN 相容的伺服器/主機之上,或讓其他 OWIN 相容的元件在 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.

注意

使用這些配接器將伴隨效能成本增加。Using these adapters comes with a performance cost. 僅使用 ASP.NET Core 元件的應用程式不應使用 Microsoft.AspNetCore.Owin 套件或配接器。Apps using only ASP.NET Core components shouldn't use the Microsoft.AspNetCore.Owin package or adapters.

檢視或下載範例程式碼 (英文) (如何下載)View or download sample code (how to download)

在 ASP.NET Core 管線中執行 OWIN 中介軟體Running OWIN middleware in the ASP.NET Core pipeline

ASP.NET Core 的 OWIN 支援部署為 Microsoft.AspNetCore.Owin 套件的一部分。ASP.NET Core's OWIN support is deployed as part of the Microsoft.AspNetCore.Owin package. 您可以藉由安裝此套件,將 OWIN 支援匯入您的專案中。You can import OWIN support into your project by installing this package.

OWIN 中介軟體符合 OWIN 規格,它需要設定 Func<IDictionary<string, object>, Task> 介面和特定的索引鍵 (例如 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). 下列簡單的 OWIN 中介軟體會顯示 "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);
}

範例簽章會傳回 Task,並依照 OWIN 的要求接受 IDictionary<string, object>The sample signature returns a Task and accepts an IDictionary<string, object> as required by OWIN.

下列程式碼示範如何使用 UseOwin 擴充方法,將 OwinHello 中介軟體 (如上所示) 新增至 ASP.NET Core 管線。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);
    });
}

您可以設定在 OWIN 管線內進行其他動作。You can configure other actions to take place within the OWIN pipeline.

注意

只能在第一次寫入回應資料流之前修改回應標頭。Response headers should only be modified prior to the first write to the response stream.

注意

基於效能考量,建議您不要多次呼叫 UseOwinMultiple calls to UseOwin is discouraged for performance reasons. OWIN 元件如果群組在一起,其運作效能最佳。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
    });
});

使用以 OWIN 為基礎的伺服器上所裝載的 ASP.NET CoreUsing ASP.NET Core Hosting on an OWIN-based server

以 OWIN 為基礎的伺服器可以裝載 ASP.NET Core 應用程式。OWIN-based servers can host ASP.NET Core apps. 其中一個這類伺服器是 Nowin,其為 .NET OWIN 網頁伺服器。One such server is Nowin, a .NET OWIN web server. 在本文的範例中,包含了參考 Nowin 並使用它來建立 IServer 能夠自我裝載之 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 是需要 Features 屬性和 Start 方法的介面。IServer is an interface that requires a Features property and a Start method.

Start 負責設定和啟動伺服器,在此情況下,這會透過一系列 Fluent API 呼叫來完成,而這些呼叫設定從 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. 請注意,_builder 變數的 Fluent 組態會指定要求將由稍早在方法中定義的 appFunc 處理。Note that the fluent configuration of the _builder variable specifies that requests will be handled by the appFunc defined earlier in the method. 每個要求都會呼叫這個 Func 來處理傳入的要求。This Func is called on each request to process incoming requests.

我們也將新增 IWebHostBuilder 延伸模組,以便能夠輕鬆地新增和設定 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();
        }
    }
}

完成上述作業後,請叫用 Program.cs 中的延伸模組,以使用這個自訂伺服器來執行 ASP.NET Core 應用程式: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();
        }
    }
}

深入了解 ASP.NET Core 伺服器Learn more about ASP.NET Core Servers.

在以 OWIN 為基礎的伺服器上執行 ASP.NET Core 並使用其 WebSocket 支援Run ASP.NET Core on an OWIN-based server and use its WebSockets support

ASP.NET Core 如何利用以 OWIN 為基礎之伺服器功能的另一個範例是存取 WebSocket 等功能。Another example of how OWIN-based servers' features can be leveraged by ASP.NET Core is access to features like WebSockets. 在上述範例中使用的 .NET OWIN 網頁伺服器支援內建的 Web 通訊端,供 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. 下列範例顯示的簡單 Web 應用程式支援 Web 通訊端,並透過 Websocket 回應傳送至伺服器的所有項目。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);
    }
}

範例使用與上述相同的 NowinServer 進行設定 - 唯一的差異是在其 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. 使用簡單 Websocket 用戶端的測試示範此應用程式:A test using a simple websocket client demonstrates the application:

Web 通訊端測試用戶端

OWIN 環境OWIN environment

您可以使用 HttpContext 建構 OWIN 環境。You can construct an OWIN environment using the HttpContext.


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

OWIN 索引鍵OWIN keys

OWIN 仰賴 IDictionary<string,object> 物件在 HTTP 要求/回應交換中傳遞資訊。OWIN depends on an IDictionary<string,object> object to communicate information throughout an HTTP Request/Response exchange. ASP.NET Core 會實作下面所列的索引鍵。ASP.NET Core implements the keys listed below. 請參閱主要規格、模組延伸OWIN Key Guidelines and Common Keys (OWIN 索引鍵指導方針和共用索引鍵)。See the primary specification, extensions, and OWIN Key Guidelines and Common Keys.

要求資料 (OWIN 1.0.0 版)Request data (OWIN v1.0.0)

KeyKey 值 (類型)Value (type) 說明Description
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

要求資料 (OWIN 1.1.0 版)Request data (OWIN v1.1.0)

KeyKey 值 (類型)Value (type) 說明Description
owin.RequestIdowin.RequestId String OptionalOptional

回應資料 (OWIN 1.0.0 版)Response data (OWIN v1.0.0)

KeyKey 值 (類型)Value (type) 說明Description
owin.ResponseStatusCodeowin.ResponseStatusCode int OptionalOptional
owin.ResponseReasonPhraseowin.ResponseReasonPhrase String OptionalOptional
owin.ResponseHeadersowin.ResponseHeaders IDictionary<string,string[]>
owin.ResponseBodyowin.ResponseBody Stream

其他資料 (OWIN 1.0.0 版)Other data (OWIN v1.0.0)

KeyKey 值 (類型)Value (type) 說明Description
owin.CallCancelledowin.CallCancelled CancellationToken
owin.Versionowin.Version String

共同索引鍵Common keys

KeyKey 值 (類型)Value (type) 說明Description
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 0.3.0 版SendFiles v0.3.0

KeyKey 值 (類型)Value (type) 說明Description
sendfile.SendAsyncsendfile.SendAsync 請參閱委派簽章See delegate signature 每個要求Per Request

Opaque 0.3.0 版Opaque v0.3.0

KeyKey 值 (類型)Value (type) 說明Description
opaque.Versionopaque.Version String
opaque.Upgradeopaque.Upgrade OpaqueUpgrade 請參閱委派簽章See delegate signature
opaque.Streamopaque.Stream Stream
opaque.CallCancelledopaque.CallCancelled CancellationToken

WebSocket 0.3.0 版WebSocket v0.3.0

KeyKey 值 (類型)Value (type) 說明Description
websocket.Versionwebsocket.Version String
websocket.Acceptwebsocket.Accept WebSocketAccept 請參閱委派簽章See delegate signature
websocket.AcceptAltwebsocket.AcceptAlt 非規格Non-spec
websocket.SubProtocolwebsocket.SubProtocol String 請參閱 RFC6455 4.2.2 節的步驟 5.5See RFC6455 Section 4.2.2 Step 5.5
websocket.SendAsyncwebsocket.SendAsync WebSocketSendAsync 請參閱委派簽章See delegate signature
websocket.ReceiveAsyncwebsocket.ReceiveAsync WebSocketReceiveAsync 請參閱委派簽章See delegate signature
websocket.CloseAsyncwebsocket.CloseAsync WebSocketCloseAsync 請參閱委派簽章See delegate signature
websocket.CallCancelledwebsocket.CallCancelled CancellationToken
websocket.ClientCloseStatuswebsocket.ClientCloseStatus int OptionalOptional
websocket.ClientCloseDescriptionwebsocket.ClientCloseDescription String OptionalOptional

其他資源Additional resources