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

C# ASP.NET Core Middleware ต่างจาก HttpModule ยังไง

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()
CORSCross-Origin Resource SharingUseCors()
Routingจับคู่ RouteUseRouting()
Sessionจัดการ SessionUseSession()
DiagnosticsError Pages, Status Code PagesUseDeveloperExceptionPage(), UseStatusCodePages()
Static Filesเสิร์ฟไฟล์ StaticUseStaticFiles()
HTTPS RedirectionRedirect HTTP → HTTPSUseHttpsRedirection()

การย้ายจาก HttpModule มา Middleware

HttpModule EventMiddleware Equivalent
BeginRequestต้น Pipeline (Use แรกๆ)
AuthenticateRequestUseAuthentication()
AuthorizeRequestUseAuthorization()
AcquireRequestState (Session)UseSession()
PreRequestHandlerExecuteก่อน MapControllers/Endpoints
PostRequestHandlerExecuteหลัง MapControllers (ใน Response phase)
EndRequestท้าย Pipeline (Response phase)
ErrorUseExceptionHandler / 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) => ...)