Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> C#

Cách dùng DelegatingHandler trong ASP.NET WebAPI C#

Trong message handler, một chuỗi message handlers được nối lại với nhau. Handler đầu nhận HTTP request, xử lý một chút, và pass request cho handler tiếp theo. Tại một điểm nào đó, response được tạo và quay ngược lên chuỗi. Pattern này gọi là delegating handler.

Ngoài built-in Server-side Message Handlers, ta cũng tạo custom Server-Side HTTP Message Handlers. Để tạo custom Server-Side HTTP Message Handler trong ASP.NET Web API, ta dùng DelegatingHandler. Tạo class kế thừa System.Net.Http.DelegatingHandler. Custom class đó override phương thức SendAsync.

Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);

Phương thức nhận HttpRequestMessage input và async trả về HttpResponseMessage. Implementation điển hình:

  • Process request message.
  • Call base.SendAsync để gửi request cho inner handler.
  • Inner handler trả về response message. (Bước này async.)
  • Process response và return cho caller.

Ví dụ: Handler chuẩn (cho request đi tiếp)

public class CustomMessageHandler : DelegatingHandler { 
    protected async override Task<HttpResponseMessage> SendAsync( 
        HttpRequestMessage request, CancellationToken cancellationToken) { 
        Debug.WriteLine("CustomMessageHandler processing the request"); 
        
        // Gọi inner handler (tiếp theo trong chain)
        var response = await base.SendAsync(request, cancellationToken); 
        
        Debug.WriteLine("CustomMessageHandler processing the response"); 
        return response; 
    } 
}

Ví dụ: Handler short-circuit (tự tạo response, không gọi inner)

public class CustomMessageHandler : DelegatingHandler { 
    protected override Task<HttpResponseMessage> SendAsync( 
        HttpRequestMessage request, CancellationToken cancellationToken) { 
        // Tự tạo response
        var response = new HttpResponseMessage(HttpStatusCode.OK) { 
            Content = new StringContent("Skipping the inner handler") 
        }; 
        
        // TaskCompletionSource tạo task không chứa delegate
        var taskCompletion = new TaskCompletionSource<HttpResponseMessage>(); 
        taskCompletion.SetResult(response); 
        return taskCompletion.Task; 
    } 
}

Pipeline Execution Flow (Luồng thực thi)

Request Flow (Downstream):          Response Flow (Upstream):
┌─────────────────────┐             ┌─────────────────────┐
│ Handler A (Outer)   │────Request──▶│ Handler A (Outer)   │
│   - Pre-process     │             │   - Post-process    │
└─────────┬───────────┘             └──────────▲──────────┘
          │                                    │
          ▼                                    │
┌─────────────────────┐             ┌──────────┴──────────┐
│ Handler B (Middle)  │────Request──▶│ Handler B (Middle)  │
│   - Pre-process     │             │   - Post-process    │
└─────────┬───────────┘             └──────────▲──────────┘
          │                                    │
          ▼                                    │
┌─────────────────────┐             ┌──────────┴──────────┐
│ Handler C (Inner)   │────Request──▶│ Handler C (Inner)   │
│   - Controller      │             │   - Create Response │
│   - Action Exec     │             │                     │
└─────────────────────┘             └─────────────────────┘

Các Built-in Handlers trong Web API

  • HttpServer - Top-level handler, nhận request từ host
  • HttpRoutingDispatcher - Dispatch request dựa trên route
  • HttpControllerDispatcher - Gửi request đến Web API controller

Use Cases thực tế

Handler Mục đích Short-circuit?
LoggingHandler Log request/response, timing Không
AuthenticationHandler Validate token, API key Có (401 nếu invalid)
RateLimitingHandler Giới hạn request rate Có (429 nếu vượt limit)
CorsHandler Thêm CORS headers Không (chỉ modify response)
CompressionHandler Nén response (gzip/deflate) Không
ErrorHandlingHandler Bắt exception, trả error format chuẩn Có (khi exception)

ASP.NET Core Equivalent

Trong ASP.NET Core, Middleware thay thế DelegatingHandler:

// Middleware tương đương
public class CustomMiddleware {
    private readonly RequestDelegate _next;
    
    public CustomMiddleware(RequestDelegate next) {
        _next = next;
    }
    
    public async Task InvokeAsync(HttpContext context) {
        // Pre-process
        await _next(context); // Call next middleware
        // Post-process
    }
}

// Register trong Startup
app.UseMiddleware();