ระดับการใช้งาน 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 |
|---|---|---|---|
| Authorization | IAuthorizationFilter | ก่อนทุกอย่าง - ตรวจสอบสิทธิ์ | [Authorize], [AllowAnonymous] |
| Resource | IResourceFilter | ก่อน/หลัง Model Binding | - |
| Action | IActionFilter | ก่อน/หลัง Action Execute | [ValidateAntiForgeryToken] |
| Exception | IExceptionFilter | เมื่อมี Exception | [HandleError] |
| Result | IResultFilter | ก่อน/หลัง 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)
});
สรุป: เลือกระดับไหนดี?
| ระดับ | เหมาะสำหรับ | ตัวอย่าง |
|---|---|---|
| Global | Cross-cutting concerns: Logging, Error Handling, Global Auth, HTTPS Redirect | HandleError, Authorize (Global), Custom Logging |
| Controller | Business 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