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

Cách thêm custom message handlers vào pipeline trong ASP.NET WebAPI C#

Để tạo custom Server-Side HTTP Message Handler trong ASP.NET Web API, cần tạo class kế thừa từ System.Net.Http.DelegatingHandler.

Bước 1 - Tạo controller và action methods tương ứng.

Ví dụ Controller

using DemoWebApplication.Models; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web.Http; 

namespace DemoWebApplication.Controllers { 
    public class StudentController : ApiController { 
        List<Student> students = new List<Student> { 
            new Student { Id = 1, Name = "Mark" }, 
            new Student { Id = 2, Name = "John" } 
        }; 
        
        public IEnumerable<Student> Get() { 
            return students; 
        } 
        
        public Student Get(int id) { 
            var studentForId = students.FirstOrDefault(x => x.Id == id); 
            return studentForId; 
        } 
    } 
}

Bước 2 - Tạo CustomMessageHandler class.

Ví dụ

using System.Net; 
using System.Net.Http; 
using System.Threading; 
using System.Threading.Tasks; 

namespace DemoWebApplication { 
    public class CustomMessageHandler : DelegatingHandler { 
        protected async override Task<HttpResponseMessage> 
            SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { 
            var response = new HttpResponseMessage(HttpStatusCode.OK) { 
                Content = new StringContent("Result through custom message handler..") 
            }; 
            var taskCompletionSource = new TaskCompletionSource<HttpResponseMessage>(); 
            taskCompletionSource.SetResult(response); 
            return await taskCompletionSource.Task; 
        } 
    } 
}

Khai báo CustomMessageHandler class kế thừa DelegatingHandler và override hàm SendAsync().

Khi HTTP request đến, CustomMessageHandler sẽ execute và trả về HTTP message riêng, không xử lý request tiếp. Vậy là ngăn chặn mọi HTTP request पहुंच đến controller.

Bước 3 - Đăng ký CustomMessageHandler trong Global.asax class.

public class WebApiApplication : System.Web.HttpApplication { 
    protected void Application_Start() { 
        GlobalConfiguration.Configure(WebApiConfig.Register); 
        GlobalConfiguration.Configuration.MessageHandlers.Add(new CustomMessageHandler()); 
    } 
}

Bước 4 - Run ứng dụng và cung cấp URL.

Output cho thấy message set trong CustomMessageHandler class. HTTP message không đến Get() action mà trả về từ CustomMessageHandler.

Message Handler Pattern chuẩn (Chain of Responsibility)

Thực tế, custom handler thường cho phép request đi tiếp (call base.SendAsync) và chỉ can thiệp trước/sau:

public class LoggingHandler : DelegatingHandler {
    protected override async Task SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken) {
        
        // Trước khi request đi vào pipeline
        var startTime = DateTime.UtcNow;
        Debug.WriteLine($"Request: {request.Method} {request.RequestUri}");
        
        // Gọi inner handler (tiếp theo trong chain)
        var response = await base.SendAsync(request, cancellationToken);
        
        // Sau khi response quay về
        var duration = DateTime.UtcNow - startTime;
        Debug.WriteLine($"Response: {response.StatusCode} in {duration.TotalMs}ms");
        
        return response;
    }
}

Đăng ký nhiều handlers (thứ tự quan trọng)

public static void Register(HttpConfiguration config) {
    // Thứ tự thêm = thứ tự xử lý request (first in, first process)
    // Response xử lý ngược lại (last in, first process response)
    
    config.MessageHandlers.Add(new LoggingHandler());        // 1. Log request/response
    config.MessageHandlers.Add(new AuthenticationHandler()); // 2. Auth
    config.MessageHandlers.Add(new CorsHandler());           // 3. CORS
    config.MessageHandlers.Add(new CompressionHandler());    // 4. Compression
    
    // ... routes config
}

Handler short-circuit (ngăn request đi tiếp)

public class ApiKeyHandler : DelegatingHandler {
    protected override async Task SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken) {
        
        if (!request.Headers.Contains("X-API-Key")) {
            // Short-circuit: trả về 401 ngay, không gọi base.SendAsync
            var response = request.CreateResponse(HttpStatusCode.Unauthorized);
            response.Content = new StringContent("API Key required");
            return response;
        }
        
        // Có API Key, cho đi tiếp
        return await base.SendAsync(request, cancellationToken);
    }
}

Client-side Message Handler (HttpClient)

var handler = new HttpClientHandler();
var client = new HttpClient(new LoggingHandler(handler) {
    InnerHandler = new RetryHandler(handler)
});

// Hoặc dùng DelegatingHandler chain
var client = new HttpClient(new CustomHandler {
    InnerHandler = new HttpClientHandler()
});