ASP.NET Core 中 .NET 的开放 Web 接口 (OWIN)Open Web Interface for .NET (OWIN) with ASP.NET Core

本文内容

作者:Steve SmithRick Anderson

ASP.NET Core 支持 .NET 的开放 Web 接口 (OWIN)。OWIN 允许 Web 应用从 Web 服务器分离。它定义了在管道中使用中间件来处理请求和相关响应的标准方法。ASP.NET Core 应用程序和中间件可以与基于 OWIN 的应用程序、服务器和中间件进行互操作。

OWIN 提供了一个分离层,可一起使用具有不同对象模型的两个框架。Microsoft.AspNetCore.Owin 包提供了两个适配器实现:

  • ASP.NET Core 到 OWIN
  • OWIN 到 ASP.NET Core

此方法可将 ASP.NET Core 托管在兼容 OWIN 的服务器/主机上,或在 ASP.NET Core 上运行其他兼容 OWIN 的组件。

备注

使用这些适配器会带来性能成本。仅使用 ASP.NET Core 组件的应用不应使用 Microsoft.AspNetCore.Owin 包或适配器。

查看或下载示例代码如何下载

在 ASP.NET Core 管道中运行 OWIN 中间件Running OWIN middleware in the ASP.NET Core pipeline

ASP.NET Core 的 OWIN 支持作为 Microsoft.AspNetCore.Owin 包的一部分进行部署。可通过安装此包将 OWIN 支持导入到项目中。

OWIN 中间件符合 OWIN 规范,该规范要求使用 Func<IDictionary<string, object>, Task> 接口,并设置特定的键(如 owin.ResponseBody)。以下简单的 OWIN 中间件显示“Hello World”:

  1. public Task OwinHello(IDictionary<string, object> environment)
  2. {
  3. string responseText = "Hello World via OWIN";
  4. byte[] responseBytes = Encoding.UTF8.GetBytes(responseText);
  5. // OWIN Environment Keys: https://owin.org/spec/spec/owin-1.0.0.html
  6. var responseStream = (Stream)environment["owin.ResponseBody"];
  7. var responseHeaders = (IDictionary<string, string[]>)environment["owin.ResponseHeaders"];
  8. responseHeaders["Content-Length"] = new string[] { responseBytes.Length.ToString(CultureInfo.InvariantCulture) };
  9. responseHeaders["Content-Type"] = new string[] { "text/plain" };
  10. return responseStream.WriteAsync(responseBytes, 0, responseBytes.Length);
  11. }

示例签名返回 Task,并接受 OWIN 所要求的 IDictionary<string, object>

以下代码显示了如何使用 UseOwin 扩展方法将 OwinHello 中间件(如上所示)添加到 ASP.NET Core 管道。

  1. public void Configure(IApplicationBuilder app)
  2. {
  3. app.UseOwin(pipeline =>
  4. {
  5. pipeline(next => OwinHello);
  6. });
  7. }

可配置在 OWIN 管道中要进行的其他操作。

备注

响应标头只能在首次写入响应流之前进行修改。

备注

由于性能原因,不建议多次调用 UseOwin组合在一起时 OWIN 组件的性能最佳。

  1. app.UseOwin(pipeline =>
  2. {
  3. pipeline(next =>
  4. {
  5. return async environment =>
  6. {
  7. // Do something before.
  8. await next(environment);
  9. // Do something after.
  10. };
  11. });
  12. });

在基于 OWIN 的服务器中使用 ASP.NET Core 托管Using ASP.NET Core Hosting on an OWIN-based server

基于 OWIN 的服务器可托管 ASP.NET Core 应用。Nowin(.NET OWIN Web 服务器)属于这种服务器。本文的示例中包含了一个引用 Nowin 的项目,并使用它创建了一个自托管 ASP.NET Core 的 IServer

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Threading.Tasks;
  6. using Microsoft.AspNetCore.Hosting;
  7. namespace NowinSample
  8. {
  9. public class Program
  10. {
  11. public static void Main(string[] args)
  12. {
  13. var host = new WebHostBuilder()
  14. .UseNowin()
  15. .UseContentRoot(Directory.GetCurrentDirectory())
  16. .UseIISIntegration()
  17. .UseStartup<Startup>()
  18. .Build();
  19. host.Run();
  20. }
  21. }
  22. }

IServer 是需要 Features 属性和 Start 方法的接口。

Start 负责配置和启动服务器,在此情况下,此操作通过一系列 Fluent API 调用完成,这些调用设置从 IServerAddressesFeature 分析的地址。请注意,_builder 变量的 Fluent 配置指定请求将由方法中之前定义的 appFunc 来处理。对于每个请求,都会调用此 Func 以处理传入请求。

我们还将添加一个 IWebHostBuilder 扩展,以便添加和配置 Nowin 服务器。

  1. using System;
  2. using Microsoft.AspNetCore.Hosting.Server;
  3. using Microsoft.Extensions.DependencyInjection;
  4. using Nowin;
  5. using NowinSample;
  6. namespace Microsoft.AspNetCore.Hosting
  7. {
  8. public static class NowinWebHostBuilderExtensions
  9. {
  10. public static IWebHostBuilder UseNowin(this IWebHostBuilder builder)
  11. {
  12. return builder.ConfigureServices(services =>
  13. {
  14. services.AddSingleton<IServer, NowinServer>();
  15. });
  16. }
  17. public static IWebHostBuilder UseNowin(this IWebHostBuilder builder, Action<ServerBuilder> configure)
  18. {
  19. builder.ConfigureServices(services =>
  20. {
  21. services.Configure(configure);
  22. });
  23. return builder.UseNowin();
  24. }
  25. }
  26. }

完成此操作后,调用 Program.cs 中的扩展以使用此自定义服务器运行 ASP.NET Core 应用 :

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Threading.Tasks;
  6. using Microsoft.AspNetCore.Hosting;
  7. namespace NowinSample
  8. {
  9. public class Program
  10. {
  11. public static void Main(string[] args)
  12. {
  13. var host = new WebHostBuilder()
  14. .UseNowin()
  15. .UseContentRoot(Directory.GetCurrentDirectory())
  16. .UseIISIntegration()
  17. .UseStartup<Startup>()
  18. .Build();
  19. host.Run();
  20. }
  21. }
  22. }

了解有关 ASP.NET Core 服务器的更多信息。

在基于 OWIN 的服务器上运行 ASP.NET Core 并使用其 WebSocket 支持Run ASP.NET Core on an OWIN-based server and use its WebSockets support

ASP.NET Core 如何利用基于 OWIN 的服务器功能的另一个示例是访问 WebSocket 等功能。前面示例中使用的 .NET OWIN Web 服务器支持内置的 Web 套接字,可由 ASP.NET Core 应用程序利用。下面的示例显示了简单的 Web 应用,它支持 Web 套接字并回显通过 WebSocket 发送到服务器的所有内容。

  1. public class Startup
  2. {
  3. public void Configure(IApplicationBuilder app)
  4. {
  5. app.Use(async (context, next) =>
  6. {
  7. if (context.WebSockets.IsWebSocketRequest)
  8. {
  9. WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
  10. await EchoWebSocket(webSocket);
  11. }
  12. else
  13. {
  14. await next();
  15. }
  16. });
  17. app.Run(context =>
  18. {
  19. return context.Response.WriteAsync("Hello World");
  20. });
  21. }
  22. private async Task EchoWebSocket(WebSocket webSocket)
  23. {
  24. byte[] buffer = new byte[1024];
  25. WebSocketReceiveResult received = await webSocket.ReceiveAsync(
  26. new ArraySegment<byte>(buffer), CancellationToken.None);
  27. while (!webSocket.CloseStatus.HasValue)
  28. {
  29. // Echo anything we receive
  30. await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, received.Count),
  31. received.MessageType, received.EndOfMessage, CancellationToken.None);
  32. received = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer),
  33. CancellationToken.None);
  34. }
  35. await webSocket.CloseAsync(webSocket.CloseStatus.Value,
  36. webSocket.CloseStatusDescription, CancellationToken.None);
  37. }
  38. }

使用与前一个相同的 NowinServer 来配置此示例 - 唯一的区别是如何在其 Configure 方法中配置应用程序。使用简单的 websocket 客户端的测试演示应用程序:

Web 套接字测试客户端

OWIN 环境OWIN environment

可使用 HttpContext 来构造 OWIN 环境。

  1. var environment = new OwinEnvironment(HttpContext);
  2. var features = new OwinFeatureCollection(environment);

OWIN 键OWIN keys

OWIN 依赖于 IDictionary<string,object> 对象,以在整个 HTTP请求/响应交换中传达信息。ASP.NET Core 实现以下所列的键。请参阅主规范、扩展OWIN Key Guidelines and Common Keys(OWIN 键指南和常用键)。

请求数据 (OWIN v1.0.0)Request data (OWIN v1.0.0)

值(类型)描述
owin.RequestSchemeString
owin.RequestMethodString
owin.RequestPathBaseString
owin.RequestPathString
owin.RequestQueryStringString
owin.RequestProtocolString
owin.RequestHeadersIDictionary<string,string[]>
owin.RequestBodyStream

请求数据 (OWIN v1.1.0)Request data (OWIN v1.1.0)

值(类型)描述
owin.RequestIdString可选

响应数据 (OWIN v1.0.0)Response data (OWIN v1.0.0)

值(类型)描述
owin.ResponseStatusCodeint可选
owin.ResponseReasonPhraseString可选
owin.ResponseHeadersIDictionary<string,string[]>
owin.ResponseBodyStream

其他数据 (OWIN v1.0.0)Other data (OWIN v1.0.0)

值(类型)描述
owin.CallCancelledCancellationToken
owin.VersionString

常用键Common keys

值(类型)描述
ssl.ClientCertificateX509Certificate
ssl.LoadClientCertAsyncFunc<Task>
server.RemoteIpAddressString
server.RemotePortString
server.LocalIpAddressString
server.LocalPortString
server.IsLocalbool
server.OnSendingHeadersAction<Action<object>,object>

SendFiles v0.3.0SendFiles v0.3.0

值(类型)描述
sendfile.SendAsync请参阅委托签名每请求

Opaque v0.3.0Opaque v0.3.0

值(类型)描述
opaque.VersionString
opaque.UpgradeOpaqueUpgrade请参阅委托签名
opaque.StreamStream
opaque.CallCancelledCancellationToken

WebSocket v0.3.0WebSocket v0.3.0

值(类型)描述
websocket.VersionString
websocket.AcceptWebSocketAccept请参阅委托签名
websocket.AcceptAlt非规范
websocket.SubProtocolString请参阅 RFC6455 4.2.2 节步骤 5.5
websocket.SendAsyncWebSocketSendAsync请参阅委托签名
websocket.ReceiveAsyncWebSocketReceiveAsync请参阅委托签名
websocket.CloseAsyncWebSocketCloseAsync请参阅委托签名
websocket.CallCancelledCancellationToken
websocket.ClientCloseStatusint可选
websocket.ClientCloseDescriptionString可选

其他资源Additional resources