中间件用于配置到 Web 应用程序的请求管道中处理请求和相应。
我们可以通过 Run 、Map 、Use 这三个扩展方法配置请求委托。可以指定单个请求委托为匿名内联方法,也可以是一个可重用的类中的定义。这些可重用的类或者匿名方法被称作中间件。
Run
public class Startup
{
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
}
}
这是 Startup.cs 中的一段代码,在此 app.Run 在管道中回应了请求。
Use
多个中间件可以通过 app.Use 链接,在中间件中通过 next 参数控制请求是否要传递到下一个中间件。
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
// Do work that doesn't write to the Response.
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from 2nd delegate.");
});
}
}
中间件被添加到 Configure
中的顺序定义了他被调用的顺序,它对应用程序的安全性、性能和功能至关重要,每个中间件都可以在执行操作之前或之后来决定不将请求传递给下一个中间件。
public class Startup
{
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
}
}
如上,通过 env.IsDevelopment() 判断,表示在开发模式下添加 app.UseDeveloperExceptionPage() 中间件来处理程序异常,当异常发生时,它会直接返回异常信息,不再将请求向下传递。
Map
如需要请求指定请求路径,可通过 app.Map 配置基于路径的管道请求,用于扩展管道分支。
public class Startup
{
private static void HandleMapTest1(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 1");
});
}
private static void HandleMapTest2(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 2");
});
}
public void Configure(IApplicationBuilder app)
{
app.Map("/map1", HandleMapTest1);
app.Map("/map2", HandleMapTest2);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate. <p>");
});
}
}
使用以上的代码,显示了如下请求和响应:
localhost:1234 > Hello from non-Map delegate.
localhost:1234/map1 > Map Test 1
localhost:1234/map2 > Map Test 2
localhost:1234/map3 > Hello from non-Map delegate.
Map 支持嵌套,例如:
app.Map("/level1", level1App => {
level1App.Map("/level2a", level2AApp => {
// "/level1/level2a"
//...
});
level1App.Map("/level2b", level2BApp => {
// "/level1/level2b"
//...
});
});
Map 还支持多个领域,例如:
app.Map("/level1/level2", HandleMultiSeg);
ASP.Net Core 内置的中间件
- Authentication:提供验证支持。
- CORS:配置跨源资源共享。
- Response Caching:支持缓存响应。
- Response Compression:支持压缩响应。
- Routing:定义和约束路由请求。
- Session:提供了用于管理用户会话的支持。
- Static Files:支持提供静态文件和目录浏览。
- URL Rewriting Middleware:支持重写url和重定向请求。
开发中间件
开发一个中间件来查看访问请求IP地址
public class Startup
{
private readonly ILogger _logger;
public Startup(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<Startup>();
}
public void Configure(IApplicationBuilder app)
{
app.Use((context, next) =>
{
_logger.LogInformation("IP: " + context.Connection.RemoteIpAddress.ToString());
// 调用下一个中间件
return next();
});
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
}
}
中间件通常封装在一个类和暴露一个扩展方法,例如:
public class RequestIPMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
public RequestIPMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
{
_next = next;
_logger = loggerFactory.CreateLogger<RequestIPMiddleware>();
}
public async Task Invoke(HttpContext context)
{
_logger.LogInformation("IP2: " + context.Connection.RemoteIpAddress.ToString());
await _next.Invoke(context);
}
}
public static class RequestIPMiddlewareExtensions
{
public static IApplicationBuilder UseRequestIP(this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestIPMiddleware>();
}
}
通过如下代码调用:
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.UseRequestIP();
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
}
}