Linux.NET学习手记(8)

上一回合中,我们讲解了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, 0, 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)

时间: 2024-08-27 12:12:17

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

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

早前的一两天<Linux.NET学习手记(8)>发布了,这一篇主要是讲述OWIN框架与OwinHost之间如何根据OWIN协议进行通信构成一套完整的系统.文中我们还直接学习如何直接操作OWIN字典,从OwinHost中拿数据进行直接使用. 不过文章发布之后,有朋友提示我,文章出了点细节上的问题,我细细度量之后,发现果然出了情况,并且还不是一个无关紧要的小问题,本打算把那篇文章下线,待修改好之后再重新上线,网友“王爷”提醒到,可以为文章专门写上一篇补充文,这样颇有手稿的感觉.考量之下我接受了王爷

Linux系统理解以及Linux系统学习心得

原创作品转载请注明出处  <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 作者:严哲璟 说一下我对Linux系统的理解 1.加载Linux内核准备:在加载基本输入输出模块(BIOS)之后,从磁盘的引导扇区读入操作系统的代码文件块到内存中,之后开始整个系统的初始化. 2.main.c的start_kernel函数是整个操作系统的入口,这也与Linux是基于C语言的特性相符,start_kernel具体做的动作很多

谈谈我对Linux系统学习的历程回顾

众所周知,Windows 和Linux 是目前最流行的2个操作系统.Windows系统适合普通用户,它的优势是图形化界面,简单易用,使用起来门槛很低,很容易上手,所以,windows占有了大多数普通用户群体.而Linux 被誉为黑客的操作系统,因其稳定和命令行操作的高效性而广泛用于开发工作,占有绝大多数开发者群体.当然,关于这两大系统的优缺点,这里就不再赘述,我主要想谈谈我的Linux的学习历程参考书籍<Linux就该这么学>和心得体会. Linux初体验 一年前,我还不知道Linux为何物,

Linux内核学习总结

李泽源 原创作品 转载请注明出处 <Linux内核分析>MOOC课程:http://mooc.study.163.com/course/USTC-1000029000 [Linux内核学习总结] 幸福来得很突然,这门课就快结束了…… 是时候,总结下这段时间的坚持了,也给同样对Linux内核有兴趣的你一个指南. 在这门课的学习过程中,按照老师的要求,每次课后都写一篇博文,这是一个很好的学习方式.每当写这些文章的时候,总是要多看几遍视频,再查查相关的资料,才能勉强凑成一个完整的文档:同时也把自己学

Linux内核学习总结(final)

Linux内核学习总结 符钰婧 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 这八周以来,我从拼不出来"Linux"这个词到知道了很多专有名词,也能大概了解Linux的工作机制,这一系列的进步都是一周周积累下来的.现在回过头来看,有种阳光总在风雨后的感觉,虽然这个比喻好像不太恰当. 闲话少说,接下来就进入这次的正题. 一.首先是对Linux操作系统的理解 1.操作系

Linux程序设计学习笔记----网络通信编程API及其示例应用

转载请注明出处, http://blog.csdn.net/suool/article/details/38702855. BSD Socket 网络通信编程 BSD TCP 通信编程流程 图为面向连接的Socket通信的双方执行函数流程.使用TCP协议的通信双方实现数据通信的基本流程如下 建立连接的步骤 1.首先服务器端需要以下工作: (1)调用socket()函数,建立Socket对象,指定通信协议. (2)调用bind()函数,将创建的Socket对象与当前主机的某一个IP地址和TCP端口

Linux 程序设计学习笔记----进程管理与程序开发(下)

转载请注明出处:http://blog.csdn.net/suool/article/details/38419983,谢谢! 进程管理及其控制 创建进程 fork()函数 函数说明具体参见:http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html 返回值:Upon successful completion, fork() shall return 0 to the child process and shall re

Linux 程序设计学习笔记----终端及串口编程基础之概念详解

转载请注明出处,谢谢! linux下的终端及串口的相关概念有: tty,控制台,虚拟终端,串口,console(控制台终端)详解 部分内容整理于网络. 终端/控制台 终端和控制台都不是个人电脑的概念,而是多人共用的小型中型大型计算机上的概念. 1.终端 一台主机,连很多终端,终端为主机提供了人机接口,每个人都通过终端使用主机的资源. 终端有字符哑终端和图形终端两种. 控制台是另一种人机接口, 不通过终端与主机相连, 而是通过显示卡-显示器和键盘接口分别与主机相连, 这是人控制主机的第一人机接口.

Linux 程序设计学习笔记----POSIX 文件及目录管理

转载请注明:http://blog.csdn.net/suool/article/details/38141047 问题引入 文件流和文件描述符的区别 上节讲到ANSI C 库函数的实现在用户态,流的相应资源也在用户空间,但无论如何实现最终都需要通过内核实现对文件的读写控制.因此fopen函数必然调用了对OS的系统调用.这一调用在LINUX下即为open, close, read, write等函数.这些都遵循POSIX标准. so,在linux系统中是如何通过POSIX标准实现对文件的操作和目