ASP.NET Core 中文文档 第三章 原理(16).NET开放Web接口(OWIN)
原文:Open Web Interface for .NET (OWIN)
作者:Steve Smith、 Rick 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.SendAsync | WebSocketSendAsync | 参考 delegate signature |
websocket.ReceiveAsync | WebSocketReceiveAsync | 参考 delegate signature |
websocket.CloseAsync | WebSocketCloseAsync | 参考 delegate signature |
websocket.CallCancelled | CancellationToken |
|
websocket.ClientCloseStatus | int |
可选项 |
websocket.ClientCloseDescription | String |
可选项 |
附录资源
ASP.NET Core 中文文档 第三章 原理(16).NET开放Web接口(OWIN)的更多相关文章
- ASP.NET Core 中文文档 第三章 原理(6)全球化与本地化
原文:Globalization and localization 作者:Rick Anderson.Damien Bowden.Bart Calixto.Nadeem Afana 翻译:谢炀(Kil ...
- ASP.NET Core 中文文档 第三章 原理(1)应用程序启动
原文:Application Startup 作者:Steve Smith 翻译:刘怡(AlexLEWIS) 校对:谢炀(kiler398).许登洋(Seay) ASP.NET Core 为你的应用程 ...
- ASP.NET Core 中文文档 第三章 原理(13)管理应用程序状态
原文:Managing Application State 作者:Steve Smith 翻译:姚阿勇(Dr.Yao) 校对:高嵩 在 ASP.NET Core 中,有多种途径可以对应用程序的状态进行 ...
- ASP.NET Core 中文文档 第三章 原理(2)中间件
原文:Middleware 作者:Steve Smith.Rick Anderson 翻译:刘怡(AlexLEWIS) 校对:许登洋(Seay) 章节: 什么是中间件 用 IApplicationBu ...
- ASP.NET Core 中文文档 第三章 原理(3)静态文件处理
原文:Working with Static Files 作者:Rick Anderson 翻译:刘怡(AlexLEWIS) 校对:谢炀(kiler398).许登洋(Seay).孟帅洋(书缘) 静态文 ...
- ASP.NET Core 中文文档 第三章 原理(10)依赖注入
原文:Dependency Injection 作者:Steve Smith 翻译:刘浩杨 校对:许登洋(Seay).高嵩 ASP.NET Core 的底层设计支持和使用依赖注入.ASP.NET Co ...
- ASP.NET Core 中文文档 第三章 原理(11)在多个环境中工作
原文: Working with Multiple Environments 作者: Steve Smith 翻译: 刘浩杨 校对: 孟帅洋(书缘) ASP.NET Core 介绍了支持在多个环境中管 ...
- ASP.NET Core 中文文档 第三章 原理(17)为你的服务器选择合适版本的.NET框架
原文:Choosing the Right .NET For You on the Server 作者:Daniel Roth 翻译:王健 校对:谢炀(Kiler).何镇汐.许登洋(Seay).孟帅洋 ...
- ASP.NET Core 中文文档 第三章 原理(7)配置
原文:Configuration 作者:Steve Smith.Daniel Roth 翻译:刘怡(AlexLEWIS) 校对:孟帅洋(书缘) ASP.NET Core 支持多种配置选项.应用程序配置 ...
- ASP.NET Core 中文文档 第三章 原理(8)日志
原文:Logging 作者:Steve Smith 翻译:刘怡(AlexLEWIS) 校对:何镇汐.许登洋(Seay) ASP.NET Core 内建支持日志,也允许开发人员轻松切换为他们想用的其他日 ...
随机推荐
- 在.NET Core 里使用 BouncyCastle 的DES加密算法
.NET Core上面的DES等加密算法要等到1.2 才支持,我们可是急需这个算法的支持,文章<使用 JavaScriptService 在.NET Core 里实现DES加密算法>需要用 ...
- iPhone Anywehre虚拟定位提示“后台服务未启动,请重新安装应用后使用”的解决方法
问题描述: iPhone越狱了,之后在Cydia中安装Anywhere虚拟定位,但是打开app提示:后台服务未启动,请重新安装应用后使用. 程序无法正常使用... 解决方法: 打开Cydia-已安装, ...
- angular实现统一的消息服务
后台API返回的消息怎么显示更优雅,怎么处理才更简洁?看看这个效果怎么样? 自定义指令和服务实现 自定义指令和服务实现消息自动显示在页面的顶部,3秒之后消失 1. 显示消息 这种显示消息的方式是不是有 ...
- netty5 HTTP协议栈浅析与实践
一.说在前面的话 前段时间,工作上需要做一个针对视频质量的统计分析系统,各端(PC端.移动端和 WEB端)将视频质量数据放在一个 HTTP 请求中上报到服务器,服务器对数据进行解析.分拣后从不同的 ...
- 【开源】.net 分布式架构之监控平台
开源地址:http://git.oschina.net/chejiangyi/Dyd.BaseService.Monitor .net 简单监控平台,用于集群的性能监控,应用耗时监控管理,统一日志管理 ...
- 我这么玩Web Api(二):数据验证,全局数据验证与单元测试
目录 一.模型状态 - ModelState 二.数据注解 - Data Annotations 三.自定义数据注解 四.全局数据验证 五.单元测试 一.模型状态 - ModelState 我理解 ...
- Maven常用命令
开发中常用的命令: 1. mvn compile 编译源代码2. mvn test-compile 编译测试代码3. mvn test 运行测试4. mvn package 打包,根据pom.xml打 ...
- Git快速入门
如果你不想看长篇的Git教程,想快速了解Git的使用,那么本文可能会对你入门Git有所帮助.由于笔者用的是Windows系统,所以本文只写Git在Windows上的使用. 一.Git安装 去Git官网 ...
- Windows下MySQL无法启动
问题描述: 从网上下了5.7 的MySQL,在bin目录下执行 start mysqld ,弹出个cmd窗口一闪就没了,也看不清是什么报错.mysqld --install安装了服务,也启动不了. ...
- Linux自动共享USB设备:udev+Samba
一.概述 公司最近要我实现USB设备插入Ubuntu后,自动共享到网络上,能像Windows共享一样(如\\192.168.1.10)访问里面的内容,不需要写入权限.当时听完这需求,我这新人表示惊呆了 ...