今天推荐的这篇文章,讲述了如何实现和使用ASP.NET 5的中间件。

虽然在ASP.NET 5中,微软没有再强调OWIN(Open Web Interface for .NET)及其微软官方的OWIN实现Katana,但是其中涉及到一些原则和设计思想依然被ASP.NET 5以自己的方式所承载下来。比如,解耦服务器和应用程序的关系,应用程序委托,环境状态这些特性都能在ASP.NET 5中找到,且进行了更多加强。

那么什么是“中间件”呢?OWIN的规范中如此定义:“中间件即是在服务器和应用程序之间的管道传入的一些组件,为了特定目的监测、路由或编辑请求和回应消息。”这样的定义对于ASP.NET 5同样适用,或者可以被认为就是传统ASP.NET中的HTTP模块和处理器。某些中间件会完成一些中间任务,比如处理请求的验证、会话状态获取和持久保持、日志记录诸如此类;有一些中间件会最终生成回应消息。

要编写ASP.NET 5的中间件,有一种非常简单的方式,一段Lambda表达式就可以搞定:

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Run(async context =>
{
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("Hello ASP.NET 5!");
});
}
}

在上述代码中,传递给IApplicationBuilder.Run方法的是一个委托:RequestDelegate,其定义如下:

public delegate Task RequestDelegate(HttpContext context);

RequestDelegate等效于OWIN中的AppFunc。其接受状态信息HttpContext作为输入参数,返回一个Task。注意,此HttpContext非SystemWeb中的HttpContext,这是封装请求处理状态且对服务器透明(不特定于某种服务器)的上下文状态对象。而返回Task可以让调用者能够等待你的中间件完成工作后才进行后续任务执行。Run方法还有多个重载,以便让你注入相关依赖。

RequestDelegate同样也可以用于把中间件串接到执行管道中:

public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Use(next => async context =>
{
// do your stuff here before calling the next middleware
// in the pipeline await next.Invoke(context); // call the next guy // do some more stuff here as the call is unwinding
}); app.Run(async context =>
{
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("Hello ASP.NET 5!");
});
}
}

通过使用IApplicationBuilder.Use方法就可以把自己的中间件代码串到其他中间件的前面。其中next这个参数,就是下一个中间件的实例。其方法定义如下:

IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate

上面是用Lambda表达式来实现中间件,不过在实际开发当中涉及的代码都比较庞杂,所以最好是放到一个单独的类当中,并提供相应的测试代码。这样你可以单独编译打包分发这个中间件。文章作者Andrei Dzimchuk以实现HTTP Basic验证的一个简单中间件为例给出了如下代码:

public class BasicAuthentication
{
private readonly RequestDelegate next; public BasicAuthentication(RequestDelegate next)
{
this.next = next;
} public async Task Invoke(HttpContext context,
IAuthenticationService authenticationService)
{
try
{
var parser = new BasicAuthenticationParser(context);
var username = parser.GetUsername();
var password = parser.GetPassword(); await authenticationService.AuthenticateAsync(username, password);
await next(context);
}
catch (InvalidCredentialsException)
{
context.Response.StatusCode = 401;
context.Response.Headers.Add("WWW-Authenticate",
new[] { "Basic" });
}
}
}

这个类非常有意思。首先让我们非常奇怪的是,它没有继承任何基类或者实现任何接口。由此可知,微软开始在ASP.NET 5中推崇“约定胜于接口”的思想。我们只要实现一个接受RequestDelegate为参数的构造器,和一个方法签名同RequestDelegate一致的Invoke方法。当然本例中Invoke还接受了另外一个参数,这就是第二个奇怪的地方,我们能够在中间件里直接使用依赖注入。本例中就是注入了一个IAuthenticationService。

要使用编写好的中间件也是非常简单。首先引用一个依赖包“Microsoft.AspNet.RequestContainer ”,然后就可以使用Microsoft.AspNet.Http.Extensions的扩展方法IApplicationBuilder.UseMiddleware来加载中间件,如下:

builder.UseMiddleware<BasicAuthentication>();

通常,我们会把单独编写一个扩展类,来提供一个语义根据明确的扩展方法。最终Startup文件就可以编写为:

public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.UseBasicAuthentication(); app.Run(async context =>
{
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("Hello ASP.NET 5!");
});
}
}

到此,我们就完成了中间件的编写和使用。当然还需要完成注册IAuthenticationService这样的代码,这个就涉及到ASP.NET 5的依赖注入特性,有机会下次介绍。

原文地址在:http://dzimchuk.net/post/Understanding-ASPNET-5-middleware

理解ASP.NET 5的中间件的更多相关文章

  1. asp.net core mvc 中间件之路由

    asp.net core mvc 中间件之路由 路由中间件 首先看路由中间件的源码 先用httpContext实例化一个路由上下文,然后把中间件接收到的路由添加到路由上下文的路由集合 然后把路由上下文 ...

  2. 理解 ASP.NET Core: 处理管道

    理解 ASP.NET Core 处理管道 在 ASP.NET Core 的管道处理部分,实现思想已经不是传统的面向对象模式,而是切换到了函数式编程模式.这导致代码的逻辑大大简化,但是,对于熟悉面向对象 ...

  3. ASP.NET Core路由中间件[3]: 终结点(Endpoint)

    到目前为止,ASP.NET Core提供了两种不同的路由解决方案.传统的路由系统以IRouter对象为核心,我们姑且将其称为IRouter路由.本章介绍的是最早发布于ASP.NET Core 2.2中 ...

  4. 理解ASP.NET Core - [01] Startup

    注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 准备工作:一份ASP.NET Core Web API应用程序 当我们来到一个陌生的环境,第一 ...

  5. 理解ASP.NET Core - [02] Middleware

    注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 中间件 先借用微软官方文档的一张图: 可以看到,中间件实际上是一种配置在HTTP请求管道中,用 ...

  6. 理解ASP.NET Core - [04] Host

    注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 本文会涉及部分 Host 相关的源码,并会附上 github 源码地址,不过为了降低篇幅,我会 ...

  7. 理解ASP.NET Core - 路由(Routing)

    注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 Routing Routing(路由):更准确的应该叫做Endpoint Routing,负责 ...

  8. 理解ASP.NET Core - 文件服务器(File Server)

    注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 提供静态文件 静态文件默认存放在 Web根目录(Web Root) 中,路径为 项目根目录(C ...

  9. 理解ASP.NET Core - 日志(Logging)

    注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 快速上手 添加日志提供程序 在文章主机(Host)中,讲到Host.CreateDefault ...

随机推荐

  1. 锋利的jQuery-1--jQuery对象和DOM对象以及相互转化

    DOM对象: document object model,文档对象模型,每一份dom都可以表示成一棵树. 如下图所示,代码省略 在这颗dom树种,h3, p, ul以及ul的3个li子节点都是dom元 ...

  2. 使用SqlSessionTemplate实现数据库的操作

    EmployeeMapper.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE map ...

  3. linux 的终端字体色和背景色的修改方法(二)

     Linux终端下的颜色设置 2013-08-31 22:57:15 分类: LINUX   在 ANSI 兼容终端(例如 xterm.rxvt.konsole 等)里, 可以用彩色显示文本而不仅仅是 ...

  4. ExtJS学习之路第六步:深入讨论组件Panel用法

    Panel加载页面 var myPanel=Ext.create('Ext.panel.Panel',{ bodyPadding: "15px 10px 0 10px", titl ...

  5. Unity3d与iOS交互开发——接入平台SDK必备技能

    原地址:http://www.2cto.com/kf/201401/273337.html# 前言废话:开发手机游戏都知道,你要接入各种平台的SDK.那就需要Unity3d与iOS中Objective ...

  6. mysql启动报错(mac)

    $mysql ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) ...

  7. C语言register关键字—最快的关键字 ---------------转自http://blog.sina.com.cn/s/blog_6a1837e90101128k.html

    register:这个关键字请求编译器尽可能的将变量存在CPU内部寄存器中,而不是通过内存寻址访问,以提高效率.注意是尽可能,不是绝对.你想想,一个CPU 的寄存器也就那么几个或几十个,你要是定义了很 ...

  8. 从零开始写一个武侠冒险游戏-8-用GPU提升性能(3)

    从零开始写一个武侠冒险游戏-8-用GPU提升性能(3) ----解决因绘制雷达图导致的帧速下降问题 作者:FreeBlues 修订记录 2016.06.23 初稿完成. 2016.08.07 增加对 ...

  9. 彻底理解数字图像处理中的卷积-以Sobel算子为例

    彻底理解数字图像处理中的卷积-以Sobel算子为例 作者:FreeBlues 修订记录 2016.08.04 初稿完成 概述 卷积在信号处理领域有极其广泛的应用, 也有严格的物理和数学定义. 本文只讨 ...

  10. nginx(五)nginx与php的安装配置

    经过前面学习,对nginx有个大概的了解,来配置LNMP;只要是在系统安装过程中选择安装比较齐全的包,基本上系统都能满足安装要求,下面是我一个一个测试的,基本上全部安装所需的库文件,放心安装: [ro ...