在本文中,我们将了解 OWIN 是什么以及它的创建历史。本文将帮助那些想知道它背后的人。
我们将了解一群人如何为 .NET 社区带来宝贵的想法。同样重要的是,微软已经接受了 OWIN,而 ASP.NET Core 基本上就是建立在这个想法之上的。
简单来说,OWIN 是 .NET 开放 Web 接口的缩写,是一种提供将 Web 服务器与 Web 应用程序解耦的规范。该规范也是所有 .NET 生态系统的开放标准。
OWIN 的官方定义是 — “定义了 .NET Web 服务器和 Web 应用程序之间的标准接口。OWIN 接口的目标是解耦服务器和应用程序,鼓励开发用于 .NET Web 开发的简单模块,并通过成为开放标准来刺激 .NET Web 开发工具的开源生态系统。”
“规范”这个词可能会让您感到困惑,但它指的是标准化的契约/接口,规定了 Web 服务器和应用程序之间的通信方式。因此,这些东西不是具体的实现,而是告诉开发人员如何在 Web 服务器和 Web 应用程序之间进行通信。
故事
OWIN 的故事始于 2010 年,当时一群人受到其他编程语言库的启发,试图创建一个在 Web 服务器和 Web 应用程序/框架之间提供 HTTP 抽象的库。
有一天,一群正在开发自己的框架/库的人,Ryan Riley(Kayak 的创建者)向其他正在开发其框架/库的人发送了一封电子邮件,内容是分享知识和共同努力(因为他们正在开发相同和不同但互补的东西)。
2010 年 9 月 7 日,Ryan Riley 发送的第一封电子邮件如下所示。
然后,大家开始一起讨论,因为这个信息很有道理。他们开始通过 Google 群组进行合作。
首先,小组开会寻找解决问题的方法。主要问题是,
- ASP.NET 与 IIS (System.Web.* 包) 耦合
- ASP.NET 太重
- IIS 太慢(旧版本)
- 很难实现 REST(比如最小 API — Sinatra -> DSL)
此外,.NET 社区需要能够与不同的轻量级 Web 服务器协同工作的解耦/独立、轻量级、高效的 Web 框架。
于是,一群人开始从 Rack(Ruby)和 WSGI(Python)中寻找灵感,开始解决这个问题。简单来说,Rack 和 WSGI 定义了 Web 服务器和 Web 应用程序之间的通用接口。
2010 年 9 月 27 日,第一稿来自 Benjamin van der Veen。
如您所见,该思想基于 Responder、Request 和 Response 接口。(它从服务器端提供某些抽象,并通过传递到应用程序端的 Request 和 Response 提供抽象。该思想通过接口提供标准化)
2010 年 11 月 29 日,该小组的一名成员 (Scott Koon) 创建了一个名为“.NET HTTP Abstractions”的工作组(请查看 Google 群组)。
这群人就 Web 服务器包装器达成了共识。同时,他们确定了 .NET 开放 Web 接口 (OWIN) 的命名法,并开始编写规范。
此外,在规范开始时,一群人就宣布了目标。
- 无依赖关系
- 风格灵活
- 服务器独立性
好吧,在编写规范的过程中,当然遇到了一些问题(我将跳过这部分,如果您想了解更多详细信息,可以查看 Google 群组和网站链接)。
经过一番头脑风暴和实验,大家找到了以下解决方案,如下所示。
他们专注于“Delegate Of Doom”(非正式术语),它限制了为 Web 服务器和应用程序之间的通信提供最小依赖性和契约(标准化)的模式或技术。这个想法是创建通信契约 + 通信管道。
他们决定创建一个入口点,为那些想要开始使用 OWIN 标准的人提供一个辅助库。这个库在Github上是开源的。
2011 年 7 月 25 日,OWIN 项目公开发布,标志着协作创建规范的开始。
最终,2012年12月,OWIN项目发布了其第一个正式版本1.0。
OWIN
本节将介绍总体思路。不涉及规格细节。
上图是 OWIN 的鸟瞰图。正如我之前所说,OWIN 只是提供 Web 服务器和 Web 应用程序之间的解耦通信。但请注意,OWIN 不是框架、库或实现。如果您查看 OWIN 规范,您将获得有关 Web 服务器和应用程序如何相互通信的规则或代码示例的详细信息。
要了解细节,有必要从参与者开始,这有助于理解 OWIN 的思想。
- Web 框架: OWIN 之上的独立组件,公开自己的对象模型或 API,应用程序可使用这些模型或 API 来促进请求处理。Web 框架可能需要从 OWIN 语义转换的适配器层。
- Web 应用程序:可能建立在 Web 框架之上的特定应用程序,使用 OWIN 兼容服务器运行。
- 中间件:在服务器和应用程序之间形成管道的传递组件,用于检查、路由或修改特定目的的请求和响应消息。
- 服务器:直接与客户端通信然后使用 OWIN 语义处理请求的 HTTP 服务器。服务器可能需要转换为 OWIN 语义的适配器层。
- 主机:应用程序和服务器在其中执行的进程,主要负责应用程序的启动。某些服务器也是主机。
主要是,参与者对于任何 Web 应用程序来说都是必须的。因此,OWIN 指示他们所有人实现目标。
请注意,为了便于理解,我将用运行时事物来描述所有过程。部分解释可能超出了 OWIN 的范围。
Web 服务器和 Web 应用程序(Web 框架的顶层)之间的通信。因此,这些参与者也具有巨大的计算逻辑。这个想法带来了用于处理 Web 请求和响应生命周期的管道。这也依赖于管道架构,该架构提供实现 Web 服务器和 Web 应用程序之间的交叉关注点。
一切始于主机,它创建所需的环境和配置内容。在运行时,它应该由内置的 Web 服务器和位于框架顶部的应用程序组成。因此,Web 服务器基本上会监听 HTTP 请求,填充内容和一些数据结构,然后将它们发送到通信管道。
构建管道的想法始于中间件,它是所有部分的链或过滤器。中间件提供了一些横切关注点,并有助于处理请求和响应生命周期。当请求来自服务器时,将它们发送到第一个链/过滤器(中间件),然后请求将一个接一个地继续。管道末端的请求由应用程序处理并生成响应,响应以反向方式发生同样的事情。
到目前为止,我们已经解释了总体思路,您可以查看规范以了解更多细节。
OWIN的解决方案从以下开始。
using Environment = IDictionary<string, object>
using AppFunc = Func<Environment, Task>
嗯,比你想象的要容易一些!
- 环境是包含所有需要的数据(包括请求和响应对象)的键值对。因此,当服务器和应用程序相互通信时,它是有意义的!
- AppFunc 是处理请求的委托。
基本上,AppFunc 如何处理应用程序端的请求?代码如下所示。
using System.IO;
using System.Text;
using Headers = IDictionary<string, string[]>;
var app = AppFunc(env =>
{
var bytes = Encoding.UTF8.GetBytes("Hello, OWIN!");
var length = bytes.Length.ToString();
var headers = env["owin.ResponseHeaders"];
headers.Add("Content-Type", new[] { "text/plain" });
headers.Add("Content-Length", new[] { length });
var stream = (Stream)env["owin.ResponseBody"];
return stream.WriteAsync(bytes, 0, bytes.Length);
});
AppFunc 上面的代码是中间件,它可以封装链中的下一个元素(即中间件)。并且它会调用下一个元素,以与其他元素相同的方式重复,就像一个嵌套链一样。
因此,它可以作为类和函数来实现。但我只展示类示例。
public class LoggingMiddleware
{
private AppFunc _next;
public LoggingMiddleware(AppFunc next)
{
this._next = next;
}
public Task LogBefore(Environment env)
{
// Implementation
}
public Task LogAfter(Environment env)
{
// Implementation
}
public async Task Invoke(Environment env)
{
LogBefore(env);
await _next(env);
LogAfter(env);
}
}
这就是中间件方面。
还具有用于管道端的 IAppBuilder 接口。其主要目的是提供配置处理 HTTP 请求和响应的中间件管道的契约。
- 最初旨在提供代表签名
- 后来添加了 IAppBuilder 并作为唯一的接口
public interface IAppBuilder
{
IDictionary<string, object> Properties { get; }
IAppBuilder Use(object middleware, params object[] args);
object Build(Type returnType);
IAppBuilder New();
}
可以看出,OWIN 解决方案仅依赖 FCL,因此依赖性极小。这些基本的东西有助于 OWIN 实现其目标。
PS 微软实现了 OWIN 的想法,它是 Katana,但这是另一个话题。
结论
OWIN 是一种规范,它提供了 Web 服务器和 Web 应用程序之间解耦的规则。此外,它还有助于实现 Web 服务器和应用程序之间的模块化架构。其背后的理念已在许多其他 Web 技术环境中得到应用。OWIN 是一个强大的理念,它为 .NET 社区提供了传统 IIS 和 ASP.NET(旧)托管模型的替代方案,解决了它们的局限性。