小的應用組件能夠包含到Http請求管道當中,ASP.NET5 集成了中間件,被包在了應用程序的Configure方法當中。app
1. 什麼是中間件async
中間件是一組被裝到應用程序管道的請求和響應中的組件。每個組件能夠選擇地是否把當前的請求傳到下一個組件當中,能夠執行一些特定的動做在下一個組件以前或者以後執行。請求委託被用來建立這樣的請求管道,用來處理你應用程序的請求。函數
請求的委託用IApplicationBuilder的run, map, use擴展方法來配置. 在Starup的configure裏面能夠作這樣的配置,一個單獨的請求委託能夠指定一個匿名的方法,或者定義在一個可重複利用的類當中。這些可重複利用的類就是中間件,或者中間組件。每一個組件負責調用下一個組件,或者選擇停止。性能
ASP.NET請求管道是由一系列的請求委託組成,一個一個地調用。以下圖所示ui
每一個委託有機會執行相應的操做在下一個委託以前或以後。任何的委託能夠選擇中止傳遞請求到下一個委託。這就是所謂的請求短路,這有時候有好的,能夠避免一些沒必要要的工做,例如Authorization中間件在Authenticated以後調用以後的委託,當沒有受權時會顯示"Not Authorized", 異常處理能夠捕獲到,由於它在管道中早執行了。this
以下是應用程序的默認配置:spa
public void COnfigure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)設計
{orm
...中間件
if(env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseIdentity();
app.UseMvc(routes => { routes.MapRout(name:"default", template:"{controller=Home}/{action=Index}/{id?}" });
}
UseExceptionHandler最早配置,這樣它能夠處理後續調用出現的任何異常,另外,這裏的設計讓請求的靜態文件不須要用戶的認證,這樣能夠提高性能,
切記:在應用配置時利用中間件的順序是很重要的,確保你的應用程序適合你的應用場景。
一個簡單的匿名的調用以下:
app.Run(async context => { await context.Response.WriteAsync("Hello, World!"); });
注意,執行完上面的這條語句,就會停止執行下面的任何語句。
再看一個例子, 在委託的參數裏能夠增長一個next參數,來調用下一個委託。
public void ConfigureLogInline(IApplicationBuilder app, ILoggerFactory loggerfactory)
{
loggerfactory.AddConsole(minLevel: logLevel.Information);
var logger = loggerfactory.CreateLogger(_environment);
app.Use(async (context, next) => {logger.LogInfromation();
await next.Invoke();
logger.LogInformation("Finished handling request".);});
app.Run(async context=>{ await context.Response.WriteAsync("Hello from" + _environment); });
}
注意:不在要調用next以後再修改HttpResponse, 由於後續的委託也會寫,致使錯亂。
2 Run, Map, and Use
通常地, 咱們用run的時候,是不會調用其它的組件的,也就是不會再調next的請求委託。因此,Run只能在最後被調用。
下面兩個結果是同樣的
public void COnfigureEnvironmentOne(IApplicationBuilder app)
{
app.Run(async context => { await context.Response.WriteAsync("Hello from " + _environment);
}
public void ConfigureEnvironmentTwo(IApplicationBuilder app)
{
app.Use(next => async context =>{ await context.Response.WriteAsync("Hello from " + _environment);
}
Map*擴展用來分支管道,下面會演示一個基於請求路徑的分支,Map擴展用來把請求的路徑和處理的方法作一個映射,例子以下:
private static void HandleMapTest(IApplicationBuilder app)
{
app.Run(async context => { await context.Response.WriteAsync("Map Test Successful"); });
}
public void ConfigureMapping(IApplicationBuilder app)
{
app.Map("/maptest", HandleMapTest);
}
MapWhen方法能夠支持謂詞的中間分支, 例如:
public void COnfigureMapWhen(IApplicationBuilder app)
{
app.MapWhen(context => { return context.Request.Query.ContainsKey("branch"); }, HandleBranch);
app.Run(async context => { awat context.Response.WriteAsync("Hello from " + _environment); });
}
private static void HandleBranch(IApplicationBuilder app)
{
app.Run(async context => { await context.Response.WriteAsync("Branch used."); });
}
上面的例子任何的請求參數中含有branch的都走HandleBranch分支,其它走下面的。
3. 內建的中間件
中間件 描述
Authentication 提供認證支持
CORS 配置跨源資源共享
Diagnostics 包含錯誤頁的支持和運行時的信息
Routing 定義限制請求的路由
Session 提供管理用戶會話的支持
Static Files 提供靜態文件,文件夾的瀏覽
4. 編寫中間件
對於複雜的請求處理,ASP.NET團隊建議實現本身的中間件,在Configure裏去調用,例如:
public class RequestLoggerMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
public RequestLoggerMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
{
_next = next;
_logger = logggerFactory.CreateLogger<RequestLoggerMiddleware>();
}
public async Task Invoke(HttpContext context)
{
_logger.LogInformation("Handling request: " + context.Request.Path);
await _next.Invoke(context);
_logger.LogInformation("Finished handling request.");
}
}
public static class RequestLoggerExtensions
{
public static IApplicationBuilder UseRequestLogger(this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestLoggerMiddleware>();
}
}
在Configure方法中你能夠簡單地利用一行代碼就搞定了。
app.UseRequestLogger();
在UseMiddleware<T>方法中ReuqestLoggerMiddleware的構造函數裏的參數會被DI自動地注入進去。