Middleware vs HttpModule - ความแตกต่างหลัก
ทั้งคู่ใช้สำหรับจัดการ HTTP Request Pipeline แต่มีความแตกต่างอย่างมากระหว่าง ASP.NET Classic (HttpModule) และ ASP.NET Core (Middleware)
ตารางเปรียบเทียบ
| ด้านเปรียบเทียบ | HttpModule (ASP.NET Classic) | Middleware (ASP.NET Core) |
| การตั้งค่า (Configuration) | web.config หรือ global.asax (XML/Declarative) | Startup.cs / Program.cs (Code/Imperative) |
| ลำดับการ Execute | ขึ้นกับ Application Life Cycle Events (คงที่) | ควบคุมได้เต็มที่** - ตามลำดับที่ Add |
| ลำดับ Response | เหมือน Request (Event-based) | กลับกัน (Reverse)** - Last In, First Out |
| การควบคุม Pipeline | ผูกกับ Event (BeginRequest, EndRequest, ฯลฯ) | อิสระจาก Event - เขียน Logic เอง |
| Platform Dependency | ผูกกับ System.Web (Windows/IIS เท่านั้น) | Host Independent** - รันได้ทุก Platform |
| Testing | ยาก (ต้อง Host ใน IIS) | ง่าย (TestHost, In-memory) |
| Async Support | จำกัด (Event-based) | Native Async/Await |
HttpModule - แบบเก่า (ASP.NET 4.x)
// HttpModule - ต้อง implement IHttpModule
public class CustomModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += OnBeginRequest;
context.EndRequest += OnEndRequest;
context.Error += OnError;
}
private void OnBeginRequest(object sender, EventArgs e)
{
var app = (HttpApplication)sender;
// Logic ที่นี่
}
public void Dispose() { }
}
ลงทะเบียนใน web.config:
<system.webServer>
<modules>
<add name="CustomModule" type="MyApp.CustomModule" />
</modules>
</system.webServer>
Middleware - แบบใหม่ (ASP.NET Core)
1. Inline Middleware (Lambda)
var app = builder.Build();
app.Use(async (context, next) =>
{
// Before next middleware
var startTime = DateTime.UtcNow;
context.Response.Headers["X-Request-Start"] = startTime.ToString("O");
await next(context); // เรียก Middleware ถัดไป
// After next middleware (Response phase)
var duration = DateTime.UtcNow - startTime;
context.Response.Headers["X-Response-Time"] = duration.TotalMilliseconds.ToString();
});
app.MapGet("/", () => "Hello World");
app.Run();
2. Class-based Middleware (แนะนำสำหรับ Logic ซับซ้อน)
public class RequestTimingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestTimingMiddleware> _logger;
public RequestTimingMiddleware(RequestDelegate next, ILogger<RequestTimingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
var startTime = DateTime.UtcNow;
_logger.LogInformation("Request starting: {Path}", context.Request.Path);
try
{
await _next(context); // เรียก Middleware ถัดไป
}
finally
{
var duration = DateTime.UtcNow - startTime;
_logger.LogInformation("Request finished: {Path} in {Duration}ms",
context.Request.Path, duration.TotalMilliseconds);
}
}
}
// Extension method สำหรับลงทะเบียนง่าย
public static class RequestTimingMiddlewareExtensions
{
public static IApplicationBuilder UseRequestTiming(this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestTimingMiddleware>();
}
}
3. ลงทะเบียนใน Pipeline (ลำดับสำคัญ!)
var app = builder.Build();
// 1. Exception Handling (บนสุด)
app.UseExceptionHandler("/error");
// 2. HTTPS/HSTS
app.UseHsts();
app.UseHttpsRedirection();
// 3. Static Files
app.UseStaticFiles();
// 4. Routing
app.UseRouting();
// 5. Custom Middleware
app.UseRequestTiming(); // เราสร้างขึ้นมา
// 6. Authentication/Authorization
app.UseAuthentication();
app.UseAuthorization();
// 7. Endpoints (สุดท้าย)
app.MapControllers();
app.MapRazorPages();
app.Run();
ความแตกต่างสำคัญ: Request/Response Order
// Middleware Pipeline Flow (Request -> Response)
app.Use(async (ctx, next) =>
{
// 1A. Request: Middleware A เริ่มทำงานก่อน
await next(ctx);
// 1B. Response: Middleware A ทำงานทีหลังสุด (Reverse)
});
app.Use(async (ctx, next) =>
{
// 2A. Request: Middleware B ทำงานต่อ
await next(ctx);
// 2B. Response: Middleware B ทำงานก่อน A
});
app.Run(async ctx =>
{
// 3. Terminal Middleware (Endpoint) - จบ Request
await ctx.Response.WriteAsync("Hello");
});
// ลำดับ Execution:
// Request: 1A → 2A → 3 (Endpoint)
// Response: 3 → 2B → 1B
Built-in Middlewares ใน ASP.NET Core
| Middleware | หน้าที่ | Extension Method |
| Authentication | ยืนยันตัวตน | UseAuthentication() |
| Authorization | อนุมัติสิทธิ์ | UseAuthorization() |
| CORS | Cross-Origin Resource Sharing | UseCors() |
| Routing | จับคู่ Route | UseRouting() |
| Session | จัดการ Session | UseSession() |
| Diagnostics | Error Pages, Status Code Pages | UseDeveloperExceptionPage(), UseStatusCodePages() |
| Static Files | เสิร์ฟไฟล์ Static | UseStaticFiles() |
| HTTPS Redirection | Redirect HTTP → HTTPS | UseHttpsRedirection() |
การย้ายจาก HttpModule มา Middleware
| HttpModule Event | Middleware Equivalent |
| BeginRequest | ต้น Pipeline (Use แรกๆ) |
| AuthenticateRequest | UseAuthentication() |
| AuthorizeRequest | UseAuthorization() |
| AcquireRequestState (Session) | UseSession() |
| PreRequestHandlerExecute | ก่อน MapControllers/Endpoints |
| PostRequestHandlerExecute | หลัง MapControllers (ใน Response phase) |
| EndRequest | ท้าย Pipeline (Response phase) |
| Error | UseExceptionHandler / try-catch ใน Middleware |
สรุป
- Middleware = Code-based, Ordered, Reversible, Cross-platform
- HttpModule = Config-based, Event-driven, Fixed order, Windows-only
- Middleware ให้ Control พipeline เต็มที่ เขียน Test ได้ง่าย รองรับ Async
- ลำดับ Request = ลำดับที่ Add, ลำดับ Response = กลับกัน (LIFO)
- ใช้
UseMiddleware<T>() หรือ Lambda Use(async (ctx, next) => ...)