ASP.NET CORE基础教程(二)-中间件
中间件概述
所谓中间件就是嵌入到应用中用来处理请求和响应的软件。在管道中每一个元件都能够选择是否把请求传递给下一个元件,同时能在下一个元件被调用前后执行相应的操作。此时相应的请求委托便会在管道中建立用来响应http请求。
通过在 IApplicationBuilder实例中使用Run,Map,Use扩展方法能够配置请求委托,当然了IApplicationBuilder一定是在startup的configure中实例的才行。单个请求可以被指定为匿名方法(叫做内嵌中间件),或者它可以在可重用类中定义,这些可重复类以及内嵌匿名方法就被叫做中间件或者中间件元件。请求管道中的每一个中间件都需要调用下一个中间件,当然了,他也可以在适当的情况下短路自己,不调用下一个中间件。
通过 IApplicationBuilder创建中间件管道
ASP.NET CORE请求管道由一些列请求委托组成,执行顺序从前到后,依次执行,其流程图如下(微软官方图)
如图所示,每一个中间件可以在调用下一个之前或之后执行操作。中间件可以选择不把请求传递给下一个中间件,也就是“短路请求管道”,(为了避免不必要的工作量,有时候需要使用”短路“)。比如静态文件中间件可以返回静态文件的请求,并对管道的其余部分进行短路。其中异常处理中间件需要先调用,只有这样他才能够在后续过程中捕获异常。
下面是一个最简单的中间件,不包括任何实际的请求,能够响应所有http请求。代码如下
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Hello, World!");
});
}
}
你可以通过使用app.use来调用一系列请求委托,其中参数next表示下一个请求委托。当你不掉用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.");
});
}
}
注意
不要在请求已经发送给客户时短路管道,因为任何在HttpResponse响应发送以后的改变均会导致系统异常。
顺序
在Configure中添加中间件的顺序决定了应用处理请求的顺序,为了逻辑上的正确,推荐添加中间件顺序为:
- 异常处理
- 静态文件付无
- 认证
- MVC
public void Configure(IApplicationBuilder app)
{
app.UseExceptionHandler("/Home/Error"); // Call first to catch exceptions
// thrown in the following middleware.
app.UseStaticFiles(); // Return static files and end pipeline.
app.UseIdentity(); // Authenticate before you access
// secure resources.
app.UseMvcWithDefaultRoute(); // Add MVC to the request pipeline.
}
上面代码中app.UseExceptionHandler是管道中的第一个中间件,所以他可以捕获后续应用的所有异常。
然后是静态文件中间件,他可以不通过其他中间件处理请求和短路管道。静态文件中间件不需要认证,因此只要是在网站根目录(wwwroot)下的文件都可以访问。
更多查看另一篇教程-处理静态文件。
如果一个请求没有被静态文件中间件处理那么他就会被传递给认证中间件 (app.UseIdentity)。只有当MVC选择了某个控制器并执行了某个操作后认证才能够被调用。
Run,Map,Use
应用通过Run,Map,Use配置HTTP请求管道。
其中Run用来短路中间件,通常在中间件管道最后调用run方法。
Mapxxx通常用来使请求管道分支。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>");
});
}
}
一旦map被使用,匹配出来的来路径部分会从HttpRequest.Path中移除,同时添加到HttpRequest.PathBase中。
编译中间件
asp.net core自带如下中间件:
- Authentication:提供认证支持
- CORS:配置资源跨域共享
- Response Caching:提供响应缓存支持
- Response Compression:提供响应压缩支持
- Routing:提供路由支持
- Session:提供Session支持
- Static Files:提供静态文件服务和路径浏览付无
URL Rewriting Middleware:URL重写和请求重定向
自定义中间件
中间件一般定义在类里面,对外提供扩展方法。下面的例子展示了通过中间件设置字段的功能。
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Use((context, next) =>
{
var cultureQuery = context.Request.Query["culture"];
if (!string.IsNullOrWhiteSpace(cultureQuery))
{
var culture = new CultureInfo(cultureQuery);
CultureInfo.CurrentCulture = culture;
CultureInfo.CurrentUICulture = culture;
}
// Call the next delegate/middleware in the pipeline
return next();
});
app.Run(async (context) =>
{
await context.Response.WriteAsync(
$"Hello {CultureInfo.CurrentCulture.DisplayName}");
});
}
}
在浏览器中输入http://localhost:xxxx/?culture=no即可测试,其中xxxx表示你的应用端口号。
以下代码把委托放到了类中。
using Microsoft.AspNetCore.Http;
using System.Globalization;
using System.Threading.Tasks;
namespace Culture
{
public class RequestCultureMiddleware
{
private readonly RequestDelegate _next;
public RequestCultureMiddleware(RequestDelegate next)
{
_next = next;
}
public Task Invoke(HttpContext context)
{
var cultureQuery = context.Request.Query["culture"];
if (!string.IsNullOrWhiteSpace(cultureQuery))
{
var culture = new CultureInfo(cultureQuery);
CultureInfo.CurrentCulture = culture;
CultureInfo.CurrentUICulture = culture;
}
// Call the next delegate/middleware in the pipeline
return this._next(context);
}
}
}
下面的扩展方法通过IApplicationBuilder使用了该中间件。
using Microsoft.AspNetCore.Builder;
namespace Culture
{
public static class RequestCultureMiddlewareExtensions
{
public static IApplicationBuilder UseRequestCulture(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestCultureMiddleware>();
}
}
}
以下代码是在configure中调用该中间件。
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.UseRequestCulture();
app.Run(async (context) =>
{
await context.Response.WriteAsync(
$"Hello {CultureInfo.CurrentCulture.DisplayName}");
});
}
}
中间件应该遵循显示依赖原则,也就是说把依赖提供在构造函数中。中间件只要创建,在整个应用的生命周期里都是好使的。
好了,以上就是本片教程的内容,接下来的教程是
- ASP.NET CORE基础教程(三)-静态文件