ASP.NET Core 2 学习笔记(三)中间件
之前ASP.NET中使用的HTTP Modules及HTTP Handlers,在ASP.NET Core中已不復存在,取而代之的是Middleware。Middleware除了簡化了HTTP Modules/Handlers的使用方式,還帶入了Pipeline的概念。
本篇將介紹ASP.NET Core的Middleware概念及用法。
Middleware 概念
ASP.NET Core在Middleware的官方說明中,使用了Pipeline這個名詞,意指Middleware像水管一樣可以串聯(lián)在一起,所有的Request及Response都會層層經(jīng)過這些水管。
用圖例可以很容易理解,如下圖:
?
App.Use
Middleware的注冊方式是在Startup.cs的Configure對IApplicationBuilder使用Use方法注冊。
大部分擴展的Middleware也都是以Use開頭的方法注冊,例如:
- UseMvc():MVC的Middleware
- UseRewriter():URL rewriting的Middleware
一個簡單的Middleware 范例。如下:
Startup.cs
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection;namespace MyWebsite {public class Startup{// This method gets called by the runtime. Use this method to add services to the container.// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940public void ConfigureServices(IServiceCollection services){}// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.public void Configure(IApplicationBuilder app, IHostingEnvironment env){if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}app.Use(async (context, next) =>{await context.Response.WriteAsync("First Middleware in. \r\n");await next.Invoke();await context.Response.WriteAsync("First Middleware out. \r\n");});app.Use(async (context, next) =>{await context.Response.WriteAsync("Second Middleware in. \r\n");await next.Invoke();await context.Response.WriteAsync("Second Middleware out. \r\n");});app.Use(async (context, next) =>{await context.Response.WriteAsync("Third Middleware in. \r\n");await next.Invoke();await context.Response.WriteAsync("Third Middleware out. \r\n");});app.Run(async (context) =>{await context.Response.WriteAsync("Hello World! \r\n");});}} }用瀏覽器打開網(wǎng)站任意連結,輸出結果:
First Middleware in. Second Middleware in. Third Middleware in. Hello World! Third Middleware out. Second Middleware out. First Middleware out.在Pipeline的概念中,注冊順序是很重要的事情。請求經(jīng)過的順序一定是先進后出。
Request 流程如下圖:?
?
?Middleware 也可以作為攔截使用,如下:
?Startup.cs
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection;namespace MyWebsite {public class Startup{// This method gets called by the runtime. Use this method to add services to the container.// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940public void ConfigureServices(IServiceCollection services){}// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.public void Configure(IApplicationBuilder app, IHostingEnvironment env){if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}app.Use(async (context, next) =>{await context.Response.WriteAsync("First Middleware in. \r\n");await next.Invoke();await context.Response.WriteAsync("First Middleware out. \r\n");});app.Use(async (context, next) =>{await context.Response.WriteAsync("Second Middleware in. \r\n");// 水管阻塞,封包不往后送var condition = false;if (condition){await next.Invoke();}await context.Response.WriteAsync("Second Middleware out. \r\n");});app.Use(async (context, next) =>{await context.Response.WriteAsync("Third Middleware in. \r\n");await next.Invoke();await context.Response.WriteAsync("Third Middleware out. \r\n");});app.Run(async (context) =>{await context.Response.WriteAsync("Hello World! \r\n");});}} }輸出結果:
First Middleware in. Second Middleware in. Second Middleware out. First Middleware out.在Second Middleware 中,因為沒有達成條件,所以封包也就不在往后面的水管傳送。流程如圖:
App.Run
Run是Middleware的最后一個行為,以上面圖例來說,就是最末端的Action。
它不像Use能串聯(lián)其他Middleware,但Run還是能完整的使用Request及Response。
App.Map
Map是能用來處理一些簡單路由的Middleware,可依照不同的URL指向不同的Run及注冊不同的Use。
新增一個路由如下:
Startup.cs
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection;namespace MyWebsite {public class Startup{// This method gets called by the runtime. Use this method to add services to the container.// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940public void ConfigureServices(IServiceCollection services){}// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.public void Configure(IApplicationBuilder app, IHostingEnvironment env){if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}app.Use(async (context, next) =>{await context.Response.WriteAsync("First Middleware in. \r\n");await next.Invoke();await context.Response.WriteAsync("First Middleware out. \r\n");});// app.Use(async (context, next) =>// {// await context.Response.WriteAsync("Second Middleware in. \r\n");// // 水管阻塞,封包不往后送// var condition = false;// if (condition)// {// await next.Invoke();// }// await context.Response.WriteAsync("Second Middleware out. \r\n");// });app.Map("/second", mapApp =>{mapApp.Use(async (context, next) =>{await context.Response.WriteAsync("Second Middleware in. \r\n");await next.Invoke();await context.Response.WriteAsync("Second Middleware out. \r\n");});mapApp.Run(async context =>{await context.Response.WriteAsync("Second. \r\n");});});app.Use(async (context, next) =>{await context.Response.WriteAsync("Third Middleware in. \r\n");await next.Invoke();await context.Response.WriteAsync("Third Middleware out. \r\n");});app.Run(async (context) =>{await context.Response.WriteAsync("Hello World! \r\n");});}} }開啟網(wǎng)站任意連結,會顯示:
First Middleware in. Third Middleware in. Hello World! Third Middleware out. First Middleware out.開啟網(wǎng)站http://localhost:5000/second,則會顯示:
First Middleware in. Second Middleware in. Second. Second Middleware out. First Middleware out.?
創(chuàng)建Middleware 類
如果Middleware全部都寫在Startup.cs,代碼將很難維護,所以應該把自定義的Middleware邏輯獨立出來。
建立Middleware類不需要額外繼承其它類或接口,一般的類即可,例子如下:
FirstMiddleware.cs
using System.Threading.Tasks; using Microsoft.AspNetCore.Http;namespace MyWebsite {public class FirstMiddleware{private readonly RequestDelegate _next;public FirstMiddleware(RequestDelegate next){_next = next;}public async Task Invoke(HttpContext context){await context.Response.WriteAsync($"{nameof(FirstMiddleware)} in. \r\n");await _next(context);await context.Response.WriteAsync($"{nameof(FirstMiddleware)} out. \r\n");}} }全局注冊
在Startup.Configure注冊Middleware就可以套用到所有的Request。如下:
Startup.cs
// ... public class Startup {// ...public void Configure(IApplicationBuilder app){app.UseMiddleware<FirstMiddleware>();// ...} }局部注冊
Middleware 也可以只套用在特定的Controller 或Action。注冊方式如下:
Controllers\HomeController.cs
// .. [MiddlewareFilter(typeof(FirstMiddleware))] public class HomeController : Controller {// ...[MiddlewareFilter(typeof(SecondMiddleware))]public IActionResult Index(){// ...} }Extensions
大部分擴展的Middleware都會用一個靜態(tài)方法包裝,如:UseMvc()、UseRewriter()等。
自定義的Middleware當然也可以透過靜態(tài)方法包,范例如下:
Extensions\CustomMiddlewareExtensions.cs
using Microsoft.AspNetCore.Builder;namespace MyWebsite {public static class CustomMiddlewareExtensions{public static IApplicationBuilder UseFirstMiddleware(this IApplicationBuilder builder){return builder.UseMiddleware<FirstMiddleware>();}} }注冊Extension Middleware 的方式如下:
Startup.cs
// ... public class Startup {// ...public void Configure(IApplicationBuilder app){app.UseFirstMiddleware();// ...} }參考
ASP.NET Core Middleware Fundamentals?
Creating Custom Middleware In ASP.Net Core
?
老司機發(fā)車啦:https://github.com/SnailDev/SnailDev.NETCore2Learning
總結
以上是生活随笔為你收集整理的ASP.NET Core 2 学习笔记(三)中间件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WordPress更新时提示无法连接到F
- 下一篇: CSVHelper在Asp.Net MV