Filters
|
This section documents ASP.NET MVC 5.3.x, ASP.NET Web API 2.2, ASP.NET Web Pages 3, OWIN/Katana, SignalR 2,
and ASP.NET Identity 2 — all running on .NET Framework 4.8.1 — the This is not ASP.NET Core MVC. ASP.NET MVC 5 is the pre-Core, This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
This page documents ASP.NET MVC 5.3.x filters on .NET Framework 4.8.1 — not ASP.NET Core’s filter pipeline (same four kinds plus endpoint filters, different interfaces — see Filters and the MVC Pipeline under ASP.NET Core).
The four filter kinds
| Kind | Interface | Runs |
|---|---|---|
Authorization |
|
First, before model binding — decides whether the request may proceed at all. |
Action |
|
|
Result |
|
|
Exception |
|
Only if an unhandled exception propagates out of model binding, action execution, or result execution. |
[Authorize] // authorization filter
[RequireHttps] // authorization filter
public class AccountController : Controller
{
[AllowAnonymous] // opts this action out of [Authorize] above
public ActionResult Login() => View();
[HttpPost]
[ValidateAntiForgeryToken] // authorization filter -- validates the CSRF token
public ActionResult Login(LoginViewModel model) { ... }
[OutputCache(Duration = 60, VaryByParam = "none")] // result filter
public ActionResult Terms() => View();
[HandleError(ExceptionType = typeof(SqlException), View = "DatabaseError")] // exception filter
public ActionResult Report() { ... }
}
Execution order and pipeline
Within a scope, filters of the same kind run in Order (ascending; default -1 means "unspecified,
runs before explicitly ordered ones") and then by FilterScope (First, Global, Controller,
Action, Last) when Order ties — global filters generally run outermost, action-level filters innermost,
for the "before" half, and in reverse for the "after" half.
Global filters
FilterConfig.RegisterGlobalFilters (called from Application_Start, see
Getting Started) registers filters that apply to every action in the
application, without decorating each controller:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new RequireHttpsAttribute());
}
}
[ChildActionOnly]
Marks an action so it can only be invoked via Html.Action/Html.RenderAction (see
Views, Layouts, and Partials) — a direct browser request
to its URL returns an error. Typical for a widget-like action that only makes sense embedded in a page:
[ChildActionOnly]
public ActionResult CartSummary() => PartialView(_cart.GetSummary());
Filter overrides
[OverrideAuthorization] (and the analogous [OverrideActionFilters] etc. from MVC 5) lets an action or
controller opt out of filters that would otherwise apply from a higher scope (global or controller-level),
without removing the global registration itself:
[Authorize(Roles = "Admin")]
public class AdminController : Controller
{
[OverrideAuthorization]
[AllowAnonymous]
public ActionResult Status() => Content("ok"); // bypasses the controller-level [Authorize] entirely
}
IFilterProvider and DI in filters
By default, attribute-based filters are constructed with a parameterless constructor, so they cannot easily
take a DI-resolved dependency. A custom IFilterProvider (or a "filter attribute as a marker + separately
registered filter implementation" pattern, using FilterAttributeFilterProvider alongside a DI-aware
provider) lets filters be resolved from a container instead:
public class AuditFilterAttribute : FilterAttribute, IActionFilter
{
public void OnActionExecuting(ActionExecutingContext ctx)
{
var audit = DependencyResolver.Current.GetService<IAuditLogger>(); // classic MVC 5 service-locator seam
audit.Log(ctx.ActionDescriptor.ActionName);
}
public void OnActionExecuted(ActionExecutedContext ctx) { }
}
DependencyResolver.Current is MVC 5’s built-in service-locator abstraction that most third-party containers
(Ninject, Autofac, Unity) plug into via IDependencyResolver.
Writing a custom filter
public class LogExecutionTimeAttribute : ActionFilterAttribute // ActionFilterAttribute implements both
{ // IActionFilter and IResultFilter
public override void OnActionExecuting(ActionExecutingContext ctx)
=> ctx.HttpContext.Items["__stopwatch"] = Stopwatch.StartNew();
public override void OnResultExecuted(ResultExecutedContext ctx)
{
var sw = (Stopwatch)ctx.HttpContext.Items["__stopwatch"];
sw.Stop();
Trace.TraceInformation($"{ctx.RouteData.Values["action"]} took {sw.ElapsedMilliseconds}ms");
}
}
See Understanding
Action Filters for the full ActionFilterAttribute base class and
Testing and Diagnostics for unit-testing filters in isolation.
Next: Bundling and Client-Side Integration moves from the server pipeline to the client-side assets MVC 5 ships.