Asp.Net Core Middleware(中間件)


## 1.Asp.Net Core Middleware(中間件)

1.1 中間件

(1)什么是中間件

  • 中間件是ASP.NET Core的核心組件,MVC框架、響應緩存、身份驗證、CORS、Swagger等都是內置中間件。

image-20220308215607520

  • 廣義上來講:Tomcat、WebLogic、Redis、IIS;狹義上來講,ASP.NET Core中的中間件指ASP.NET Core中的一個組件。

  • 中間件由前邏輯、next、后邏輯3部分組成,前邏輯為第一段要執行的邏輯代碼、next為指向下一個中間件的調用、后邏輯為從下一個中間件執行返回所執行的邏輯代碼。每個HTTP請求都要經歷一系列中間件的處理,每個中間件對於請求進行特定的處理后,再轉到下一個中間件,最終的業務邏輯代碼執行完成后,響應的內容也會按照處理的相反順序進行處理,然后形成HTTP響應報文返回給客戶端。

  • 中間件組成一個管道,整個ASP.NET Core的執行過程就是HTTP請求和響應按照中間件組裝的順序在中間件之間流轉的過程。開發人員可以對組成管道的中間件按照需要進行自由組合

(2)中間件的三個概念

Map、Use和Run。Map用來定義一個管道可以處理哪些請求,Use和Run用來定義管道,一個管道由若干個Use和一個Run組成,每個Use引入一個中間件,而Run是用來執行最終的核心應用邏輯。

image-20220308215919743

(3)理解中間件執行順序

image-20220308220816901

app.Map("/test", async appbuilder => {
    appbuilder.Use(async (context, next) => {
        context.Response.ContentType = "text/html";
        await context.Response.WriteAsync("1  Start<br/>");
        await next.Invoke();
        await context.Response.WriteAsync("1  End<br/>");
    });
    appbuilder.Use(async (context, next) => {
        await context.Response.WriteAsync("2  Start<br/>");
        await next.Invoke();
        await context.Response.WriteAsync("2  End<br/>");
    });
    appbuilder.Run(async ctx => {
        await ctx.Response.WriteAsync("hello middleware <br/>");
    });
});

1.2 中間件的基本實現

中間件類是一個普通的.NET類,它不需要繼承任何父類或者實現任何接口,但是這個類需要有一個構造方法,構造方法至少要有一個RequestDelegate類型的參數,這個參數用來指向下一個中間件。這個類還需要定義一個名字為Invoke或InvokeAsync的方法,方法至少有一個HttpContext類型的參數,方法的返回值必須是Task類型。中間件類的構造方法和Invoke(或InvokeAsync)方法還可以定義其他參數,其他參數的值會通過依賴注入自動賦值。

image-20220308223037915

1.3 Markdown轉html中間件

(1)安裝Ude.NetStandard,獲取流的編碼

Install-Package Ude.NetStandard

(2)安裝MarkdownSharp,md文件轉html

Install-Package MarkdownSharp

(3)MarkDownViewerMiddleware

public class MarkDownViewerMiddleware
{
    private readonly RequestDelegate next;
    private readonly IWebHostEnvironment hostEnv;
    private readonly IMemoryCache memCache;

    public MarkDownViewerMiddleware(RequestDelegate next,
        IWebHostEnvironment hostEnv, IMemoryCache memCache)
    {
        this.next = next;
        this.hostEnv = hostEnv;
        this.memCache = memCache;
    }

    /// <summary>
    /// 檢測流的編碼
    /// </summary>
    /// <param name="stream"></param>
    /// <returns></returns>
    private static string DetectCharset(Stream stream)
    {
        CharsetDetector charDetector = new();
        charDetector.Feed(stream);
        charDetector.DataEnd();
        string charset = charDetector.Charset ?? "UTF-8";
        stream.Position = 0;
        return charset;
    }

    /// <summary>
    /// 讀取文本內容
    /// </summary>
    /// <param name="stream"></param>
    /// <returns></returns>
    private static async Task<string> ReadText(Stream stream)
    {
        string charset = DetectCharset(stream);
        using var reader = new StreamReader(stream, Encoding.GetEncoding(charset));
        return await reader.ReadToEndAsync();
    }

    public async Task InvokeAsync(HttpContext context)
    {
        string path = context.Request.Path.Value ?? "";
        if (!path.EndsWith(".md"))
        {
            await next(context);
            return;
        }
        var file = hostEnv.WebRootFileProvider.GetFileInfo(path);
        if (!file.Exists)
        {
            await next(context);
            return;
        }
        context.Response.ContentType = $"text/html;charset=UTF-8";
        context.Response.StatusCode = 200;
        string cacheKey = nameof(MarkDownViewerMiddleware)
            + path + file.LastModified;
        var html = await memCache.GetOrCreateAsync(cacheKey, async ce =>
        {
            ce.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1);
            using var stream = file.CreateReadStream();
            string text = await ReadText(stream);
            Markdown markdown = new Markdown();
            return markdown.Transform(text);
        });
        await context.Response.WriteAsync(html);
    }
}

(4)app.UseMiddleware

MarkDownViewerMiddleware操作的是靜態文件,所以要在UseStaticFiles之前,否則會被當做靜態文件直接輸出

image-20220308232452367

1.4 Filter和Middware的區別

  • 中間件是ASP.NET Core這個基礎提供的功能,而Filter是ASP.NET Core MVC中提供的功能。ASP.NET Core MVC是由MVC中間件提供的框架,而Filter屬於MVC中間件提供的功能。

  • 中間件可以處理所有的請求,而Filter只能處理對控制器的請求;中間件運行在一個更底層、更抽象的級別,因此在中間件中無法處理MVC中間件特有的概念。

  • 中間件和Filter可以完成很多相似的功能。“未處理異常中間件”和“未處理異常Filter”;“請求限流中間件”和“請求限流Filter”的區別。

  • 優先選擇使用中間件;但是如果這個組件只針對MVC或者需要調用一些MVC相關的類的時候,我們就只能選擇Filter。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM