Middleware trong ASP.NET Core

ASP.NET Core đã giới thiệu một khái niệm mới gọi là Middleware. Middleware là một thành phần (lớp) được thực thi theo mọi yêu cầu trong ứng dụng ASP.NET Core.

Trong ASP.NET cổ điển, HttpHandlers và HttpModules là một phần của đường ống yêu cầu (request pipeline). Middleware tương tự như HttpHandlers và HttpModules, nơi cả hai cần được cấu hình và thực thi trong mỗi yêu cầu.

Thông thường, sẽ có nhiều middleware trong ứng dụng web ASP.NET Core. Nó có thể là một framework cung cấp middleware được thêm thông qua NuGet hoặc middleware tùy chỉnh của riêng bạn.

Chúng ta có thể thiết lập thứ tự thực hiện middleware trong đường ống yêu cầu. Mỗi middleware thêm hoặc sửa đổi yêu cầu http và tùy ý chuyển điều khiển sang middleware tiếp theo. Hình dưới đây minh họa việc thực hiện các middleware trong ASP.NET Core.

Middleware trong ASP.NET Core

Middleware xây dựng đường ống yêu cầu. Hình dưới đây minh họa việc xử lý yêu cầu ASP.NET Core.

Xử lý request trong ASP.NET Core

Bạn có thể truy cập Hướng dẫn lập trình ASP.NET Core để không bỏ lỡ bất kỳ bài viết nào của chúng tôi.

Cấu hình Middleware

Chúng ta có thể cấu hình middleware trong phương thức Configure của lớp Startup bằng cách sử dụng thể hiện của interface IApplicationBuilder. Ví dụ sau đây thêm một middleware duy nhất bằng phương thức Run trả về chuỗi "Hello World!" cho từng yêu cầu.

public class Startup
{
    public Startup()
    {
    }
    
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        //configure middleware using IApplicationBuilder here..
            
        app.Run(async (context) =>
        {              
            await context.Response.WriteAsync("Hello World!");              
        });

        // other code removed for clarity.. 
    }
}

Trong ví dụ trên, phương thức Run() là một phương thức mở rộng của IApplicationBuilder, nó thêm middleware đầu cuối vào đường ống yêu cầu của ứng dụng. Middleware được cấu hình ở trên trả về phản hồi với chuỗi "Hello World!" cho mỗi yêu cầu.

Tìm hiểu phương thức Run

Chúng ta đã sử dụng phương thức mở rộng Run để thêm middleware ở ví dụ trên. Sau đây là chữ ký của phương thức Run:

public static void Run(this IApplicationBuilder app, RequestDelegate handler)

Phương thức Run là một phương thức mở rộng của interface IApplicationBuilder và nó chấp nhận một tham số kiểu RequestDelegate. RequestDelegate là một delegate tham chiếu tới phương thức xử lý yêu cầu. Sau đây là chữ ký RequestDelegate.

public delegate Task RequestDelegate(HttpContext context);

Bạn có thể tìm hiểu thêm về delegate trong C# ở bài viết dưới đây:

Delegate trong C# | Comdy
Delegate trong C# là gì? Delegate trong C# dùng để làm gì? Cách sử dụng Delegate trong C#.

Như bạn có thể thấy ở trên, phương thức Run chấp nhận một phương thức có chữ ký phải khớp với delegate RequestDelegate như là một tham số.

Do đó, phương thức này phải có tham số HttpContext và trả về Task. Vì vậy, bạn có thể định nghĩa một biểu thức lambda hoặc định nghĩa một phương thức để làm tham số cho phương thức Run.

Biểu thức lambda được định nghĩa trong phương thức Run ở trên tương tự như biểu thức trong ví dụ bên dưới.

public class Startup
{
    public Startup()
    {
    } 

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
         app.Run(MyMiddleware);
    }

    private Task MyMiddleware(HttpContext context) 
    {
        return context.Response.WriteAsync("Hello World! ");
    }
}

Ở ví dụ trên, phương thức MyMiddleware là một phương thức đồng bộ, do đó nó sẽ giữ luồng cho đến khi hoàn thành việc thực thi. Vì vậy, chúng ta có thể chuyển nó thành phương thức bất đồng bộ bằng cách sử dụng từ khóa asyncawait để cải thiện hiệu suất và khả năng mở rộng.

// other code removed for clarity

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
     app.Run(MyMiddleware);
}

private async Task MyMiddleware(HttpContext context) 
{
    await context.Response.WriteAsync("Hello World! ");
}

Đoạn mã trên giống như hai đoạn mã dưới đây sử dụng biểu thức lambda.

app.Run(async context => await context.Response.WriteAsync("Hello World!") );

//or 

app.Run(async (context) =>
{
    await context.Response.WriteAsync("Hello World!"); 
});

Vì vậy, chúng ta có thể cấu hình middleware bằng các sử dụng phương thức Run.

Cấu hình nhiều Middleware

Hầu hết các ứng dụng ASP.NET Core sẽ có nhiều middleware và chúng sẽ được thực hiện tuần tự.

Tuy nhiên khi sử dụng phương thức Run để thêm một middleware đầu cuối thì nó sẽ không thể gọi các middleware tiếp theo vì nó sẽ là middleware cuối cùng trong chuỗi.

Ở ví dụ dưới đây chỉ có phương thức Run đầu tiên được thực hiện, phương thức Run thứ hai sẽ không bao giờ thực hiện.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.Run(async (context) =>
    {
        await context.Response.WriteAsync("Hello World From 1st Middleware"); 
    });
    
    // the following will never be executed
    app.Run(async (context) =>
    {
        await context.Response.WriteAsync("Hello World From 2nd Middleware"); 
    });
}

Để cấu hình nhiều middleware, chúng ta sẽ sử dụng phương thức mở rộng Use(). Nó tương tự như phương thức Run() ngoại trừ việc nó bao gồm tham số next để gọi middleware tiếp theo trong chuỗi. Hãy xem ví dụ sau.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.Use(async (context, next) =>
    {
        await context.Response.WriteAsync("Hello World From 1st Middleware!");

        await next();
    });

    app.Run(async (context) =>
    {
        await context.Response.WriteAsync("Hello World From 2nd Middleware"); 
    });
}

Ví dụ trên sẽ hiển thị Hello World From 1st Middleware!Hello World From 2nd Middleware! trong trình duyệt.

Vì vậy, chúng ta có thể sử dụng phương thức Use() để cấu hình nhiều middleware theo thứ tự chúng ta muốn.

Thêm Middleware tích hợp qua NuGet

ASP.NET Core là một khung mô-đun. Chúng tôi có thể thêm các tính năng phía máy chủ mà chúng tôi cần trong ứng dụng của mình bằng cách cài đặt các trình cắm khác nhau thông qua NuGet. Có rất nhiều plugin trung gian có sẵn có thể được sử dụng trong ứng dụng của chúng tôi.

Sau đây là một số middleware tích hợp sẵn trong ASP.NET Core:

Middleware Miêu tả
Authentication Thêm hỗ trợ xác thực.
CORS Định cấu hình chia sẻ tài nguyên cross-origin.
Routing Thêm khả năng định tuyến cho MVC hoặc web form
Session Thêm hỗ trợ cho phiên người dùng.
StaticFiles Thêm hỗ trợ để phục vụ các file tĩnh và duyệt thư mục.
Diagnostics Thêm hỗ trợ cho báo cáo và xử lý các trường hợp ngoại lệ và lỗi.

Chúng ta cùng xem cách sử dụng middleware Diagnostics ở dưới đây.

Middleware Diagnostics

Middleware Diagnostics được sử dụng để báo cáo và xử lý các trường hợp ngoại lệ và lỗi trong ASP.NET Core và chẩn đoán lỗi của Entity Framework Core.

Mở file project.json trong Solution Explorer và thêm phụ thuộc Microsoft.AspNetCore.Diagnostics nếu nó chưa được thêm vào. Đợi một lúc cho đến khi Visual Studio khôi phục các gói.

Gói này bao gồm các middleware và phương thức mở rộng sau đây:

Middleware / Phương thức mở rộng Miêu tả
DeveloperExceptionPageMiddleware
-> UseDeveloperExceptionPage()
Nắm bắt các ngoại lệ đồng bộ và không đồng bộ từ đường ống và tạo ra các phản hồi lỗi bằng HTML.
ExceptionHandlerMiddleware
-> UseExceptionHandler()
Bắt ngoại lệ, ghi log và thực hiện lại trong một đường ống thay thế.
StatusCodePagesMiddleware
-> UseStatusCodePages()
Kiểm tra các phản hồi với mã trạng thái trong khoảng từ 400 đến 599.
WelcomePageMiddleware
-> UseWelcomePage()
Hiển thị trang Chào mừng cho đường dẫn gốc.

Chúng ta có thể gọi các phương thức mở rộng Use* tương ứng để sử dụng các middleware ở trên trong phương thức Configure của lớp Startup.

Ở ví dụ dưới đây chúng ta hãy thử thêm middleware WelcomePage để hiển thị trang chào mừng cho đường dẫn gốc như sau:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{   
    app.UseWelcomePage(); 
    //other code removed for clarity 
}

Ví dụ trên sẽ hiển thị trang chào mừng sau mỗi khi có yêu cầu.

Welcome page trong ASP.NET Core

Bằng cách này, chúng tôi có thể sử dụng các phương thức mở rộng Use* khác nhau để thêm các middleware khác nhau.

Tiếp theo, chúng ta sẽ tìm hiểu cách thực hiện chức năng ghi log trong ứng dụng ASP.NET Core.

Tạo middleware tùy chỉnh trong ASP.NET Core

Ở phần này, bạn sẽ tìm hiểu cách tạo và cấu hình middleware tùy chỉnh của riêng bạn vào đường ống yêu cầu của ứng dụng ASP.NET Core.

Thành phần của middleware tùy chỉnh giống như bất kỳ lớp .NET nào khác và nó có phương thức Invoke(). Tuy nhiên, để thực thi middleware kế tiếp theo trình tự, nó phải có tham số kiểu RequestDelegate trong phương thức khởi tạo.

Visual Studio có mẫu để tạo lớp middleware tiêu chuẩn. Để làm điều này, bạn nhấp chuột phải vào project hoặc thư mục mà bạn muốn tạo lớp middleware và chọn Add -> New Item. Điều này sẽ mở cửa sổ bật lên Add New Item. Tìm kiếm từ "middleware" trong hộp tìm kiếm phía trên bên phải như hình dưới đây.

Tạo middleware tùy chỉnh trong ASP.NET Core

Chọn mục Middleware Class rồi đặt tên cho nó và nhấp vào nút Add. Việc này sẽ thêm một lớp mới cho middleware kèm theo phương thức mở rộng như dưới đây.

// You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
public class MyMiddleware
{
    private readonly RequestDelegate _next;

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

    public Task Invoke(HttpContext httpContext)
    {

        return _next(httpContext);
    }
}

// Extension method used to add the middleware to the HTTP request pipeline.
public static class MyMiddlewareExtensions
{
    public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<MyMiddleware>();
    }
} 

Như bạn có thể thấy ở trên, phương thức Invoke() là phương thức đồng bộ. Vì vậy, chúng ta sẽ thay đổi nó thành không đồng bộ và viết code xử lý logic tùy chỉnh trước khi gọi next();

public class MyMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;

    public MyMiddleware(RequestDelegate next, ILoggerFactory logFactory)
    {
        _next = next;

        _logger = logFactory.CreateLogger("MyMiddleware");
    }

    public async Task Invoke(HttpContext httpContext)
    {
        _logger.LogInformation("MyMiddleware executing..");

        await _next(httpContext); // calling next middleware

    }
}

// Extension method used to add the middleware to the HTTP request pipeline.
public static class MyMiddlewareExtensions
{
    public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<MyMiddleware>();
    }
} 

Cấu hình middleware tùy chỉnh trong ASP.NET Core

Bây giờ, chúng ta cần thêm middleware tùy chỉnh của mình vào đường ống yêu cầu bằng cách sử dụng phương thức mở rộng như bên dưới.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseMyMiddleware();

    app.Run(async (context) =>
    {
        await context.Response.WriteAsync("Hello World!");
    });
}

Chúng ta cũng có thể thêm middleware bằng các sử dụng phương thức app.UseMiddleware<MyMiddleware>() của interface IApplicationBuilder.

Như vậy là chúng ta đã tìm hiểu về cách tạo và cấu hình middleware tùy chỉnh trong ứng dụng ASP.NET Core.

ASP.NET Core MVC
Bài Viết Liên Quan:
ASP.NET Core vs Go: Hiệu suất HTTP của ai tốt hơn
Trung Nguyen 11/10/2020
ASP.NET Core vs Go: Hiệu suất HTTP của ai tốt hơn

Trong bài viết này, chúng tôi sẽ so sánh hiệu suất HTTP của ASP.NET Core và Go sử dụng mô hình kiến trúc MVC.

ASP.NET Core Dependency Injection: Best Practice, Mẹo và Thủ Thuật
Trung Nguyen 10/10/2020
ASP.NET Core Dependency Injection: Best Practice, Mẹo và Thủ Thuật

Trong bài viết này, tôi sẽ chia sẻ các best practice, mẹo và thủ thuật về việc sử dụng Dependency Injection (DI) trong ứng dụng ASP.NET Core.

View Layout, View Start, View Imports trong ASP.NET Core
Trung Nguyen 10/04/2020
View Layout, View Start, View Imports trong ASP.NET Core

View Layout, View Start, View Imports là gì? Lợi ích và các sử dụng View Layout, View Start, View Imports trong ASP.NET Core.

View trong ASP.NET Core
Trung Nguyen 10/04/2020
View trong ASP.NET Core

Tất tần tật về View, Razor View, Layout View, View Start, View Import, Tag Helpers trong ASP.NET Core MVC.