正如上篇文章所述那样,OWIN在Web Server与Web Application之间定义了一套规范(Specs),意在解耦Web Server与Web Application,
从而推进跨平台的实现。若要真正使用OWIN规范,那么必须要对他们进行实现。目前有两个产品实现了OWIN规范——由微软主导的
Katana和第三方的Nowin。这篇文章,我主要关注还是Katana,由微软团队主导,开源到CodePlex上。
可以在Visual Studio中输入命令:git clone https://git01.codeplex.com/katanaproject来查看源代码。

在介绍Katana之前,我觉得有必要为大家梳理一下过去10几年前ASP.NET 发展历程。

ASP.NET 发展历程

ASP.NET Web Form

ASP.NET Web Form 在2002正式发布时,面向的开发者主要有两类:

  • 使用混合HTML标记和服务端脚本开发动态网站的ASP开发者,另外,ASP运行时抽象了底层的HTTP连接和Web Server,并为开发者提供了一系列的对象模型用于交互Http请求,当然也提供了额外的服务诸如Session、Cache、State等。
  • 开发WinForm的程序员,他们可能对HTTP和HTML一无所知,但熟悉拖控件的方式来构建应用程序。

为了迎合这两类开发者,ASP.NET Web Form通过使用沉重的ViewState来保存页面回传过程中的状态值,因为HTTP协议是无状态的,通过ViewState,使原本没有记忆的Http协议变得有记忆起来。这在当时是非常好的设计,能通过拖拽控件的形式快速开发Web,而不必过多的去关注底层原理。同时ASP.NET团队还为ASP.NET丰富了更多的功能、诸如:Session、Cache、Configuration等等。

这在当时无疑是成功的,ASP.NET的发布迅速拉拢了开发者,在Web开发中形成了一股新的势力,但同时也买下来一些隐患:

  • 所有的功能、特性都发布在一个整体框架上并且紧耦合核心的Web抽象库——System.Web
  • System.Web是.NET Framework的重要组成部分,这意味着要修复更新System.Web必须更新.NET Framework,但.NET Framework是操作系统的基础,为了稳定性往往不会频繁更新。
  • ASP.NET Framework (System.Web)紧耦合IIS
  • IIS只能运行在Windows系统

ASP.NET MVC

由于Web Form产生一大堆ViewState和客户端脚本,这对开发者来说慢慢变成一种累赘,因为我们只想产生纯净的HTML标记。所以开发者更想去主动控制而非被动产生额外HTML标记。

所以微软基于MVC设计模式推出了其重要的Web Framework——ASP.NET MVC Framework,通过Model-View-Control解耦了业务逻辑和表现逻辑,同时没有了服务器端控件,将页面的控制权完全交给了开发者。

为了快速更新迭代,通过Nuget来获取更新,故从.NET Framework中分离开了。

但唯一不足的是,ASP.NET MVC还是基于ASP.NET Framework(注:ASP.NET MVC 6已经不依赖System.Web),所以Web Application和Web Server依旧没有解耦。

ASP.NET Web API

随着时间的推移,一些问题开始暴露出来了,由于Web Server和Web Application紧耦合在一起,微软在开发独立、简单的Framework上越发捉襟见肘,这和其他平台下开源社区蓬勃发展形成鲜明对比,幸运的是,微软做出了改变,推出了独立的Web Framework ——ASP.NET Web API,他适用于移动互联网并可以快速通过Nuget安装,更为重要的是,他不依赖System.Web,也不依赖IIS,你可以Self-Host或者在其他Web Server部署。

Katana

随着Web API能够运行在自己的轻量级的宿主中,并且越来越多简单、模块化、专一的Framework问世,开发人员有时候不得不启动单独的进程来处理Web应用程序的各种组件(模块)、如静态文件、动态文件、Web API和Socket。为了避免进程扩散,所有的进程必须启动、停止并且独立进行管理。这时,我们需要一个公共的宿主进程来管理这些模块。

这就是OWIN诞生的原因,解耦成最小粒度的组件,然后这些标准化框架和组件可以很容易地插入到OWIN Pipeline中,从而对组件进行统一管理。而Katana正是OWIN的实现,为我们提供了丰富的Host和Server。

走进Katana的世界

Katana作为OWIN的规范实现,除了实现Host和Server之外,还提供了一系列的API帮助开发应用程序,其中已经包括一些功能组件如身份验证(Authentication)、诊断(Diagnostics)、静态文件处理(Static Files)、ASP.NET Web API和SignalR的绑定等。

Katana的基本原则

  • 可移植性:从HostàServeràMiddleware,每个Pipeline中的组件都是可替换的,并且第三方公司和开源项目的Framework都是可以在OWIN Server上运行,也就是说不受平台限制,从而实现跨平台。
  • 模块化:每一个组件都必须保持足够独立性,通常只做一件事,以混合模块的形式来满足实际的开发需求
  • 轻量和高效:因为每一个组件都是模块化开发,而且可以轻松的在Pipeline中插拔组件,实现高效开发

Katana 体系结构

Katana实现了OWIN的Layers,所以Katana的体系结构和OWIN一致,如下所示:

1.)Host :宿主Host被OWIN规范定义在第一层(最底层),他的职责是管理底层的进程(启动、关闭)、初始化OWIN Pipeline、选择Server运行等。

Katana为我们提供了3中选择:

  • IIS / ASP.NET :使用IIS是最简单和向后兼容方式,在这种场景中OWIN Pipeline通过标准的HttpModule和HttpHandler启动。使用此Host你必须使用System.Web作为OWIN Server
  • Custom Host :如果你想要使用其他Server来替换掉System.Web,并且可以有更多的控制权,那么你可以选择创建一个自定义宿主,如使用Windows Service、控制台应用程序、Winform来承载Server。
  • OwinHost :如果你对上面两种Host还不满意,那么最后一个选择是使用Katana提供的OwinHost.exe:他是一个命令行应用程序,运行在项目的根部,启动HttpListener Server并找到基于约束的Startup启动项。OwinHost提供了命令行选项来自定义他的行为,比如:手动指定Startup启动项或者使用其他Server(如果你不需要默认的HttpListener Server)。

2.)Server

Host之后的Layer被称为Server,他负责打开套接字并监听Http请求,一旦请求到达,根据Http请求来构建符合OWIN规范的Environment Dictionary(环境字典)并将它发送到Pipeline中交由Middleware处理。Katana对OWIN Server的实现分为如下几类:

  • System.Web:如前所述那样,System.Web和IIS/ASP.NET Host两者彼此耦合,当你选择使用System.Web作为Server ,Katana System.Web Server把自己注册为HttpModule和HttpHandler并且处理发送给IIS的请求,最后将HttpRequest、HttpResponse对象映射为OWIN环境字典并将它发送至Pipeline中处理。
  • HttpListener:这是OwinHost.exe和自定义Host默认的Server。
  • WebListener:这是ASP.NET vNext默认的轻量级Server,他目前无法使用在Katana中

3)Middleware

Middleware(中间件)位于Host、Server之后,用来处理Pipeline中的请求,Middleware可以理解为实现了OWIN应用程序委托AppFun的组件。

Middleware处理请求之后并可以交由下一个Pipeline中的Middleware组件处理,即链式处理请求,通过环境字典可以获取到所有的Http请求数据和自定义数据。Middleware可以是简单的Log组件,亦可以为复杂的大型Web Framework,诸如:ASP.NET Web API、Nancy、SignlR等,如下图所示:Pipeline中的Middleware用来处理请求:

4.)Application

最后一层即为Application,是具体的代码实现,比如ASP.NET Web API、SignalR具体代码的实现。

现在,我想你应该了解了什么事Katana以及Katana的基本原则和体系结构,那么现在就是具体应用到实际当中去了。

使用ASP.NET/IIS托管Katana-based应用程序

  • Visual Studio创建Web Application
  • Install-Package Microsoft.Owin.Host.SystemWeb

    添加Startup启动类

    • ASP.NET/IIS作为Host
    • System.Web作为Server

在Startup的Configuration方法中实现OWIN Pipeline处理逻辑,如下代码所示:

  1. public class Startup
  2.     {
  3.         public void Configuration(IAppBuilder app)
  4.         {
  5.             app.Run(context =>
  6.             {
  7.                 context.Response.ContentType = "text/plain";
  8.                 return context.Response.WriteAsync("Hello World");
  9.             });
  10.         }
  11.     }

app.Run方法将一个接受IOwinContext对象最为输入参数并返回Task的Lambda表达式作为OWIN Pipeline的最后处理步骤,IOwinContext强类型对象是对Environment Dictionary的封装,然后异步输出"Hello World"字符串。

细心的你可能观察到,在Nuget安装Microsoft.Owin.Host.SystemWeb程序集时,默认安装了依赖项Microsoft.Owin程序集,正式它为我们提供了扩展方法Run和IOwinContext接口,当然我们也可以使用最原始的方式来输出"Hello World"字符串,即Owin程序集为我们提供的最原始方式,这仅仅是学习上参考,虽然我们不会在正式场景下使用:

  1. using AppFunc = Func<IDictionary<string, object>, Task>;
  2.     public class Startup
  3.     {
  4.         public void Configuration(IAppBuilder app)
  5.         {
  6.             app.Use(new Func<AppFunc, AppFunc>(next => (env =>
  7.             {
  8.                 string text = "Hello World";
  9.                 var response = env["owin.ResponseBody"] as Stream;
  10.                 var headers = env["owin.ResponseHeaders"] as IDictionary<string, string[]>;
  11.                 headers["Content-Type"] = new[] { "text/plain" };
  12.                 return response.WriteAsync(Encoding.UTF8.GetBytes(text), 0, text.Length);
  13.             })));
  14.         }
  15.     }

使用自定义Host(self-host)托管Katana-based应用程序

使用自定义Host托管Katana应用程序与使用IIS托管差别不大,你可以使用控制台、WinForm、WPF等实现托管,但要记住,这会失去IIS带有的一些功能(SSL、Event Log、Diagnostics、Management…),当然这可以自己来实现。

  • 创建控制台应用程序
  • Install-Package Microsoft.Owin.SelfHost
  • 在Main方法中使用Startup配置项构建Pipeline并监听端口
  1. static void Main(string[] args)
  2.         {
  3.             using (WebApp.Start<Startup>("http://localhost:10002"))
  4.             {
  5.                 System.Console.WriteLine("启动站点:http://localhost:10002");
  6.                 System.Console.ReadLine();
  7.             }
  8.         }

使用自定义的Host将失去IIS的一些功能,当然我们可以自己去实现。幸运的是,Katana为我们默认实现了部分功能,比如Diagnostic,包含在程序集Microsoft.Owin.Diagnostic中。

  1. public void Configuration(IAppBuilder app)
  2.         {
  3.             app.UseWelcomePage("/");
  4.             app.UseErrorPage();
  5.             app.Run(context =>
  6.             {
  7.                 //将请求记录在控制台
  8.                 Trace.WriteLine(context.Request.Uri);
  9.                 //显示错误页
  10.                 if (context.Request.Path.ToString().Equals("/error"))
  11.                 {
  12.                     throw new Exception("抛出异常");
  13.                 }
  14.                 context.Response.ContentType = "text/plain";
  15.                 return context.Response.WriteAsync("Hello World");
  16.             });
  17.         }

在上述代码中,当请求的路径(Request.Path)为根目录时,渲染输出Webcome Page并且不继续执行Pipeline中的其余Middleware组件,如下所示:

如果请求的路径为Error时,抛出异常,显示错误页,如下所示:

使用OwinHost.exe托管Katana-based应用程序

当然我们还可以使用Katana提供的OwinHost.exe来托管应用程序,毫无疑问,通过Nuget来安装OwinHost。

如果你按照我的例子一步一步执行的话,你会发现不管使用ASP.NET/IIS托管还是自托管,Startup配置类都是不变的,改变的仅仅是托管方式。同理OwinHost也是一样的,但它更灵活,我们可以使用类库或者Web应用程序来作为Application。

  • 使用类库

类库作为Application,可以最小的去引用程序集,创建一个类库后,删除默认的Class1.cs,然后并且添加Startup启动项,这会默认像类库中添加Owin和Microsoft.Owin程序集的引用。

然后,使用Nuget来安装OwinHost.exe,如Install-Package OwinHost,注意它并不是一个程序集,而是.exe应用程序位于<solution root>/packages/OwinHost.(version)/tools文件夹。

因为类库不能直接运行,那么只能在它的根目录调用OwinHost.exe来托管,它将加载.\bin文件下所有的程序集,所以需要改变类库的默认输出,如下所示:

然后编译解决方案,打开cmd,键入如下命令:

如上图成功启动了宿主Host并且默认监听5000端口。

OwinHost.exe还提供自定义参数,通过追加-h来查看,如下所示:

既然类库不能直接运行,当然你也不能直接进行调试,我们可以附加OwinHost进程来进行调试,如下所示:

注:

我在使用OwinHost.exe 3.0.1时,Startup如果是如下情况下,它提示转换失败,不知是否是该版本的Bug。

  1. using AppFunc = Func<IDictionary<string, object>, Task>;
  2.    public class Startup
  3.    {
  4.        public void Configuration(IAppBuilder app)
  5.        {
  6.            //使用OwinHost.exe,报错,提示转换失败
  7.            app.Run(context=>context.Response.WriteAsync("Hello World"));
  8.            //使用OwinHost.exe 不报错
  9.            //app.Use(new Func<AppFunc, AppFunc>(next => (env =>
  10.            //{
  11.            // string text = "Hello World";
  12.            // var response = env["owin.ResponseBody"] as Stream;
  13.            // var headers = env["owin.ResponseHeaders"] as IDictionary<string, string[]>;
  14.            // headers["Content-Type"] = new[] { "text/plain" };
  15.            // return response.WriteAsync(Encoding.UTF8.GetBytes(text), 0, text.Length);
  16.            //})));
  17.        }
  18.    }

报错信息如下:

  • 使用Web Application

Web Application比类库使用起来轻松多了,你可以直接运行和调试,唯一比较弱的可能是它引用较多的程序集,你完全可以删掉,比如System.Web。

通过Nuget安装了OwinHost.exe之后,可以在Web中使用它,如下所示:

几种指定启动项Startup的方法

  • 默认名称约束:默认情况下Host会去查找root namespace下的名为Startup的类作为启动项。
  • OwinStartup Attribute:当创建Owin Startup类时,自动会加上Attribute 如:[assembly: OwinStartup(typeof(JKXY.KatanaDemo.OwinHost.Startup))]
  • 配置文件,如: <add key="owin:appStartup" value="JKXY.KatanaDemo.Web.StartupDefault" />
  • 如果使用自定义Host,那么可以通过WebApp.Start<Startup>("http://localhost:10002") 来设置启动项。
  • 如果使用OwinHost,那么可以通过命令行参数来实现,如下截图所示

启动项Startup的高级应用

启动项Startup支持Friendly Name,通过Friendly Name我们可以动态切换Startup。

比如在部署时,我们会有UAT环境、Production环境,在不同的环境中我们可以动态切换Startup来执行不同的操作。

举个栗子,我创建来两个带有Friendly Name的Startup,如下所示:

  • Production Startup
 [assembly: OwinStartup("Production", typeof(JKXY.KatanaDemo.Web.StartupProduction))]
namespace JKXY.KatanaDemo.Web
{
using AppFunc = Func<IDictionary<string, object>, Task>;
public class StartupProduction
{
public void Configuration(IAppBuilder app)
{
app.Run(context=>context.Response.WriteAsync("Production"));
}
}
}
  • UAT Startup
 [assembly: OwinStartup("UAT",typeof(JKXY.KatanaDemo.Web.StartupUAT))]

 namespace JKXY.KatanaDemo.Web
{
public class StartupUAT
{
public void Configuration(IAppBuilder app)
{
app.Run(context=>context.Response.WriteAsync("UAT"));
}
}
}
  • 根据Friendly Name使用配置文件或者OwinHost 参数来切换Startup
  <appSettings>
<add key="owin:appStartup" value="Production" />
</appSettings>

小结

花了好久才最终完成这篇博客,为大家讲解了Katana的世界,那么接下来我将继续OWIN & Katana之旅,探索Middleware的创建,谢谢大家支持。

ASP.NET MVC随想录——锋利的KATANA的更多相关文章

  1. ASP.NET MVC 随想录——开始使用ASP.NET Identity,初级篇(转)

    ASP.NET MVC 随想录——开始使用ASP.NET Identity,初级篇   阅读目录 ASP.NET Identity 前世今生 建立 ASP.NET Identity 使用ASP.NET ...

  2. ASP.NET MVC 随想录—— 使用ASP.NET Identity实现基于声明的授权,高级篇

    在这篇文章中,我将继续ASP.NET Identity 之旅,这也是ASP.NET Identity 三部曲的最后一篇.在本文中,将为大家介绍ASP.NET Identity 的高级功能,它支持声明式 ...

  3. ASP.NET MVC随想录——漫谈OWIN

    什么是OWIN OWIN是Open Web Server Interface for .NET的首字母缩写,他的定义如下: OWIN在.NET Web Servers与Web Application之 ...

  4. ASP.NET MVC 随想录——探索ASP.NET Identity 身份验证和基于角色的授权,中级篇

    在前一篇文章中,我介绍了ASP.NET Identity 基本API的运用并创建了若干用户账号.那么在本篇文章中,我将继续ASP.NET Identity 之旅,向您展示如何运用ASP.NET Ide ...

  5. ASP.NET MVC 随想录——开始使用ASP.NET Identity,初级篇

    在之前的文章中,我为大家介绍了OWIN和Katana,有了对它们的基本了解后,才能更好的去学习ASP.NET Identity,因为它已经对OWIN 有了良好的集成. 在这篇文章中,我主要关注ASP. ...

  6. ASP.NET MVC随想录——创建自定义的Middleware中间件

    经过前2篇文章的介绍,相信大家已经对OWIN和Katana有了基本的了解,那么这篇文章我将继续OWIN和Katana之旅——创建自定义的Middleware中间件. 何为Middleware中间件 M ...

  7. ASP.NET MVC 随想录

    http://www.cnblogs.com/OceanEyes/category/696137.html

  8. 锋利的KATANA

    锋利的KATANA 阅读目录 ASP.NET 发展历程 走进Katana的世界 使用ASP.NET/IIS托管Katana-based应用程序 使用自定义Host(self-host)托管Katana ...

  9. ASP.NET MVC 5 05 - 视图

    PS: 唉,这篇随笔国庆(2015年)放假前几天开始的,放完假回来正好又赶上年底,公司各种破事儿. 这尼玛都写跨年了都,真服了.(=_=#) 好几次不想写了都. 可是又不想浪费这么多,狠不下心删除.没 ...

随机推荐

  1. 关于DOS与cmd(windows系统)

    dos是计算机的最初期的操作系统,对电脑操作必须输入各种dos命令窗口,可以理解成运行计算机机器内部语言,知道编程吗?其实早期dos命令操作系统就是运行计算机内部的编程命令,因此操作人员都必须具有一定 ...

  2. C#基础系列——一场风花雪月的邂逅:接口和抽象类

    前言:最近一个认识的朋友准备转行做编程,看他自己边看视频边学习,挺有干劲的.那天他问我接口和抽象类这两个东西,他说,既然它们如此相像, 我用抽象类就能解决的问题,又整个接口出来干嘛,这不是误导初学者吗 ...

  3. 读书笔记---《火球:UML大战需求分析》

    书评 作为一本UML和需求分析的入门书来说还算可以,写的比较接地气,如果是做过很多项目的读者,很容易找到共鸣点. 美中不足:部分概念可能有错误,其中对于Component和Artifact的解释明显和 ...

  4. yii获取当前url和域名

    <?php //当前域名 echo Yii::app()->request->hostInfo; //除域名外的URL echo Yii::app()->request-> ...

  5. 软件开发学习笔记 <一> UML

    UML http://www.uml-diagrams.org http://www.umlchina.com/index.htm 统一建模语言(UML)始于1997年的一个OMG(对象管理组织)标准 ...

  6. jdbc-批量插入、批量删除、批量更新

    一.JDBC的批量插入 JDBC批量插入主要用于数据导入和日志记录因为日志一般都是先写在文件下的等.    我用Mysql5.1.5的JDBC driver 分别对三种比较常用的方法做了测试   方法 ...

  7. console.log((function f(n){return ((n > 1) ? n * f(n-1) : n)})(5))调用解析

    console.log((function f(n){) ? n * f(n-) : n)})()); 5被传入到函数,函数内部三元计算,5 > 1成立,运算结果是5*f(4),二次运算,5*4 ...

  8. 私有项目免费使用Git

    GitHub,私有项目是要收费了,如果想建立私有项目可以选择GitLab. GitLab注册地址:https://gitlab.com/users/sign_in 本机需要安装git,图形化的工具使用 ...

  9. [日常训练]yayamao的神题

    Description $yayamao$是数学神犇,一天他在纸上计算起了$1/P$, 我们知道按照模拟除法可以得到准确解,例如$1/7=0.(142857),1/10=0.1(0)$.$yayama ...

  10. Jstat PID not found

    解决步骤 删除/tmp/hsperfdata_{USER}文件夹,如果是root用户登录,即为/tmp/hsperfdata_root 通过chown.chmod命令保证执行jstat用户必定拥有对/ ...