1.1. 中间件原理
1.1.1. 什么是中间件
中间件是段代码用于处理请求和响应,通常多个中间件链接起来形成管道,由每个中间件自己来决定是否要调用下一个中间件。
1.1.2. 中间件执行过程
举一个示例来演示中间件的执行过程(分别有三个中间件:日志记录、权限验证和路由):当请求进入应用程序时,执行执行日志记录的中间件,它记录请求属性并调用链中的下一个中间件权限验证,如果权限验证通过则将控制权传递给下一个中间件,不通过则设置401 HTTP代码并返回响应,响应传递给日志中间件进行返回。
1.1.3. 中间件的配置
中间件配置主要是用Run、Map和Use方法进行配置;简单的中间件可以直接使用匿名方法就可以搞定,如下代码:
app.Run(async (context,next) => { await context.Response.WriteAsync("environment " + env); await next(); });
如果想重用中间件,就需要单独封装到一个类中进行调用。
1.2. 依赖注入中间件
在实际项目中,中间件往往需要调用其它对象的方法。所以要创建对象之间的依赖,由于ASP.NET Core 内置的依赖注入系统,写程序的时候可以创建更优雅的代码。
首先需要要在IOC容器中注册类,就是Startup类中的ConfigureServices方法中进行注册,ConfigureServices方法会在Configure方法之前被执行。以便在用中间件时所有依赖都准备好了。
现在有一个Greeter类:
public class Greeter : IGreeter { public string Greet() { return "Hello from Greeter!"; } } public interface IGreeter { string Greet(); }
第一步在ConfigureServices方法中进行注册
public void ConfigureServices(IServiceCollection services) { services.AddTransient<IGreeter, Greeter>(); }
笔者这里使用的是AddTransient进行注册,该方法在每次请求时创建该类的新实例。可以选择其它方法:AddSingleton,AddScoped或简单的Add(所有在幕后前使用)。整个DI系统在官方文档中有所描述。
在注册了依赖项后,就可以使用它们了。IApplicationBuilder实例允许在Configure方法中有一个RequestServices属性用于获取Greeter实例。由于已经注册了这个IGreeter接口,所以不需要将中间件与具体的Greeter实现相结合。
app.Use(async (ctx, next) => { IGreeter greeter = ctx.RequestServices.GetService<IGreeter>(); await ctx.Response.WriteAsync(greeter.Greet()); await next(); });
如果Greeter类有一个参数化的构造函数,它的依赖关系也必须在其中注册ConfigureServices。
中间件可以很容易解决依赖关系。可以向中间件构造函数添加其他参数:
public class MyMiddleware { private readonly RequestDelegate _next; private readonly IGreeter _greeter; public MyMiddleware(RequestDelegate next, IGreeter greeter) { _next = next; greeter = greeter; } public async Task Invoke(HttpContext context) { await context.Response.WriteAsync(_greeter.Greet()); await _next(context); } }
或者,可以将此依赖关系添加到Invoke方法中:
public async Task Invoke(HttpContext context, IGreeter greeter) { await context.Response.WriteAsync(greeter.Greet()); await _next(context); }
如果DI系统知道这些参数的类型,则在类被实例化时,它们将被自动解析。很简单!
1.3. Cookies和session中间件
1.3.1. Session
HTTP是一个无状态协议,Web服务器将每一个请求都视为独立请求。并且不保存之前请求中用户的值。
Session 状态是ASP.NET Core提供的一个功能,它可以在用户通应用访问网络服务器的时候保存和存储用户数据。由服务器上的字典和散列表组成,Session状态通过浏览器的请求中得到,Session的数据保存到缓存中。
ASP.NET Core通过包含Session ID的Cookie来维护会话状态,每个请求都会携带此Session ID。
在Microsoft.AspNetCore.Session包中提供的中间件用来管理Session状态。要启用Session中间件,Startup类里面需要做以下几个操作:
使用任何一个实现了IDistributedCache接口的服务来启用内存缓存,
设置AddSession回调,由于AddSession是在Microsoft.AspNetCore.Session包内实现的,所以必须在Nuget中添加Microsoft.AspNetCore.Session包
UseSession回调
具体示例代码如下:
using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using System; public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMvc(); // 添加一个内存缓存 services.AddDistributedMemoryCache(); services.AddSession(options => { // 设置10秒钟Session过期来测试 options.IdleTimeout = TimeSpan.FromSeconds(10); options.Cookie.HttpOnly = true; }); } public void Configure(IApplicationBuilder app) { app.UseSession(); app.UseMvcWithDefaultRoute(); } }
上面代码中IdleTimeout属性用来确定用户多久没有操作时丢弃Session。此属性和Cookie超时无关,通过Session中间件的每个请求都会重置超时时间。
1.3.2. Session保存到Redis中