Request請求進來,Middleware1=》Middleware2=》Middleware3,Response返回Middleware3=》Middleware2=》Middleware1
何為中間件?
1 public class Middleware 2 { 3 private readonly RequestDelegate _next; 4 5 public Middleware(RequestDelegate next) 6 { 7 _next = next; 8 } 9 10 public Task Invoke(HttpContext httpContext) 11 { 12 13 return _next(httpContext); 14 } 15 } 16 17 public delegate Task RequestDelegate(HttpContext context);
構造函數中接受一個RequestDelegate參數,invoke方法中接受HttpCointext參數。簡而言之就是Func<RequestDelegate,RequestDelegate>
中間件如何串聯?
查看源碼!
IApplicationBuilder.Use方法其實就是在往components里添加中間件。
public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
{
_components.Add(middleware);
return this;
}
IApplicationBuilder.Build方法,先將compoments集合反轉循環遍歷,把結果作為參數再傳給下一個中間件。
1 public RequestDelegate Build() 2 { 3 RequestDelegate app = context => 4 { 5 // If we reach the end of the pipeline, but we have an endpoint, then something unexpected has happened. 6 // This could happen if user code sets an endpoint, but they forgot to add the UseEndpoint middleware. 7 var endpoint = context.GetEndpoint(); 8 var endpointRequestDelegate = endpoint?.RequestDelegate; 9 if (endpointRequestDelegate != null) 10 { 11 var message = 12 $"The request reached the end of the pipeline without executing the endpoint: '{endpoint.DisplayName}'. " + 13 $"Please register the EndpointMiddleware using '{nameof(IApplicationBuilder)}.UseEndpoints(...)' if using " + 14 $"routing."; 15 throw new InvalidOperationException(message); 16 } 17 18 context.Response.StatusCode = 404; 19 return Task.CompletedTask; 20 }; 21 22 foreach (var component in _components.Reverse()) 23 { 24 app = component(app); 25 } 26 27 return app; 28 }
1 app.Use(next => { 2 Console.WriteLine("step 1"); 3 return async c => 4 { 5 await c.Response.WriteAsync("step 1 start"); 6 await next.Invoke(c); 7 await c.Response.WriteAsync("step 1 end"); 8 }; 9 }); 10 11 app.Use(next => { 12 Console.WriteLine("step 2"); 13 return async c => 14 { 15 await c.Response.WriteAsync("step 2 start"); 16 await next.Invoke(c); 17 await c.Response.WriteAsync("step 2 end"); 18 }; 19 }); 20 21 app.Use(next => { 22 Console.WriteLine("step 3"); 23 return async c => 24 { 25 await c.Response.WriteAsync("step 3 start"); 26 // await next.Invoke(c); 27 await c.Response.WriteAsync("step 3 end"); 28 }; 29 });
結果:
在控制台輸出step 3,step 2,step 1 因為有Resverse,合理!
頁面輸出 step1 start step 2 start step 3 start step 3 end step 2 end step 1 end 對應管道模型