# 八、OWIN

## 简介

的[开放网络界面。NET](http://owin.org/) (OWIN)是一个微软规范，定义了一个合同。NET 应用程序与网络服务器交互。这包括执行 HTTP 请求的管道和位于中间的服务契约(中间件)。这也恰好是即将到来的 ASP.NET 5 的基础。

OWIN 允许您将您的服务应用程序与任何特定的 web 服务器(如 IIS)分离。虽然它可以使用 IIS，但也可以通过 OWIN 的 web 服务器实现 [OwinHttpListener](https://msdn.microsoft.com/en-us/library/microsoft.owin.host.httplistener.owinhttplistener%28v=vs.113%29.aspx) 进行自我托管(就像 WCF 一样)。

您需要添加对[微软的引用。owin . host . httplistener](https://www.nuget.org/packages/Microsoft.Owin.Host.HttpListener/)NuGet 包:

![](img/image036.png)

图 15:安装 HttpListener NuGet 包

我们为什么要关心 OWIN？嗯，这一次，它给了你一个一致的管道，更符合 ASP.NET 在不久的将来的方式:不再有网络表单——MVC 将通过 OWIN 进行配置！

| ![](img/note.png) | 注:要想了解 OWIN，请查看《简洁地》系列中乌戈·拉坦齐和西蒙妮·奇亚雷塔所著的《简洁地 OWIN》一书。 |

## 注册服务

OWIN 管道从调用一个名为 **`Startup`** 的类中名为 **`Configuration`** 的方法开始。这是惯例；没有基类或接口规定这一点，类和方法甚至可以是静态的。如果我们想更改这个引导方法，我们可以通过在程序集级别添加一个 [OwinStartupAttribute](https://msdn.microsoft.com/en-us/library/microsoft.owin.owinstartupattribute(v=vs.113).aspx) 或者在 **Web.config** 的 [appSettings](https://msdn.microsoft.com/en-us/library/aa903313%28v=vs.71%29.aspx) 部分添加一个“ [owin:appStartup](http://www.asp.net/aspnet/overview/owin-and-katana/owin-startup-class-detection) 条目来实现。在这里，我们注册一个中间件组件，作为回报，它将注册我们所有的服务(如租户识别和注册):

代码示例 82

```cs
          public static class Startup
         {
               public static void Configuration(IAppBuilder builder)
               {
                     builder.UseStaticFiles();
                     builder.UseDefaultFiles();
                     //rest goes here
                     builder.Use<MultitenancyMiddleware>();
                     //rest goes here
               }
         }

```

中间件类继承自[OwinMiddleware](https://msdn.microsoft.com/en-us/library/microsoft.owin.owinmiddleware%28v=vs.113%29.aspx)——还有其他选择，但这是我最喜欢的一个。中间件类在其构造函数中接收到一个指向管道中下一个中间件的指针，并且应该在其 [Invoke](https://msdn.microsoft.com/en-us/library/dn270632(v=vs.113).aspx) 方法中返回其调用的结果。

一个例子:

代码示例 83

```cs
          public class MultitenancyMiddleware : OwinMiddleware
         {
               public MultitenancyMiddleware(OwinMiddleware next) : base(next) {      }

               public override Task Invoke(IOwinContext context)
               {
                     //services registration
                     context.Set<ITenantLocationStrategy>(
                           typeof(ITenantLocationStrategy).FullName, 
                           new MefTenantLocationStrategy(
                                 typeof(Common.ContextRepository).Assembly));
                     context.Set<ITenantIdentifierStrategy>(
                           typeof(ITenantIdentifierStrategy).FullName, 
                           new HostHeaderTenantIdentifierStrategy());
                     context.Set<IConfiguration>(
                           typeof(IConfiguration).FullName, 
                           new AppSettingsConfiguration());  

                     //rest goes here

                     return this.Next.Invoke(context);
               }
         }

```

| ![](img/note.png) | 注意:现在，您不能将 OWIN 与 ASP.NET MVC 或 Web Forms 一起使用，因为这些依赖于 System.Web.DLL，ASP.NET 框架的核心，但是 ASP.NET MVC 6 将在 OWIN 之上工作。 |

因此，如果您要使用 OWIN，并且您需要解决我们的引导服务之一，您可以坚持选择 IoC 容器和公共服务定位器，或者您可以使用 OWIN 的内部实现:

代码示例 84

```cs
          public override Task Invoke(IOwinContext context)
         {
               var tls = context.Get<ITenantLocationStrategy>(
                     typeof(ITenantLocationStrategy).FullName);
               return this.Next.Invoke(context);
         }

```

OWIN 也支持[ASP.NET 身份](http://www.asp.net/identity)进行认证。[微软只需添加 NuGet 包。并对添加的类进行任何更改:](https://www.nuget.org/packages/Microsoft.AspNet.Identity.Owin/)

![](img/image037.png)

图 16:OWIN 的 ASP.NET 身份包

## Web API

与 MVC 不同，Web API 可以与 OWIN 一起使用。您需要注册一个实现，例如微软 NuGet 包[微软提供的实现。AspNet.WebApi.Owin](https://www.nuget.org/packages/Microsoft.AspNet.WebApi.Owin/) :

![](img/image038.jpg)

图 17:网络应用编程接口 OWIN 包

然后你需要用前面提到的 **`Configuration`** 方法注册 Web API 服务，使用 **`UseWebApi`** 扩展方法:

代码示例 85

```cs
          public static class Startup
         {
               public static void Configuration(IAppBuilder builder)
               {
                     builder.UseWebApi(new HttpConfiguration());
                     //rest goes here
               }
         }

```

## 更换系统。网

OWIN 的出现是因为想要取代**系统。网页**建筑。**系统中的一个关键类。Web** 是 [HttpContext](https://msdn.microsoft.com/en-us/library/system.web.httpcontext%28v=vs.110%29.aspx) ，在 OWIN 已经不存在了。这就产生了一个问题:我们在第 3 章中介绍的接口，即`**ITenantIdentifierStrategy**`，依赖于属于**系统的类。Web** ，所以我们需要弄清楚没有它我们怎么能达到同样的效果。OWIN 管道比 ASP.NET 管道简单得多；它遵循一种被称为[责任链](http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern)的模式，管道中的每个阶段(称为中间件)调用下一个阶段，最终在此之前和之后做一些事情。因此，如果我们想为其他人提供一些服务，我们需要在第一阶段做到这一点:

代码示例 86

```cs
          public class OwinHostHeaderTenantIdentifierStrategy : OwinMiddleware
         {
               public OwinHostHeaderTenantIdentifierStrategy(OwinMiddleware next):
                     base(next) { }

               public override Task Invoke(IOwinContext context)
               {
                     context.Request.Environment["Tenant"] =                    TenantsConfiguration.GetTenants().Single(x =>                    x.Name == context.Request.Host.Value.Split(':')
                                      .First().ToLower());

                     return this.Next.Invoke(context);
               }
         }

```

相当于 OWIN 的 [HttpContext](https://msdn.microsoft.com/en-us/library/system.web.httpcontext%28v=vs.110%29.aspx) 的是[low context](https://msdn.microsoft.com/en-us/library/microsoft.owin.iowincontext(v=vs.113).aspx)接口的实现:它有 [Request](https://msdn.microsoft.com/en-us/library/microsoft.owin.iowincontext.request(v=vs.113).aspx) 和 [Response](https://msdn.microsoft.com/en-us/library/microsoft.owin.iowincontext.response(v=vs.113).aspx) 对象，加上一些其他有用的方法和属性。在本例中，我们将由主机头标识的当前租户存储在一个环境变量(环境[集合)中。OWIN 没有规定如何去做，所以请随意去做。重要的是，这个中间件需要在任何其他可能需要它的东西之前插入管道:](https://msdn.microsoft.com/en-us/library/microsoft.owin.iowinrequest.environment%28v=vs.113%29.aspx)

代码示例 87

```cs
          public static class Startup
         {
               public static void Configuration(IAppBuilder builder)
               {
                     builder.UseWebApi(new HttpConfiguration());
                     builder.UseStaticFiles();
                     builder.UseDefaultFiles();
                     //rest goes here
                     builder.Use<MultitenancyMiddleware>();
                     builder.Use<OwinHostHeaderTenantIdentifierStrategy>();
                     //rest goes here
               }
         }

```

## 单元测试

为了对 OWIN 设置进行单元测试，我们可能需要注入几个属性，例如当前主机，这样它就可以被主机头策略的实现捕获:

代码示例 88

```cs
          public static void Setup(this IOwinContext context)
         {
               context.Request.Host = new HostString("abc.com");
         }

```

其他策略不需要任何特别的设置。