Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C#

การใช้งาน DelegatingHandler ใน ASP.NET WebAPI C#

ใน Message Handler ชุดของ Message Handlers จะถูกเชื่อมต่อกันเป็น Chain Handler แรกจะรับ HTTP Request ทำ Processing แล้วส่ง Request ไปยัง Handler ถัดไป ในบางจุด Response จะถูกสร้างขึ้นและกลับขึ้นไปใน Chain รูปแบบนี้เรียกว่า Delegating Handler

นอกจาก Built-in Server-side Message Handlers แล้ว เรายังสามารถสร้าง Custom Server-Side HTTP Message Handlers ได้ ใน ASP.NET Web API เราใช้ DelegatingHandler ต้องสร้าง Class สืบทอดจาก System.Net.Http.DelegatingHandler คลาส Custom นั้นควร Override เมธอด SendAsync

Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);

เมธอดนี้รับ HttpRequestMessage เป็น Input และคืนค่า HttpResponseMessage แบบ Asynchronous การ Implement แบบปกติจะทำดังนี้:

  1. Process Request Message
  2. Call base.SendAsync เพื่อส่ง Request ไปยัง Inner Handler
  3. Inner Handler คืนค่า Response Message (Async)
  4. Process Response และ Return ให้ Caller

ตัวอย่าง: Logging Handler (Pass-through)

public class CustomMessageHandler : DelegatingHandler {
    protected async override Task SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken) {
        
        Debug.WriteLine("CustomMessageHandler processing the request");
        
        // เรียก Inner Handler (สำคัญ: ต้อง await)
        var response = await base.SendAsync(request, cancellationToken);
        
        Debug.WriteLine("CustomMessageHandler processing the response");
        return response;
    }
}

ตัวอย่าง: Short-circuit Handler (Skip Inner Handler)


public class CustomMessageHandler : DelegatingHandler {
    protected override Task SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken) {
        
        // สร้าง Response เอง ไม่เรียก Inner Handler
        var response = new HttpResponseMessage(HttpStatusCode.OK) {
            Content = new StringContent("Skipping the inner handler")
        };
        
        // TaskCompletionSource สร้าง Task ที่ไม่มี Delegate
        var taskCompletion = new TaskCompletionSource();
        taskCompletion.SetResult(response);
        return taskCompletion.Task;
    }
}

ตัวอย่าง: Rate Limiting Handler


public class RateLimitingHandler : DelegatingHandler {
    private static readonly ConcurrentDictionary _counters = new();
    
    protected override async Task SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken) {
        
        var clientIp = GetClientIp(request);
        var counter = _counters.GetOrAdd(clientIp, _ => new RequestCounter());
        
        if (counter.Increment() > 100) { // 100 requests per window
            var response = new HttpResponseMessage(HttpStatusCode.TooManyRequests) {
                Content = new StringContent("Rate limit exceeded"),
                ReasonPhrase = "Too Many Requests"
            };
            response.Headers.RetryAfter = new System.Net.Http.Headers.RetryConditionHeaderValue(TimeSpan.FromMinutes(1));
            return response;
        }
        
        return await base.SendAsync(request, cancellationToken);
    }
    
    private string GetClientIp(HttpRequestMessage request) {
        // Implementation to extract client IP
        return request.GetOwinContext()?.Request.RemoteIpAddress ?? "unknown";
    }
    
    private class RequestCounter {
        private int _count = 0;
        private DateTime _windowStart = DateTime.UtcNow;
        
        public int Increment() {
            var now = DateTime.UtcNow;
            if (now - _windowStart > TimeSpan.FromMinutes(1)) {
                _count = 0;
                _windowStart = now;
            }
            return Interlocked.Increment(ref _count);
        }
    }
}

ลำดับการ Execute ของ Message Handlers

Handlers ถูก Execute ในลำดับที่ Add เข้าไปใน MessageHandlers Collection:


// Registration Order (Outer to Inner)
config.MessageHandlers.Add(new Handler1()); // Outermost - First to receive Request
config.MessageHandlers.Add(new Handler2());
config.MessageHandlers.Add(new Handler3()); // Innermost - Last before Controller

// Request Flow: Handler1 → Handler2 → Handler3 → Controller
// Response Flow: Controller → Handler3 → Handler2 → Handler1

Built-in Server-side Handlers

  • HttpServer - รับ Request จาก Host
  • HttpRoutingDispatcher - Dispatch ตาม Route
  • HttpControllerDispatcher - ส่ง Request ไปยัง Web API Controller

Use Cases สำหรับ DelegatingHandler

  • Logging และ Monitoring
  • Authentication/Authorization (API Key, JWT Validation)
  • Rate Limiting / Throttling
  • Request/Response Transformation
  • Caching
  • Error Handling / Exception Logging
  • Correlation ID Propagation