在 OWIN 的最底层, 处理请求的函数定义的委托签名如下:
Func<IDictionary<string, object>, Task>
这个函数接受类型为 IDictionary<string, object>
的 OWIN 环境, 返回一个 Task
对象。
通常可以为这个函数起这样的别名:
using AppFunc = Func<
IDictionary<string, object>, // OWIN 环境
Task>; // 任务
于是,请求处理函数可以这样表示:
Func<AppFunc, Task>
中间件是 OWIN 中很重要的概念, 中间件介于 OWIN 服务器 与 OWIN 应用之间, 通过职责链模式处 理请求。
OWIN 为 Middleware 的注册提供了三个版本的重载函数, 可以分别适用于不同的场景:
public interface IAppBuilder {
IAppBuilder Use(object middleware, params object[] args);
}
public static class AppBuilderUseExtensions {
public static IAppBuilder Use<T>(
this IAppBuilder app,
params object[] args
);
public static IAppBuilder Use(
this IAppBuilder app,
Func<IOwinContext, Func<Task>, Task> handler
);
}
根据这三个方法, 添加 Middleware 有如下几种方式:
使用 Lambda 表达式可以创建简单的或者用于诊断的中间件, 比如:
app.Use(async (context, next) => {
Console.WriteLine("Middleware with Lambda begin.");
await next();
Console.WriteLine("Middleware with Lambda end.");
});
当然, Middleware 执行时可以不必等待下一个处理程序结束而直接返回, 比如:
app.Use(async (context, next) => {
Console.WriteLine("Middleware with Lambda begin.");
return Task.FromResult(0);
});
创建自定义 Middleware 类型是最通用的方式, 只要遵守 OWIN 的约定即可:
示例代码如下:
using AppFunc = Func<IDictionary<string, object>, Task>;
public class LogMiddleware {
private readonly AppFunc next;
public LogMiddleware(AppFunc next) {
this.next = next;
}
public async Task Invoke(IDictionary<string, object> env) {
Console.WriteLine("LogMiddleware Start.");
await next(env);
Console.WriteLine("LogMiddleware End.");
}
}
使用上面的中间件的代码如下:
app.Use<LogMiddleware>(/* 构造函数其它参数 */);
在运行时, OWIN 通过反射调用 LogMiddleware 的构造函数创建实例并调用 Invoke 方法。
当然,还可以直接使用 Middleware 的实例, 这样很适用于有 IoC 容器的场景, 同样, 只要符合 OWIN 的约定即可:
AppFunc
;Task
;示例代码如下:
using AppFunc = Func<IDictionary<string, object>, Task>;
public class InstanceMiddleware {
private AppFunc next;
public void Initialize(AppFunc next) {
this.next = next;
}
public async Task Invoke(IDictionary<string, object> env) {
Console.WriteLine("InstanceMiddleware Start.");
await next(env);
Console.WriteLine("InstanceMiddleware End.");
}
}
Middleware 实例可以这样使用:
var instance = new InstanceMiddleware();
/*
instance 后面可以添加 Initialize 方法的其它参数, 如果有 IoC 容器的话, 似乎就没什么
必要了
*/
app.Use(instance);
如果对上面的反射以及约定不感兴趣的话, 还可以使用 OwinMiddleware
基类, 该类型定义
如下:
public abstract class OwinMiddleware {
protected OwinMiddleware Next { get; set; }
protected OwinMiddleware(OwinMiddleware next) {
this.Next = next;
}
public abstract Task Invoke(IOwinContext context);
}
使用基类的话, 上面的 LogMiddleware 就要这样写了:
public class LogOwinMiddleware : OwinMiddleware {
public LogOwinMiddleware(OwinMiddleware next)
: base(next) {
}
public async override Task Invoke(IOwinContext context) {
Console.WriteLine("LogOwinMiddleware Start.");
await Next.Invoke(context);
Console.WriteLine("LogOwinMiddleware End.");
}
}
上面对 Middleware 的介绍比较全了, 如果要做 OWIN Middleware 开发的话, 可以从这几种方式 入手。
PS: 还有一种使用內联函数的方式, 也提一下, 但是个人不怎么推荐, 比如 Middleware 可以表示成:
Func<AppFunc // next process delegate,
AppFunc // this process delegate
>
使用起来是这样自的:
app.Use(new Func<AppFunc, AppFunc>(next => (async env => {
Console.WriteLine("Middleware with AppFunc begin.");
await next.Invoke(env);
Console.WriteLine("Middleware with AppFunc end.");
})));