起因
从Asp.Net(Webform/Mvc/Api)到Asp.Net Core不同就是请求管道换成中间件,在Asp.Net WebForm到MVC请求管道(底层)变化不是很大.看Asp.Net管道可以参考这篇很早之前在博客园写的博客:
重新认识Asp.Net管道模型
中间件是一种装配到应用管道以处理请求和响应的软件
作用:
- 选择是否将请求传递到管道中的下一个组件
- 可在管道中的下一个组件前后执行工作
官方文档中的关于中间件的执行图:
第一个中间件
在Asp.Net Core Web程序中,在Startup类Configure方法增加以下代码:
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("hello kestrel,hello asp.net core \n");
});
app.Use(next =>
{
Console.WriteLine("1");
return async c =>
{
await c.Response.WriteAsync("kestrel exec middleware start 1 \n");
await next.Invoke(c);
await c.Response.WriteAsync("kestrel exec middleware end 1 \n");
};
});
app.Use(next =>
{
Console.WriteLine("2");
return async c =>
{
await c.Response.WriteAsync("kestrel exec middleware start 2 \n");
await next.Invoke(c);
await c.Response.WriteAsync("kestrel exec middleware end 2 \n");
};
});
app.Use(next =>
{
Console.WriteLine("3");
return async c =>
{
await c.Response.WriteAsync("kestrel exec middleware start 3 \n");
await c.Response.WriteAsync("kestrel exec middleware end 3 \n");
};
});
查看Kestrel启动后的打印顺序:
在浏览器中访问: http://localhost:5000
控制台的顺序和在浏览器的结果,是相反的.为什么是相反的? 带着好奇心我们去看看源码是什么样的.
github上ApplicationBuilder地址为:https://github.com/dotnet/aspnetcore/blob/v3.1.0/src/Http/Http/src/Builder/ApplicationBuilder.cs
private readonly IList<Func<RequestDelegate, RequestDelegate>> _components = new List<Func<RequestDelegate, RequestDelegate>>();
public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
{
_components.Add(middleware);
return this;
}
public IApplicationBuilder New()
{
return new ApplicationBuilder(this);
}
public RequestDelegate Build()
{
RequestDelegate app = context =>
{
var endpoint = context.GetEndpoint();
var endpointRequestDelegate = endpoint?.RequestDelegate;
if (endpointRequestDelegate != null)
{
var message =
$"The request reached the end of the pipeline without executing the endpoint: '{endpoint!.DisplayName}'. " +
$"Please register the EndpointMiddleware using '{nameof(IApplicationBuilder)}.UseEndpoints(...)' if using " +
$"routing.";
throw new InvalidOperationException(message);
}
context.Response.StatusCode = StatusCodes.Status404NotFound;
return Task.CompletedTask;
};
foreach (var component in _components.Reverse())
{
app = component(app).Invoke();
}
return app;
}