您的位置:首页 > 编程语言 > ASP

ASP.NET Core 中文文档 第三章 原理(16).NET开放Web接口(OWIN)

2016-08-24 09:30 1296 查看
原文:Open Web Interface for .NET (OWIN)

作者:Steve SmithRick Anderson

翻译:谢炀(kiler398)

校对:孟帅洋(书缘)

ASP.NET Core 支持 OWIN(即 Open Web Server Interface for .NET 的首字母缩写),OWIN的目标是用于解耦Web Server和Web Application。此外, OWIN为中间件定义了一个标准方法用来处理单个请求以及相关联的响应。ASP.NET Core 的程序和中间件可以和 OWIN-based 应用程序、服务器以及中间件相互交互。

章节:

在 ASP.NET 管道中运行 OWIN 中间件

在基于 OWIN 的服务器上宿主 ASP.NET

在 OWIN-based 服务器上运行 ASP.NET Core 并使用 WebSockets 支持

OWIN 键值

附录资源

查看下载示例代码

在 ASP.NET 管道中运行 OWIN 中间件

ASP.NET Core 对于 OWIN 的支持基于
Microsoft.AspNetCore.Owin
包。你可以在你的应用程序把这个包作为一个依赖导入到你的 project.json 文件里来实现对 OWIN 支持, 如下所示:

"dependencies": {
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
"Microsoft.AspNetCore.Owin": "1.0.0"                    //手动高亮
},

OWIN 中间件遵循 OWIN 标准, OWIN 标准定义了一系列
Func<IDictionary<string, object>, Task>
需要用到的属性接口, 并且规定了某些键值必须被设置 (例如
owin.ResponseBody
)。 下面的简单的中间件的例子来显示 "Hello World":

public Task OwinHello(IDictionary<string, object> environment)
{
string responseText = "Hello World via OWIN";
byte[] responseBytes = Encoding.UTF8.GetBytes(responseText);

// OWIN Environment Keys: http://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);
}

OWIN 最简单的方法签名是接收一个
IDictionary<string, object>
输入参数并且返回
Task
结果。

添加 OWIN 中间件到 ASP.NET 管道是最简单的办法是使用
UseOwin
扩展方法完成。参考上面所示的
OwinHello
方法,将它添加到管道是一个简单的事情:

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

当然你也可以在 OWIN 管道中配置其他 actions 来替代。


注意

响应头信息只能在第一次写入响应流的时机之前修改。




注意

因为性能原因同时调用多个
UseOwin
是不被鼓励的。 OWIN 组件如果能组合在一起将运作是最好的。


app.UseOwin(pipeline =>
{
pipeline(next =>
{
// do something before
return OwinHello;
// do something after
});
});

在基于 OWIN 的服务器上宿主 ASP.NET

基于 OWIN 的服务器可以宿主 ASP.NET 应用程序,
Nowin
就是其中之一,一个.NET 的 OWIN Web 服务器。在本文的例子中,我已经包含一个非常简单的项目并引用 Nowin 并用它来创建一个能够自托管 ASP.NET 核心的一个简单的服务器。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Owin;
using Microsoft.Extensions.Options;
using Nowin;

namespace NowinSample
{
public class NowinServer : IServer                  //手动高亮
{
private INowinServer _nowinServer;
private ServerBuilder _builder;

public IFeatureCollection Features { get; } = new FeatureCollection();

public NowinServer(IOptions<ServerBuilder> options)
{
Features.Set<IServerAddressesFeature>(new ServerAddressesFeature());
_builder = options.Value;
}

public void Start<TContext>(IHttpApplication<TContext> application)
{
// Note that this example does not take into account of Nowin's "server.OnSendingHeaders" callback.
// Ideally we should ensure this method is fired before disposing the context.
Func<IDictionary<string, object>, Task> appFunc = async env =>
{
// The reason for 2 level of wrapping is because the OwinFeatureCollection isn't mutable
// so features can't be added
var features = new FeatureCollection(new OwinFeatureCollection(env));

var context = application.CreateContext(features);
try
{
await application.ProcessRequestAsync(context);
}
catch (Exception ex)
{
application.DisposeContext(context, ex);
throw;
}

application.DisposeContext(context, null);
};

// Add the web socket adapter so we can turn OWIN websockets into ASP.NET Core compatible web sockets.
// The calling pattern is a bit different
appFunc = OwinWebSocketAcceptAdapter.AdaptWebSockets(appFunc);

// Get the server addresses
var address = Features.Get<IServerAddressesFeature>().Addresses.First();

var uri = new Uri(address);
var port = uri.Port;
IPAddress ip;
if (!IPAddress.TryParse(uri.Host, out ip))
{
ip = IPAddress.Loopback;
}

_nowinServer = _builder.SetAddress(ip)
.SetPort(port)
.SetOwinApp(appFunc)
.Build();
_nowinServer.Start();
}

public void Dispose()
{
_nowinServer?.Dispose();
}
}
}

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

Start
的职责是配置和启动服务器,在本示例中是通过一系列 fluent API 调用IServerAddressesFeature硬编码服务器地址来监听请求。注意 fluent 的
builder
变量指定了请求会被方法
appFunc
所处理。
Func
方法在每一个请求被处理前调用。

我们同样会添加
IWebHostBuilder
扩展来使得 Nowin 服务器易于添加和配置。

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

上述操作就绪以后,所有的需要使用自定义服务器运行 ASP.NET 应用程序的设置都在下面的 project.json 文件的命令中:

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
Servers


在 OWIN-based 服务器上运行 ASP.NET Core 并使用 WebSockets 支持

如何基于OWIN的服务器功能,可以通过ASP.NET核心加以利用另一个例子是获得像WebSockets的功能。在前面的例子中使用的.NET OWIN Web服务器具有内置的网络插座,可通过一个ASP.NET的核心应用加以利用的支持。下面的例子显示了支持网络套接字和简单的回显然后直接通过WebSockets发送到服务器的任何一个简单的Web应用程序。

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
方法是如何配置的。用 一个简单的 websocket 客户端的演示实际效果:



OWIN 键值

OWIN 依赖一个
IDictionary<string,object>
对象用来在一个完整的 HTTP 请求/响应交互中通讯信息。ASP.NET Core 实现所有的 OWIN 规范中列出的要求的必需和可选的以及自身实现的键。在OWIN规范不要求任何键是可选的,并且可以仅在某些情况下可以使用。 在使用 OWIN 键的时候,参阅 OWIN Key Guidelines and Common Keys 是一个好习惯。

请求数据 (OWIN v1.0.0)

值 (类型)描述
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

请求数据 (OWIN v1.1.0)

值 (类型)描述
owin.RequestId
String
可选项

响应数据 (OWIN v1.0.0)

值 (类型)描述
owin.ResponseStatusCode
int
可选项
owin.ResponseReasonPhrase
String
可选项
owin.ResponseHeaders
IDictionary<string,string[]>
owin.ResponseBody
Stream

其他数据 (OWIN v1.0.0)

值 (类型)描述
owin.CallCancelled
CancellationToken
owin.Version
String

通用键值

值 (类型)描述
ssl.ClientCertificate
X509Certificate
ssl.LoadClientCertAsync
Func<Task>
server.RemoteIpAddress
String
server.RemotePort
String
server.LocalIpAddress
String
server.LocalPort
String
server.IsLocal
bool
server.OnSendingHeaders
Action<Action<object>,object>

发送文件 v0.3.0

值 (类型)描述
sendfile.SendAsync参考 delegate signature每请求

Opaque v0.3.0

值 (类型)描述
opaque.Version
String
opaque.Upgrade
OpaqueUpgrade
参考 delegate signature
opaque.Stream
Stream
opaque.CallCancelled
CancellationToken

WebSocket v0.3.0

值 (类型)描述
websocket.Version
String
websocket.Accept
WebSocketAccept
参考 delegate signature
websocket.AcceptAlt没有规定
websocket.SubProtocol
String
参考 RFC6455 Section 4.2.2 Step 5.5
websocket.SendAsyncWebSocketSendAsync参考 delegate signature
websocket.ReceiveAsyncWebSocketReceiveAsync参考 delegate signature
websocket.CloseAsyncWebSocketCloseAsync参考 delegate signature
websocket.CallCancelled
CancellationToken
websocket.ClientCloseStatus
int
可选项
websocket.ClientCloseDescription
String
可选项

附录资源

Middleware

Servers

返回目录
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: