上一回合中,我们讲解了Linux.NET面对OWIN需要做出的准备,以及介绍了如何将两个支持OWIN协议的框架:SignalR以及NancyFX以OwinHost的方式部署到Linux.NET当中。这一章,我们将对框架与OwinHost之间怎么通过OWIN协议作出解析。

本章我们将讨论学习:

  (1)、连接两世界之门——“Middleware“

  (2)、转动大门的钥匙,打开无尽的财宝

  (3)、适配器?转换插头

相关示例代码,可以点击这里进行下载。


1、充当”门“的”Middleware“

英文名”Middleware“,中文名”中间件“,要了解什么是Middleware,我们先看看OWIN协议中的分层。

上图为OWIN分层的一个简图。最下的一层是我们的操作系统,Linux、Windows、Unix、Mac或其他;对上一层则是运行于操作系统中的OwinHost;再往上一层也就是紫色那层是基于OWIN协议建立的基础框架;而最顶层则是我们基于这些OWIN协议的框架所诞生的应用程序(直接操作OWIN字典的暂不记录在图中)。

抛开最顶和最底两层不管,当用户从客户端发起一请求,经过漫长的网络,到达目标主机时,请求将被并且仅能被OwinHost捕获,因为只有OwinHost在持续的不断监听端口。虽然请求已经被OwinHost捕获,但是OwinHost并没有能力对这个刚捕获的请求做出处理(这里特指需要经过OWIN框架及相关应用程序处理的请求)即使它知道自身有请求需要处理。

同样的,我们再把目光转到OWIN框架,它是我们的”处理中枢“,它能够对我们把我们的输入通过适当的计算之后把正确的答案输出来,但是它也有一个缺点,那就是它自身没有办法收集”相关信息“,也就是它自己并不能产生出”输入“。

这就好比人的大脑与其他器官,OWIN框架是我们的”大脑“,OwinHost则是我们的”器官“,没有了大脑我们的其他器官也无法正常运行(当然咯,有点功能不需要大脑,就像有些OwinHost处理静态资源不需要经过OWIN框架一样),没有了其他“器官”的支持“大脑”也无法发挥作用甚至会死亡(没有宿主,OWIN框架也无法运行)。

因此,我们需要有相应的“神经”来连通我们的“器官”与“大脑”之间的通信。而Middleware发挥的就是这种作用,它是连接OwinHost与OWIN框架的门,OwinHost把捕获到的请求通过自身的处理后通过这扇门推送到OWIN框架中;而OWIN框架也自己对请求计算后得出的响应通过这扇门返回到OwinHost中,再由OwinHost推送到用户手上。

而事实上,Middleware作为一扇连接OwinHost与OWIN框架的门,让这两个世界得以交流以外,还发挥着另外一个作用,那就是规定了统一的信息出入口,所有的请求响应均只能够通过这扇门传递,这或者可以更方便的对一些敏感信息、恶意代码之流的数据进行拦截与过滤。

2、转动我们手中的钥匙

正如上一节中最后所讲到的一样,Middleware作为OWIN框架与OwinHost的唯一通道,这意味着无论是SignalR、NancyFX、Webapi、FubuMVC或是其他,它们所站立的起点高度都是一致的,我们只要把能握住Middleware,就相当于把握住了大门的钥匙,我们也可以做出我们自己的框架出来。这也是我在上一回合中所提到OWIN协议给我们带来的好处中的第二点:“它给鼓励了一批人把自己的想法变成现实”。

本节我们将简述如何直接操作OWIN字典,直接和OwinHost进行通信。

首先我们需要在Visual Studio中建立我们的项目,然后通过NuGet获得OWIN:

然后我们新建一个类,并以它作为我们的Middleware:

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
namespace Demo1
{
using AppFun = Func<IDictionary<string, object>, Task>;
public class MyMiddleware
{
private readonly AppFun _env; public MyMiddleware(AppFun env)
{
if (env == null) throw new ArgumentNullException("OWIN环境参数为空");
this._env = env;
} public Task Invoke(IDictionary<string, object> env)
{
var responseBody = "Linux.NET 学习手记(8)&nbsp; --小蝶惊鸿";
var responseBodyBytes = Encoding.UTF8.GetBytes(responseBody);
((IDictionary<string, string[]>)env["owin.ResponseHeaders"]).Add("Content-Type", new string[] { "text/html; charset=utf-8" });
((Stream)env["owin.ResponseBody"]).Write(responseBodyBytes, , responseBodyBytes.Length);
return this._env(env);
}
}
}

MyMiddleware

这里要对代码进行一番的解析:
  (1)、这是我们的Middleware,所有来自于OwinHost的请求数据以及OWIN框架响应的数据都要通过这个类来进行统一中转处理。  

  (2)、IDictionary<string, object>实则为OWIN字典,里面包含了基于OWIN协议的用于OwinHost与OWIN框架之间通信的数据信息。

  (3)、程序启动时,OwinHost会先实例化这个类(实则调用Startup中的Configuration,然后实例化这个类,稍后我们会对此进行讲述),继而执行这个类的构造函数对Environment(也就是那个env)进行初始化。

  (4)、每次OwinHost捕获到请求之后,会调用Invoke,OWIN字典会携带请求进入该方法,程序处理完成之后,OWIN字典则会携带OWIN框架的响应离开该方法。

创建好我们的Middleware之后,我们需要在项目的根目录新建一个名为“Startup”的类,并在此类里面创建一个名为“Configuration”的方法。

namespace Demo1
{
using Owin;
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Use(typeof(MyMiddleware)); }
}
}

Startup.cs

这里也要为这个类作出一番解析:
OwinHost尝试驱动OWIN框架时,它会尝试寻找Startup,并激活里面的Configuration,继而激活我们自定义的Middleware。OwinHost激活我们的Middleware之后,OwinHost与OWIN框架之间就建立了连接,连接这两个世界的“门”也就打开了。

在示例代码中,Demo1为讲解如何通过简单的操作OWIN字典获取并返回我们想要输出的结果。

Demo2则是模拟ASP.NET MVC的路由功能,OwinHost激活Startup时,程序会对自身的程序集进行反射,找出所有以“Controller”结尾的类,并把里面的方法注册到路由字典中。当有来自于用户的请求,程序则会自动的拆解URL并在路由字典中判断是否存在改页面,存在则继而激活相应的方法(Action),不存在则导向到404页面。其效果如下图所示:

成功的路由导向到Home/Index 页面

访问一个不存在的地址,路由导向到一个404的小动画。

事实上,由于我们是基于OWIN协议直接操作OWIN字典所诞生的小Demo,因此我们是可以以一种无障碍的方式直接将项目发布到Linux.NET中运行。

3、充当转换插头角色的适配器

可能有细心而又爱动脑筋的读者不禁问到,关于那两个Demo(也能泛指其他所有的OWIN框架),OwinHost已经有了(Katana或者Jexus或其他),Middleware也由我们自行提供,不是OwinHost就可以与OWIN框架之间作出通信了吗?上一回合中所出现的适配器又是怎么回事?为什么没有见到Windows版的适配器?

在解析这个之前,我先上一张能够很恰当比喻适配器的图片:

这是我随手从网上找来的图片,用过它的读者很容易就能够分辨出来它是一个转换插头,它能够把各种类型的原插口转换成通用的插口。对的,没错,如果以简单的方式来理解,适配器所起的所用正式OwinHost与OWIN框架之间的转换插头,它把OwinHost中所提供的原始数据格式化成OWIN字典供OWIN框架使用。这就是简单的理解方式。

更深入的方式来理解,适配器发挥着两个重要的作用,除了简单理解中所讲述的作用以外,它还充当着让OwinHost成功驱动Startup并激活Configuration的关键。有兴趣的读者可以打开Jexus针对于OWIN框架的适配器,你会发现原来它也是通过反射寻找Startup类并激活里面的Configuration来创建Middleware并建立连接的,了解了这一点之后,我们可以通过修改适配器的源码来更改OwinHost尝试驱动OWIN框架时最先激活的类,我们可以根据自己的爱好把“Startup”这个名字改为“Breakdown”、“Sunday”或者“ILoveChina”甚至“ILoveXiaodiejinghong”,也可以把“Configuration”改为其他……总之你喜欢的。

至于为何Katana没有适配器,我这里只能说:“可能已经内置了吧”(具体还需要各位读者查看源码,我没有查看过,因此没有发言权)。


好的,两回合文章我们简单的认知了一些关于OWIN的事情,OWIN作为微软提出一套重要协议具有重大的战略意义。不多说了,我们下回再见吧。谢谢。

Linux.NET学习手记(8)的更多相关文章

  1. Linux.NET学习手记(7)

    前一篇中,我们简单的讲述了下如何在Linux.NET中部署第一个ASP.NET MVC 5.0的程序.而目前微软已经提出OWIN并致力于发展VNext,接下来系列中,我们将会向OWIN方向转战. 早在 ...

  2. 关于《Linux.NET学习手记(8)》的补充说明

    早前的一两天<Linux.NET学习手记(8)>发布了,这一篇主要是讲述OWIN框架与OwinHost之间如何根据OWIN协议进行通信构成一套完整的系统.文中我们还直接学习如何直接操作OW ...

  3. Linux.NET学习手记(6)

    各位读者大家好,好长一段时间没有更新文章了,自从参加工作之后,每天等待去做的工作没完没了,个人的时间也变得奢侈起来,今后要尽量从中脱身,抽更多的时间来完成自己想做的事情(希望如此). 言归正传,上一回 ...

  4. Linux.NET实战手记—自己动手改泥鳅(上)

    各位读者大家好,不知各位读者有否阅读在下的前一个系列<Linux.NET 学习手记>,在前一个系列中,我们从Linux中Mono的编译安装开始,到Jexus服务器的介绍,以及如何在Linu ...

  5. Linux LVM学习总结——扩展卷组VG

    Linux服务器由于应用变更或需求的缘故,有可能出现分区空间不足的情况,此时往往需要进行扩容(要增加分区的空间),而采用LVM的好处就是可以在不需停机的情况下可以方便地调整各个分区大小.如下所示,分区 ...

  6. linux的学习记录随笔

    为什么学习linux 因为操作系统是一种介质,你要接触其中的东西,首先必须要有介质,而linux在服务器端是老大哥的地位,所以呢,学习linux吧. 学习的方式 可以看视频 imooc.百度传课.网易 ...

  7. Linux LVM学习总结——创建卷组VG

    在Linux平台如何创建一个卷组(VG)呢?下面简单介绍一下卷组(VG)的创建步骤.本文实验平台为Red Hat Enterprise Linux Server release 6.6 (Santia ...

  8. 别出心裁的Linux命令学习法

    别出心裁的Linux命令学习法 操作系统操作系统为你完成所有"硬件相关.应用无关"的工作,以给你方便.效率.安全.操作系统的功能我总结为两点:管家婆和服务生: 管家婆:通过进程.虚 ...

  9. EF框架学习手记

    转载: [ASP.NET MVC]: - EF框架学习手记 1.EF(Entity Framework)实体框架EF是ADO.NET中的一组支持开发面向数据的软件应用程序的技术,是微软的一个ORM框架 ...

随机推荐

  1. JS调用Android、Ios原生控件

    在上一篇博客中已经和大家聊了,关于JS与Android.Ios原生控件之间相互通信的详细代码实现,今天我们一起聊一下JS调用Android.Ios通信的相同点和不同点,以便帮助我们在进行混合式开发时, ...

  2. 使用Zabbix监控Oracle数据库

    Orabbix介绍 监控Oracle数据库我们需要安装第三方提供的Zabbix插件,我们先测试比较有名的Orabbix,http://www.smartmarmot.com/product/orabb ...

  3. AFNetworking 3.0 源码解读(九)之 AFNetworkActivityIndicatorManager

    让我们的APP像艺术品一样优雅,开发工程师更像是一名匠人,不仅需要精湛的技艺,而且要有一颗匠心. 前言 AFNetworkActivityIndicatorManager 是对状态栏中网络激活那个小控 ...

  4. JS继承之寄生类继承

    原型式继承 其原理就是借助原型,可以基于已有的对象创建新对象.节省了创建自定义类型这一步(虽然觉得这样没什么意义). 模型 function object(o){ function W(){ } W. ...

  5. Http请求

    HTTP报文是面向文本的,报文中的每一个字段都是一些ASCII码串,各个字段的长度是不确定的.HTTP有两类报文:请求报文和响应报文. 请求报文 一个HTTP请求报文由请求行(request line ...

  6. 设计模式C#合集--工厂方法模式

    简单工厂,代码: public interface ISpeak { public void Say(); } public class Hello : ISpeak { public void Sa ...

  7. Android程序中--不能改变的事情

    有时,开发人员会对应用程序进行更改,当安装为以前版本的更新时出现令人惊讶的结果 - 快捷方式断开,小部件消失或甚至根本无法安装. 应用程序的某些部分在发布后是不可变的,您可以通过理解它们来避免意外. ...

  8. docker4dotnet #2 容器化主机

    .NET 猿自从认识了小鲸鱼,感觉功力大增.上篇<docker4dotnet #1 前世今生&世界你好>中给大家介绍了如何在Windows上面配置Docker for Window ...

  9. MySQL全文索引 FULLTEXT索引和like的区别

    1.概要 InnoDB引擎对FULLTEXT索引的支持是MySQL5.6新引入的特性,之前只有MyISAM引擎支持FULLTEXT索引.对于FULLTEXT索引的内容可以使用MATCH()-AGAIN ...

  10. 关于Hadoop用户体系的设想(胡思乱想)

    关于Hadoop的用户体系设计设想 Hadoop并没有一个完整的用户体系,其权限控制的对象,主要是Linux的其它用户(即非安装Hadoop的用户),控制方式也和Linux的文件权限很像,目前权限控制 ...