Sự liên quan giữa Middleware và Request Pipeline trong ASP.NET Core

Sự liên quan giữa Middleware và Request Pipeline trong ASP.NET Core

Bài viết này chúng ta sẽ học về Middleware và cách mà Request Pipeline làm việc với ứng dụng ASP.NET Core.

Request Pipeline

Request Pipeline là cơ chế bắt đầu khi các request bắt đầu được xử lý với một đối tượng Request đầu vào và kết thúc với đầu ra là một response. Pipeline chỉ ra cách mà ứng dụng phản hồi với HTTP Request. Request đến từ trình duyệt đi qua pipeline và quay trở lại khi xử lý xong để trả về client. Các thành phần đơn lẻ tạo nên pipeline này được gọi là middleware.

Middleware là gì?

Middleware là thành phần của phần mềm đóng vai trò tác động vào request pipeline (luồng request) để xử lý chúng và tạo ra response phản hồi lại client. Mỗi một tiến trình middleware thao tác với các request nhận được từ middleware trước nó. Nó cũng có thể quyết định gọi middleware tiếp theo trong pipeline hoặc trả về response cho middleware ngay trước nó. (ngắt pipeline).

Chúng làm việc ra sao

Hình dưới đây cho ta thấy Request Pipeline kết hợp với middleware làm việc trong ứng dụng ASP.NET Core.

 

Đầu tiên, HTTP Request đến (trực tiếp hoặc qua External web server) ứng dụng. Kestrel web server nhặt lấy request và tạo một HttpContext và gán nó vào Middleware đầu tiên trong request pipeline.

Middleware đầu tiên sẽ nhận request, xử lý và gán nó cho middleware tiếp theo. Quá trình này tiếp diễn cho đến khi đi đến middleware cuối cùng. Tùy thuộc bạn muốn pipeline của bạn có bao nhiêu middleware.

Middleware cuối cùng sẽ trả request ngược lại cho middleware trước đó, và sẽ ngắt quá trình trong request pipeline.

Mỗi Middleware trong pipeline sẽ tuần tự có cơ hội thứ hai để kiểm tra lại request và điểm chỉnh response trước khi được trả lại.

Cuối cùng, response sẽ đến Kestrel nó sẽ trả response về cho client. Bất cứ middleware nào trong request pipeline đều có thể ngắt request pipeline tại chỗ đó với chỉ một bước đơn giản là không gán request đó đi tiếp.

Quá trình này giống một cuộc thi chạy tiếp sức giữa các middleware phải không các bạn

Cấu hình Request Pipeline

Để bắt đầu sử dụng Middleware, chúng ta cần thêm nó vào Request Pipeline. Nó được thực hiện bởi phương thức Configure trong Startup class. Phương thức Configure sẽ nhận các thể hiện của IApplicationBuilder, sử dụng chúng để đăng ký các middleware của chúng ta. Mở ứng dụng Helloworld trong bài Bắt đầu khởi tạo ứng dụng ASP.NET Core. Hoặc bạn có thể tạo một ứng dụng ASP.NET Core. Trong project template chọn Empty Project và chọn .NET Core, .NET Core 2.2.

Mở file Startup và tìm phương thức Configure sau đó thay đổi code như sau;

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
 
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("<div> Hello World from the middleware 1 </div>");
            });
 
        }

Chúng ta sử dụng phương thức app.Run để đăng ký middleware đầu tiên và hiển thị dòng chữ “Hello world from Middleware 1” khi nó thực thi.

Phương thức app.Run để lấy thể hiện của HttpContext. Bạn có thể sử dụng đối tượng Response từ HttpContext để viết thêm các thông tin vào HttpResponse.

Cấu hình Middleware với Use và Run

Sử dụng hai extension method Use và Run để cho phép chúng ta đăng ký Middleware nội bộ (inline middleware) vào request pipeline. Phương thức Run thêm vào một middleware ngắt. Phương thức Use thêm vào middleware, nó sẽ gọi middleware tiếp theo trong pipeline.

Giờ hãy thêm một middleware nữa sử dụng app.Run

 

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
 
            app.Use(async (context, next) =>
            {
                await context.Response.WriteAsync("<div> Hello World from the middleware 1 </div>");
            });
 
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("<div> Hello World from the middleware 2 </div>");
            });
 
        }

Phương thức app.Use có nhận hai tham số, một là HttpContext và hai là một RequestDelegate, về cơ bản nó là tham chiếu tới middleware tiếp theo. Giờ hãy chạy code.

Thông điệm “Hello world from the middleware 1” xuất hiện trên trình duyệt. Thông điệp từ middleware thứ 2 không xuất hiện. Bởi vì trách nhiệm của nó gọi middleware tiếp theo. Chúng ta có thể gọi middleware tiếp theo bằng cách gọi phương thức Invoke của middleware tiếp theo:

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
 
            app.Use(async (context, next) =>
            {
                await context.Response.WriteAsync("<div> Hello World from the middleware 1 </div>");
                await next.Invoke();
            });
 
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("<div> Hello World from the middleware 2 </div>");
            });
 
        }

Giờ chạy code bạn sẽ thấy cả hai dòng chữ. Tiếp theo chúng ta sẽ thêm một middleware nữa và thêm một dòng chữ theo sau khi gọi đến middleware tiếp theo

  public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
 
            app.Use(async (context, next) =>
            {
                await context.Response.WriteAsync("<div> Hello World from the middleware 1 </div>");
                await next.Invoke();
                await context.Response.WriteAsync("<div> Returning from the middleware 1 </div>");
            });
 
            app.Use(async (context, next) =>
            {
                await context.Response.WriteAsync("<div> Hello World from the middleware 2 </div>");
                await next.Invoke();
                await context.Response.WriteAsync("<div> Returning from the middleware 2 </div>");
            });
 
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("<div> Hello World from the middleware 3 </div>");
            });
 
        }

Chúng ta sẽ thấy rằng các middleware có cơ hội thứ 2 để sửa request trên đường quay lại.

Sắp xếp middleware

Middleware sẽ được thực thi theo thứ tự mà chúng ta thêm nó vào pipeline.

Custom Middleware

Trong phần trên chúng ta đã tạo các middleware nội bộ (inline middleware) sử dụng app.Use và app.Run. Cách khác là chúng ta tạo middleware bằng cách sử dụng các class. Class middleware không yêu cần triển khai bất cứ interface nào hoặc kế thừa từ bất cứ class nào. Tuy nhiên nó có 2 quy tắc mà chúng ta phải tuân theo:

  1. Class middleware phải khai báo public constructor và không static với ít nhất một tham số thuộc kiểu RequestDelegate. Đây chính là tham chiếu đến middelware tiếp theo trong pipeline. Khi bạn gọi RequestDelegate này thực tế là bạn đang gọi middleware kế tiếp trong pipeline.
  2. Class middleware phải định nghĩa một method public tên là Invoke nhận một HttpContext và trả về một Task. Đây là phương thức được gọi khi request tới middleware.

Tạo custom middleware

Giờ chúng ta sẽ tạo một class đơn giản để demo. Tên của nó là SimpleMiddleware.

public class SimpleMiddleware
    {
        private readonly RequestDelegate _next;
 
        public SimpleMiddleware(RequestDelegate next)
        {
            _next = next;
        }
 
        public async System.Threading.Tasks.Task Invoke(HttpContext context)
        {
            await context.Response.WriteAsync("<div> Hello from Simple Middleware </div>");
            await _next(context);
            await context.Response.WriteAsync("<div> Bye from Simple Middleware </div>");
        }
    }

Đầu tiên trong constructor, chúng ta sẽ lấy tham chiếu của middleware tiếp theo trong pipeline. Chúng ta lưu nó trong biến local tên là _next


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

Tiếp theo chúng ta phải khai báo phương thức Invoke, nó sẽ nhận tham chiếu đến HttpContext. Chúng ta sẽ viết ra một vài dòng chữ vào response và sau đó gọi middleware tiếp theo sử dụng await _next(context).

public async System.Threading.Tasks.Task Invoke(HttpContext context)
        {
 
            await context.Response.WriteAsync("<div> Hello from Simple Middleware </div>");
            await _next(context);
            await context.Response.WriteAsync("<div> Bye from Simple Middleware </div>");
 
        }

Tiếp theo chúng ta sẽ cần đăng ký middleware trong request pipeline. Chúng ta có thể sử dụng phương thức UseMiddleware như dưới đây:

app.UseMiddleware<SimpleMiddleware>();

Copy đoạn trên vào phương thức Configure. Chạy code và bạn sẽ thấy dòng chữ xuất ra từ SimpleMiddleware hiển thị trên trình duyệt.

Extension Method

Chúng ta có thể tạo ra một extension method đơn giản để đăng ký middleware. Tạo một class khác có tên SomeMiddlewarerExtensions và tạo một phương thức UseSimpleMiddleware như dưới:

public static class SomeMiddlewarerExtensions
    {
        public static IApplicationBuilder UseSimpleMiddleware(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<SimpleMiddleware>();
        }
    }

Giờ thay vì sử dụng:

app.UseMiddleware<SimpleMiddleware>();

Chúng ta sẽ sử dụng:

app.UseSimpleMiddleware();

để đăng ký middleware.

Tổng kết

Middleware là mã nguồn hay là các thành phần riêng lẻ để xử lý các request đến. Các middleware này đứng theo dãy với nhau gọi là request pipeline. Chúng ta tạo middleware và đăng ký nó trong phương thức Configure của class Startup.

Bài viết liên quan

+61404577839