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) --小蝶惊鸿";
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)的更多相关文章
- Linux.NET学习手记(7)
前一篇中,我们简单的讲述了下如何在Linux.NET中部署第一个ASP.NET MVC 5.0的程序.而目前微软已经提出OWIN并致力于发展VNext,接下来系列中,我们将会向OWIN方向转战. 早在 ...
- 关于《Linux.NET学习手记(8)》的补充说明
早前的一两天<Linux.NET学习手记(8)>发布了,这一篇主要是讲述OWIN框架与OwinHost之间如何根据OWIN协议进行通信构成一套完整的系统.文中我们还直接学习如何直接操作OW ...
- Linux.NET学习手记(6)
各位读者大家好,好长一段时间没有更新文章了,自从参加工作之后,每天等待去做的工作没完没了,个人的时间也变得奢侈起来,今后要尽量从中脱身,抽更多的时间来完成自己想做的事情(希望如此). 言归正传,上一回 ...
- Linux.NET实战手记—自己动手改泥鳅(上)
各位读者大家好,不知各位读者有否阅读在下的前一个系列<Linux.NET 学习手记>,在前一个系列中,我们从Linux中Mono的编译安装开始,到Jexus服务器的介绍,以及如何在Linu ...
- Linux LVM学习总结——扩展卷组VG
Linux服务器由于应用变更或需求的缘故,有可能出现分区空间不足的情况,此时往往需要进行扩容(要增加分区的空间),而采用LVM的好处就是可以在不需停机的情况下可以方便地调整各个分区大小.如下所示,分区 ...
- linux的学习记录随笔
为什么学习linux 因为操作系统是一种介质,你要接触其中的东西,首先必须要有介质,而linux在服务器端是老大哥的地位,所以呢,学习linux吧. 学习的方式 可以看视频 imooc.百度传课.网易 ...
- Linux LVM学习总结——创建卷组VG
在Linux平台如何创建一个卷组(VG)呢?下面简单介绍一下卷组(VG)的创建步骤.本文实验平台为Red Hat Enterprise Linux Server release 6.6 (Santia ...
- 别出心裁的Linux命令学习法
别出心裁的Linux命令学习法 操作系统操作系统为你完成所有"硬件相关.应用无关"的工作,以给你方便.效率.安全.操作系统的功能我总结为两点:管家婆和服务生: 管家婆:通过进程.虚 ...
- EF框架学习手记
转载: [ASP.NET MVC]: - EF框架学习手记 1.EF(Entity Framework)实体框架EF是ADO.NET中的一组支持开发面向数据的软件应用程序的技术,是微软的一个ORM框架 ...
随机推荐
- ASP.NET Core应用针对静态文件请求的处理[4]: DirectoryBrowserMiddleware中间件如何呈现目录结构
和StaticFileMiddleware中间件一样,DirectoryBrowserMiddleware中间本质上还是定义了一个请求地址与某个物理目录之间的映射关系,而目标目录体现为一个FilePr ...
- [C#] C# 知识回顾 - 委托 delegate
C# 知识回顾 - 委托 delegate [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6031892.html 目录 What's 委托 委托的属性 ...
- 初学者看过来之JSON入门
1. 什么是JSON JSON---Javascript Object Notation,前两个单词大家应该都认识,最后一个notation,是"记号.标记法"的意思,连在一起,便 ...
- CRL快速开发框架系列教程五(使用缓存)
本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...
- ASP.NET加密和解密数据库连接字符串
大家知道,在应用程序中进行数据库操作需要连接字符串,而如果没有连接字符串,我们就无法在应用程序中完成检索数据,创建数据等一系列的数据库操作.当有人想要获取你程序中的数据库信息,他首先看到的可能会是We ...
- Kafka副本管理—— 为何去掉replica.lag.max.messages参数
今天查看Kafka 0.10.0的官方文档,发现了这样一句话:Configuration parameter replica.lag.max.messages was removed. Partiti ...
- App解读
一直不懂别人口中说的原生开发.混合式开发.今天突然看了一篇文章讲解的是什么叫做原生App?移动 Web App?混合APP?分享给大家. 原生App是专门针对某一类移动设备而生的,它们都是直接安装到设 ...
- Android之ContentProvider数据存储
一.ContentProvider保存数据介绍 一个程序可以通过实现一个ContentProvider的抽象接口将自己的数据完全暴露出去,而且ContentProvider是以类似数据库中表的方式将数 ...
- git命令行操作
从本地上传代码到仓库(假设已经建好仓库): 1.初始化: git init 2.将所有文件加入缓存区: git add * 3.提交当前工作空间的修改内容: git commit -m 'commit ...
- Atitit.cto 与技术总监的区别
Atitit.cto 与技术总监的区别 1. 核心区别1 2. Cto主要职责1 3. 如何提升到cto1 4. CTO五种基本的必备素质:2 5. 2 1. 核心区别 技术总监(Chief Tech ...