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

Filter ใน ASP.NET MVC C# ใช้ได้ที่ระดับไหนบ้าง

ระดับการใช้งาน Filter ใน ASP.NET MVC

ใน ASP.NET MVC Filter สามารถนำไปใช้ได้ที่ 3 ระดับ ตามขอบเขตการทำงาน:

1. Action Method Level (ระดับ Action Method)

Filter ทำงาน เฉพาะ Action Method นั้นๆ ที่ตกแต่ง Attribute

using System.Web.Mvc;

namespace DemoMvcApplication.Controllers
{
    public class HomeController : Controller
    {
        [Authorize]  // Action Level Filter
        public string Index()
        {
            return "Index Invoked";
        }
        
        public string About()  // ไม่มี Filter
        {
            return "About Invoked";
        }
    }
}

2. Controller Level (ระดับ Controller)

Filter ทำงานกับ ทุก Action Method ใน Controller นั้น

using System.Web.Mvc;

namespace DemoMvcApplication.Controllers
{
    [Authorize]  // Controller Level Filter
    public class HomeController : Controller
    {
        public string Index1()
        {
            return "Index1 Invoked";
        }
        
        public string Index2()
        {
            return "Index2 Invoked";
        }
        
        [AllowAnonymous]  // ยกเว้น Action นี้
        public string PublicPage()
        {
            return "Public";
        }
    }
}

3. Global Level (ระดับ Application)

Filter ทำงานกับ ทุก Controller และ Action ในทั้ง Application ตั้งค่าใน Global.asax.cs (ASP.NET MVC 5) หรือ Startup.cs (ASP.NET Core)

ASP.NET MVC 5 (Global.asax.cs)

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
}

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());  // Global Error Handling
        filters.Add(new AuthorizeAttribute());    // Global Authorization
    }
}

ASP.NET Core (Program.cs / Startup.cs)

// Program.cs (.NET 6+)
var builder = WebApplication.CreateBuilder(args);

// Global Filters ผ่าน MVC Options
builder.Services.AddControllersWithViews(options =>
{
    // Global Authorization
    options.Filters.Add(new AuthorizeAttribute());
    
    // Global Exception Handling
    options.Filters.Add(new HandleErrorAttribute());
    
    // Global Action Filter (Custom)
    options.Filters.Add(typeof(CustomActionFilter));
    
    // หรือแบบ Instance
    options.Filters.Add(new CustomActionFilter());
});

var app = builder.Build();

ประเภท Filter (Filter Types)

ประเภทInterfaceจุดทำงานตัวอย่าง Built-in
AuthorizationIAuthorizationFilterก่อนทุกอย่าง - ตรวจสอบสิทธิ์[Authorize], [AllowAnonymous]
ResourceIResourceFilterก่อน/หลัง Model Binding-
ActionIActionFilterก่อน/หลัง Action Execute[ValidateAntiForgeryToken]
ExceptionIExceptionFilterเมื่อมี Exception[HandleError]
ResultIResultFilterก่อน/หลัง Action Result Execute-

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

Request
  │
  ▼
[Global Authorization Filters]
  │
  ▼
[Controller Authorization Filters]
  │
  ▼
[Action Authorization Filters]
  │
  ▼
[Global Resource Filters - OnResourceExecuting]
  │
  ▼
[Controller Resource Filters - OnResourceExecuting]
  │
  ▼
[Action Resource Filters - OnResourceExecuting]
  │
  ▼
    Model Binding
  │
  ▼
[Global Action Filters - OnActionExecuting]
  │
  ▼
[Controller Action Filters - OnActionExecuting]
  │
  ▼
[Action Action Filters - OnActionExecuting]
  │
  ▼
    ACTION METHOD EXECUTES
  │
  ▼
[Action Action Filters - OnActionExecuted] (Reverse)
  │
  ▼
[Controller Action Filters - OnActionExecuted]
  │
  ▼
[Global Action Filters - OnActionExecuted]
  │
  ▼
[Action Result Filters - OnResultExecuting]
  │
  ▼
    ACTION RESULT EXECUTES (View, Json, File, etc.)
  │
  ▼
[Action Result Filters - OnResultExecuted] (Reverse)
  │
  ▼
[Controller Result Filters - OnResultExecuted]
  │
  ▼
[Global Result Filters - OnResultExecuted]
  │
  ▼
[Resource Filters - OnResourceExecuted] (Reverse)
  │
  ▼
Response

ตัวอย่าง Custom Action Filter

using System.Diagnostics;
using Microsoft.AspNetCore.Mvc.Filters;

public class LogActionFilter : IActionFilter
{
    private readonly ILogger<LogActionFilter> _logger;
    
    public LogActionFilter(ILogger<LogActionFilter> logger)
    {
        _logger = logger;
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        _logger.LogInformation("Action Executing: {Controller}.{Action}", 
            context.Controller.GetType().Name, 
            context.ActionDescriptor.DisplayName);
        
        // สามารถ Cancel Action ได้
        // context.Result = new BadRequestResult();
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        if (context.Exception != null)
        {
            _logger.LogError(context.Exception, "Action Failed: {Action}", 
                context.ActionDescriptor.DisplayName);
        }
        else
        {
            _logger.LogInformation("Action Executed: {Action}", 
                context.ActionDescriptor.DisplayName);
        }
    }
}

// ลงทะเบียน Global
builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add();  // Type-based (DI support)
});

สรุป: เลือกระดับไหนดี?

ระดับเหมาะสำหรับตัวอย่าง
GlobalCross-cutting concerns: Logging, Error Handling, Global Auth, HTTPS RedirectHandleError, Authorize (Global), Custom Logging
ControllerBusiness logic ร่วมกันใน Controller: Auth, Validation, Audit[Authorize], [ValidateModel], Custom Audit
Actionเฉพาะเจาะจง: AllowAnonymous, Specific Validation, Custom Logic[AllowAnonymous], [HttpPost], Custom Filter

Best Practices

  • ใช้ Global สำหรับ Infrastructure concerns (Logging, Error Handling)
  • ใช้ Controller สำหรับ Business rules ที่ร่วมกันใน Controller
  • ใช้ Action สำหรับ Exception cases หรือ Special handling
  • หลีกเลี่ยง Logic ซับซ้อนใน Filter - ย้ายไป Service/Action ดีกว่า
  • Filter ที่ต้องการ DI ให้ลงทะเบียนแบบ Type options.Filters.Add<TFilter>() ไม่ใช่ Instance