เพื่อสร้าง Custom Server-Side HTTP Message Handler ใน ASP.NET Web API เราต้องสร้าง Class ที่ต้องสืบทอดจาก System.Net.Http.DelegatingHandler
ขั้นตอนที่ 1: สร้าง Controller และ Action Methods
using DemoWebApplication.Models;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace DemoWebApplication.Controllers {
public class StudentController : ApiController {
List students = new List {
new Student { Id = 1, Name = "Mark" },
new Student { Id = 2, Name = "John" }
};
public IEnumerable Get() {
return students;
}
public Student Get(int id) {
var studentForId = students.FirstOrDefault(x => x.Id == id);
return studentForId;
}
}
}
ขั้นตอนที่ 2: สร้าง Custom Message Handler Class
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace DemoWebApplication {
public class CustomMessageHandler : DelegatingHandler {
protected async override Task
SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
var response = new HttpResponseMessage(HttpStatusCode.OK) {
Content = new StringContent("Result through custom message handler..")
};
var taskCompletionSource = new TaskCompletionSource();
taskCompletionSource.SetResult(response);
return await taskCompletionSource.Task;
}
}
}
เราได้ประกาศ CustomMessageHandler Class สืบทอดจาก DelegatingHandler และ Override ฟังก์ชัน SendAsync()
เมื่อ HTTP Request มาถึง CustomMessageHandler จะ Execute และส่งคืน HTTP Message เอง โดยไม่ Process Request ต่อไป นั่นหมายความว่าเรากำลังป้องกันไม่ให้ HTTP Request ไปถึง Controller
ขั้นตอนที่ 3: ลงทะเบียน CustomMessageHandler ใน Global.asax
public class WebApiApplication : System.Web.HttpApplication {
protected void Application_Start() {
GlobalConfiguration.Configure(WebApiConfig.Register);
GlobalConfiguration.Configuration.MessageHandlers.Add(new CustomMessageHandler());
}
}
ขั้นตอนที่ 4: ทดสอบ
Run Application และเรียก URL จะได้ Response จาก CustomMessageHandler แทนที่จะไปถึง Controller
รูปแบบ Message Handler ที่สมบูรณ์กว่า (Chaining)
public class LoggingMessageHandler : DelegatingHandler {
protected async override Task SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken) {
// Before request goes to inner handler
Debug.WriteLine($"Request: {request.Method} {request.RequestUri}");
// Call inner handler (next in pipeline)
var response = await base.SendAsync(request, cancellationToken);
// After response comes back
Debug.WriteLine($"Response: {response.StatusCode}");
return response;
}
}
public class ApiKeyValidationHandler : DelegatingHandler {
protected async override Task SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken) {
// Validate API Key
if (!request.Headers.Contains("X-Api-Key")) {
var response = new HttpResponseMessage(HttpStatusCode.Unauthorized) {
Content = new StringContent("API Key required")
};
return response; // Short-circuit - ไม่ไป Inner Handler
}
return await base.SendAsync(request, cancellationToken);
}
}
// ลงทะเบียนในลำดับ (First added = Outermost)
config.MessageHandlers.Add(new LoggingMessageHandler());
config.MessageHandlers.Add(new ApiKeyValidationHandler());
config.MessageHandlers.Add(new CustomMessageHandler());
Client-Side Message Handler
ฝั่ง Client ใช้กับ HttpClient:
var handler = new HttpClientHandler();
var customHandler = new CustomClientHandler(handler);
var client = new HttpClient(customHandler);
public class CustomClientHandler : DelegatingHandler {
protected override async Task SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken) {
// Add custom header
request.Headers.Add("X-Custom-Header", "MyValue");
var response = await base.SendAsync(request, cancellationToken);
// Log response
Debug.WriteLine($"Response: {response.StatusCode}");
return response;
}
}