在Startup
中配置中间件请求管道,通常是这样的:
public void Configure(IApplicationBuilder app)
{
app.UseStaticFiles();
app.UseMvc(routes => {
routes.MapRoute(
name : "default",
template: "{controller=Home}/{action=Index}/{id}"
);
});
}
看看IStartupFilter
namespace Micorosft.AspNetCore.Hosting
{
public interface IStartupFilter
{
Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next);
}
}
IStartupFilter
接受一个泛型委托,生成一个泛型委托。
联想到,Startup
有一个实例方法,也返回泛型委托。
Startup _startup = new Startup();
Action<IApplicationBuilder> startupConfiture = _startup.Configure;
这里的startupConfiture
是可以给IStartupFilter
的Configure
方法的。
IStartupFilter filter1 = new StartupFilter();
Action<IApplicationBuilder> filterConfigure = filter1.Configure(startupConfigure);
IStartupFilter filter2 = new StartupFilter();
Action<IApplicationBuilder> filterConfigure2 = filter2.Configure(filterConfigure);
也就是说,从请求管道出来,通过IStartupFilter
把IApplicationBuilder
的生命延长了。
也可以这么理解,实际上,请求管道里的东东都实现了IStartupFilter
这个接口。
那么,IApplicationBuilder
是什么时候被调用的呢?是生成WebHost
的时候调用。
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build();
host.Run();
}
来看看Build
方法内部。
private RequestDelegate BuildApplication()
{
//工厂的方式生成IApplicationBuilder
IApplicationBuilder builder = builderFactory.CreateBuilder(Server.Features);
builder.ApplicationService = _applicationServices;
//从DI容器中取出服务
var startupFilters = _applicationServices.GetService<IEnumerable<IStartupFilter>>();
//一下,Startup中的Configure是对于请求管道而言的
Action<IApplicationBuilder> configure = _startup.Configure();
foreach(var filter in startupFilters.Reverse())
{
configure = filter.Configure(configure);
}
conigure(builder);
return builder.Build();//RequestDelegate就是请求管道本身
}
举个例子。
自定义一个中间件。
public class RequestServiceContainerMiddleware
{
private readonly RequestDelegate _next;
private IServiceScopeFactory _scopeFactory;
public RequestServiceContainerMiddleware(RequestDelegate next, IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
var existingFeatures = httpContext.Features.Get<IServiceProvidersFeature>();
if(existingFeatures?.RequestService!=null)
{
await _next.Invoke(httpContext);
return;
}
using(var feature = new RequestServiceFeature(_scopeFactory))
{
try
{
httpContext.Feature.Set<IServiceProviderFactory>(feature);
await _next.Invoke(httpContext);
}
catch{}
}
}
}
自定义IStartupFilter
public class AutoRequestServiceStartupFilter : IStartupFilter
{
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
{
return builder => {
builder.UseMiddleware<RequestServiceContainerMiddlware>();
next(builder);
};
}
}
AutoRequestServiceStartupFilter
无需注册,因为在Build
方法的时候就已经调用了所有实现IStartupFilter
接口的类。