Creating custom filters in ASP.NET MVC is a powerful technique that can help you to add functionality like logging, authentication, and other cross-cutting concerns to your application in a clean and reusable manner. In this guide, we will walk through the process of creating custom filters in ASP.NET MVC step by step.
Understanding Filters in ASP.NET MVC
Before diving into creating custom filters, it's essential to understand the role and the four types of filters available within ASP.NET MVC:
- Authorization Filters: These run first and are generally used to determine if a request can be handled by the target controller and action method.
- Action Filters: These run before and after the action method but after the authorization filters have successfully executed and right after the authorization filters.
- Result Filters: These run before and after the action result is executed. They are ideal for modifying the response before it arrives at the client.
- Exception Filters: As the name implies, these are used to manage and handle exceptions thrown by the action methods and other filters.
All of these filters inherit from the common base System.Web.Mvc.FilterAttribute
and can be applied to individual controller actions or globally for the MVC application.
Creating a Custom Filter
Let's walk through the process of creating a custom filter in ASP.NET MVC. We'll create a simple logging filter that logs the action and controller names every time an action is hit in our application.
Step 1: Setting Up Your Project
Ensure you have an ASP.NET MVC project set up. If not, you can create a new ASP.NET MVC project by following the steps below:
- Open Visual Studio.
- Create a new project by selecting
File
->New Project
. - Choose
ASP.NET Web Application (.NET Framework)
and name itCustomFiltersDemo
. - Select
MVC
template and clickCreate
.
Step 2: Creating a Logging Filter
Now, let's create a custom filter to log the controller and action method.
Add a new class to your project:
- Right-click on your project in the Solution Explorer.
- Select
Add
->Class
and name itLoggingFilterAttribute.cs
.
Inherit from ActionFilterAttribute:
- Modify the class to inherit from the
ActionFilterAttribute
class:
using System.Web.Mvc; public class LoggingFilterAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { // Get the controller and action name string controller = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName; string action = filterContext.ActionDescriptor.ActionName; // Do something with this information // For example, log it to console or a file System.Diagnostics.Debug.WriteLine($"ActionExecuting: {controller} -> {action}"); base.OnActionExecuting(filterContext); } public override void OnActionExecuted(ActionExecutedContext filterContext) { string controller = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName; string action = filterContext.ActionDescriptor.ActionName; // Do something after the action method is executed System.Diagnostics.Debug.WriteLine($"ActionExecuted: {controller} -> {action}"); base.OnActionExecuted(filterContext); } }
In this example, the
LoggingFilterAttribute
class inherits fromActionFilterAttribute
. It overrides theOnActionExecuting
andOnActionExecuted
methods. TheOnActionExecuting
method is called before the action method is executed, andOnActionExecuted
is called after the action method is executed. In these methods, we retrieve the controller and action method names and write them to the debugging output.- Modify the class to inherit from the
Applying the Filter:
- You can apply the custom
LoggingFilterAttribute
to individual action methods or entire controllers. To apply it globally, you can register it in theFilterConfig
file.
For example, to apply it globally:
using System.Web.Mvc; using CustomFiltersDemo.Filters; // Make sure to include your namespace public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); filters.Add(new LoggingFilterAttribute()); // Add the logging filter } }
- You can apply the custom
Creating Controller Actions to Test:
- Let’s create a sample controller and some actions to test our custom logging filter.
using System.Web.Mvc; namespace CustomFiltersDemo.Controllers { public class HomeController : Controller { public ActionResult Index() { return View(); } public ActionResult About() { ViewBag.Message = "Your application description page."; return View(); } public ActionResult Contact() { ViewBag.Message = "Your contact page."; return View(); } } }
Running the Application:
- Run the application by pressing
F5
. Navigate to different URLs likeHome/Index
,Home/About
, andHome/Contact
. - Open the
Output
window in Visual Studio (View
->Output
) and selectDebug
from the dropdown. You should see outputs like:
ActionExecuting: Home -> Index ActionExecuted: Home -> Index ActionExecuting: Home -> About ActionExecuted: Home -> About ActionExecuting: Home -> Contact ActionExecuted: Home -> Contact
- Run the application by pressing
This confirms that your custom logging filter is working as expected and logging the controller and action names each time an action is executed.
Example of an Exception Filter
Now, let's look at an example of a custom exception filter. This filter will catch unhandled exceptions and log them before the standard error page is displayed.
Create a Custom Exception Filter Class:
- Right-click on your project in the Solution Explorer.
- Select
Add
->Class
and name itExceptionLoggingFilterAttribute.cs
. - Modify the class to inherit from
ExceptionFilterAttribute
and log exceptions:
using System.Web.Mvc; public class ExceptionLoggingFilterAttribute : ExceptionFilterAttribute { public override void OnException(ExceptionContext filterContext) { // Log the exception here (e.g., to a file or database) System.Diagnostics.Debug.WriteLine($"Exception: {filterContext.Exception.Message}"); // Optionally, display a custom error view filterContext.ExceptionHandled = true; filterContext.Result = new ViewResult { ViewName = "Error" }; base.OnException(filterContext); } }
Register the Exception Filter Globally:
- Open
FilterConfig.cs
and register theExceptionLoggingFilterAttribute
:
using System.Web.Mvc; using CustomFiltersDemo.Filters; public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); filters.Add(new LoggingFilterAttribute()); filters.Add(new ExceptionLoggingFilterAttribute()); // Add the exception filter } }
- Open
Create an Error View:
- Create a new view for displaying errors:
- Right-click on the
Views
folder ->Add
->View
. Name the viewError.cshtml
.
@{ ViewBag.Title = "Error"; } <h2>An error occurred while processing your request.</h2>
Triggering an Exception:
- Modify one of your controller actions to throw an exception to test the exception filter:
public class HomeController : Controller { public ActionResult Index() { throw new InvalidOperationException("This is a test exception."); } public ActionResult About() { ViewBag.Message = "Your application description page."; return View(); } public ActionResult Contact() { ViewBag.Message = "Your contact page."; return View(); } }
Test the Exception Filter:
- Run the application and navigate to the
Home/Index
action. Instead of seeing a yellow screen of death, you should see the custom error view.
- Run the application and navigate to the
Conclusion
Creating custom filters in ASP.NET MVC is a fundamental skill that allows you to add behavior to your application in a clean and reusable way. These filters can help with logging, authentication, and exception handling, making your codebase more modular and maintainable. By following the steps outlined in this guide, you can create and apply custom filters to your ASP.NET MVC applications.
Additional Tips
- Dependency Injection: For more complex scenarios, consider using dependency injection in your filters. This can help you manage database contexts, logging frameworks, and other dependencies more effectively.
- Thread Safety: Be mindful of thread safety when writing custom filters, especially if they interact with shared resources.
- Testing: Write unit tests for your filters to ensure they behave as expected in different scenarios.
Mastering the art of creating custom filters will make you a more efficient and effective developer in ASP.NET MVC. Happy coding!