深入理解HttpPipeline

HttpPipeline是ASP.NET Core中重要的一個概念,這個概念在開發中經常會用到。它通過定義一系列的middleware來組織請求的處理流程,可以方便地對請求進行處理。本文將從不同的方面,探討HttpPipeline如何工作。

一、Pipeline的組成

HTTP請求在ASP.NET Core中經過一個由若干個中間件組成的管道,這個管道被稱之為Pipeline。ASP.NET Core應用程序的Startup類就是用來定義和組織Pipeline的。Startup類中有兩個方法:ConfigureServices和Configure方法。

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // 配置依賴注入
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // 配置HTTP請求管道
    }
}

其中ConfigureServices方法是用來配置依賴注入,Configure方法是用來配置HTTP請求管道。在Configure方法中,可以向管道中添加中間件,Middleware的順序將決定它們在管道中的執行順序。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();
    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller}/{action}/{id?}");
    });
}

上述代碼中,我們向管道中添加了以下五個Middleware:

  • UseHttpsRedirection : HTTP請求重定向到HTTPS
  • UseStaticFiles : 處理靜態文件請求
  • UseRouting : 處理請求路徑
  • UseAuthorization : 處理授權
  • UseEndpoints : 處理路由匹配

基本的請求處理流程如下圖所示:

二、Middleware的工作原理

Middleware是處理請求的核心部件,也是Pipeline的基本單位。Middleware負責處理請求並調用管道中下一個Middleware。下一個Middleware可以通過HttpContext.RequestDelegate指定,比如:

public class MyMiddleware
{
    private readonly RequestDelegate _next;

    public MyMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // 處理請求前的邏輯
        await _next(context);
        // 處理請求後的邏輯
    }
}

上述代碼中,MyMiddleware是一個簡單的Middleware,它在處理請求前和請求後都會有相應的邏輯。在MyMiddleware的構造函數中,我們注入了HttpContext.RequestDelegate類型的參數_next,它表示了Pipeline中下一個Middleware。在MyMiddleware的InvokeAsync方法中,我們首先執行自己的邏輯,然後調用_next委託,以便讓執行流程繼續下去。

如果你需要在管道中使用自己的Middleware,首先需要定義這個Middleware,在Startup類的Configure方法中引入自己定義的Middleware:

public void Configure(IApplicationBuilder app)
{
    app.UseMiddleware<MyMiddleware>();
    // 省略其他Middleware的配置
}

這樣,自己定義的Middleware就被引入到了Pipeline中。

三、Middleware的生命周期

ASP.NET Core中定義了三種Middleware的生命周期,分別是Transistent、Scoped、Singleton。

  • Transient: 瞬時,實例每次請求都會創建
  • Scoped: 域,每次請求都只會創建一個實例
  • Singleton: 單例,實例在應用程序生命周期內只會被創建一次

為了了解生命周期的區別,我們可以通過一個簡單的示例來說明:

public interface IMyService
{
    void DoSomething();
}
public class MyService : IMyService
{
    public MyService()
    {
        Console.WriteLine("MyService實例被創建");
    }

    public void DoSomething()
    {
        Console.WriteLine("MyService正在處理事務");
    }
}
public class MyMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IMyService _service;

    public MyMiddleware(RequestDelegate next, IMyService service)
    {
        _next = next;
        _service = service;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        _service.DoSomething();
        await _next(context);
    }
}

上述代碼中,我們定義了一個IMyService接口和MyService實現類,還有一個MyMiddleware,它需要注入IMyService類型的service。在MyMiddleware的InvokeAsync方法中,我們首先調用service.DoSomething()方法來對IMyService實例進行操作。

在Startup類的ConfigureServices方法中,我們將IMyService註冊到依賴注入容器中,使用Transient生命周期:

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IMyService, MyService>();
}

這意味着每次請求都會創建一個新的IMyService實例。當我們使用這個Pipeline時,會看到多次創建MyService的實例:

MyService實例被創建
MyService實例被創建

然後我們將IMyService的生命周期從Transient改成Scoped:

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IMyService, MyService>();
}

這意味着,每次請求將使用同一個IMyService實例。輸出結果為:

MyService實例被創建

最後我們將生命周期改成Singleton:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IMyService, MyService>();
}

這將保證整個應用程序生命周期內只會創建一個IMyService實例,輸出結果為:

MyService實例被創建

四、Middleware執行順序

在管道中,Middleware的順序對於請求的處理流程至關重要。每個Middleware只負責它自己的業務邏輯,所以每個Middleware是互相獨立的。每個Middleware的順序會對整個Pipeline的處理造成影響。

Middleware的順序可以通過在Configure方法中的調用順序決定:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // 20210517 加入自定義的 Middleware
    app.UseMiddleware<RequestResponseLoggingMiddleware>();
    app.UseAuthentication();
    app.UseAuthorization();
    app.UseStaticFiles();
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

除此之外,Middleware還可以通過條件控制順序。例如:

public void Configure(IApplicationBuilder app)
{
    app.Use(async (context, next) =>
    {
        if (context.Request.Path.StartsWithSegments("/admin"))
        {
            await context.Response.WriteAsync("你需要管理員權限才能訪問管理頁面");
        }
        else
        {
            await next();
        }
    });

    // 省略其他Middleware的配置
}

在上述代碼中,我們使用了一個匿名Middleware,它檢查請求路徑是否以”/admin”開頭。如果請求路徑以”/admin”開頭,將返回一條錯誤信息。這個Middleware是在管道的開始處位置,這意味着即使後面的Middleware能夠處理任何類型的請求,如果請求路徑以”/admin”開頭,這個Middleware也會優先執行。

五、自定義Middleware

在使用ASP.NET Core時,我們可能需要自己編寫一些Middleware來處理請求。編寫Middleware非常簡單,只需要實現Invoke方法即可:

public class MyMiddleware
{
    private readonly RequestDelegate _next;

    public MyMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        // 處理請求前的邏輯
        await _next(context);
        // 處理請求後的邏輯
    }
}

在ASP.NET Core中,Middleware通常是由一個Invoke方法和一個構造函數組成的。Invoke方法是用來處理請求的,構造函數是用來接收參數的。我們可以在Invoke方法中執行任何邏輯。例如,我們可以修改請求或者響應的內容,或者執行任何附加邏輯(如日誌記錄)。

在編寫Middleware時,我們需要記住以下幾點:

  • 每個Middleware必須使用下一個Middleware,否則整個Pipeline的處理過程將被打斷。
  • 每個Middleware應該儘可能做到高內聚、低耦合。
  • Middleware的順序對請求的處理流程至關重要,必須慎重選擇。

六、結語

ASP.NET Core中的HttpPipeline有着重要的作用,通過定義一系列的middleware來組織請求的處理流程,方便地對請求進行處理。在實際開發中,我們會經常使用到Middleware,因此理解Pipeline的工作原理是非常重要的。希望本文能夠對你有所幫助。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/199122.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-04 19:14
下一篇 2024-12-04 19:14

相關推薦

  • 深入解析Vue3 defineExpose

    Vue 3在開發過程中引入了新的API `defineExpose`。在以前的版本中,我們經常使用 `$attrs` 和` $listeners` 實現父組件與子組件之間的通信,但…

    編程 2025-04-25
  • 深入理解byte轉int

    一、字節與比特 在討論byte轉int之前,我們需要了解字節和比特的概念。字節是計算機存儲單位的一種,通常表示8個比特(bit),即1字節=8比特。比特是計算機中最小的數據單位,是…

    編程 2025-04-25
  • 深入理解Flutter StreamBuilder

    一、什麼是Flutter StreamBuilder? Flutter StreamBuilder是Flutter框架中的一個內置小部件,它可以監測數據流(Stream)中數據的變…

    編程 2025-04-25
  • 深入探討OpenCV版本

    OpenCV是一個用於計算機視覺應用程序的開源庫。它是由英特爾公司創建的,現已由Willow Garage管理。OpenCV旨在提供一個易於使用的計算機視覺和機器學習基礎架構,以實…

    編程 2025-04-25
  • 深入了解scala-maven-plugin

    一、簡介 Scala-maven-plugin 是一個創造和管理 Scala 項目的maven插件,它可以自動生成基本項目結構、依賴配置、Scala文件等。使用它可以使我們專註於代…

    編程 2025-04-25
  • 深入了解LaTeX的腳註(latexfootnote)

    一、基本介紹 LaTeX作為一種排版軟件,具有各種各樣的功能,其中腳註(footnote)是一個十分重要的功能之一。在LaTeX中,腳註是用命令latexfootnote來實現的。…

    編程 2025-04-25
  • 深入了解Python包

    一、包的概念 Python中一個程序就是一個模塊,而一個模塊可以引入另一個模塊,這樣就形成了包。包就是有多個模塊組成的一個大模塊,也可以看做是一個文件夾。包可以有效地組織代碼和數據…

    編程 2025-04-25
  • 深入探討馮諾依曼原理

    一、原理概述 馮諾依曼原理,又稱“存儲程序控制原理”,是指計算機的程序和數據都存儲在同一個存儲器中,並且通過一個統一的總線來傳輸數據。這個原理的提出,是計算機科學發展中的重大進展,…

    編程 2025-04-25
  • 深入剖析MapStruct未生成實現類問題

    一、MapStruct簡介 MapStruct是一個Java bean映射器,它通過註解和代碼生成來在Java bean之間轉換成本類代碼,實現類型安全,簡單而不失靈活。 作為一個…

    編程 2025-04-25
  • 深入理解Python字符串r

    一、r字符串的基本概念 r字符串(raw字符串)是指在Python中,以字母r為前綴的字符串。r字符串中的反斜杠(\)不會被轉義,而是被當作普通字符處理,這使得r字符串可以非常方便…

    編程 2025-04-25

發表回復

登錄後才能評論