In ASP.NET MVC, a user request is routed to the appropriate Controller and Action Method. We need situations where we want to execute some logic before or after an action method executes. ASP.NET MVC provides Filters for this.
Please check the link below for part one of this article.
In this article, we shall learn the order of execution of filters, different levels where we can apply these filters, and implementing Exception Filters.
Order of execution of Filters
Filters are executed in the below order -
- Authorization Filters
- Action Filters
- Result Filters
- Exception Filters
Exception Filters get executed depending on the exception that has occurred. If any exception occurs before the rendering of View, Exception Filters are called changing the order of execution of result filters.
Let us verify the order of execution with the below example.
I have created an action and decorated it with CustomAuthorize and CustomFilters attributes, as below.
- [CustomAuthorize]
- [CustomFilters]
- public ActionResult FiltersExample() {
- return View();
- }
Now, I will hit this action by URL without logging in to the application. As the action is decorated with customauthorize attribute, it should redirect me to the login page. Well, it is working in the same way.
This clearly proves that Authorize Filters are executed before the other filters. Now, let us log in to the application and verify the order of execution of other filters.
If we see in the above image, the Action Filters are executed before the Result Filter. Even though we have added code in OnResultExecuted to display a message, the message is not displayed because the OnResultExecuted is called after the View is rendered. Now, let us check when are the Exception Filters called. Let us throw some unhandled (null reference) exception within the action and verify the order of execution of filters.
When Exception occurs within the action, it calls the onActionExecuted method and then calls the OnExceptionMethod(). The OnResultExecuted and OnResultExecuting methods will not be called because the return View is not executed because of the exception.
So, the bottom line is that when an exception is occured within an action, OnException method gets executed after the OnActionExecuted and when exception is occured while rendering the View, the OnException is executed after the OnResultExecuted methods.
Logging Exceptions to DB
As we mentioned in part one, let us see how we can log an exception to DB. Exceptions can be logged within the OnExceptionMethod, as shown in the below code.
- public class CustomFilters: ActionFilterAttribute, IExceptionFilter {
- public override void OnActionExecuted(ActionExecutedContext filterContext) {
- filterContext.Controller.ViewBag.ActionExecuted = "On Action Executed";
- base.OnActionExecuted(filterContext);
- }
- public override void OnActionExecuting(ActionExecutingContext filterContext) {
- filterContext.Controller.ViewBag.ActionExecuting = "On Action Executing";
- base.OnActionExecuting(filterContext);
- }
- public override void OnResultExecuted(ResultExecutedContext filterContext) {
- filterContext.Controller.ViewBag.ResultExecuted = "On Result Executed";
- base.OnResultExecuted(filterContext);
- }
- public override void OnResultExecuting(ResultExecutingContext filterContext) {
- filterContext.Controller.ViewBag.ResultExecuting = "On Result Executing";
- base.OnResultExecuting(filterContext);
- }
- public void OnException(System.Web.Mvc.ExceptionContext filterContext) {
- filterContext.Controller.ViewBag.onException = "OnException";
- ExceptionLog exceptionLog = new ExceptionLog();
- exceptionLog.ClientRequest = HttpContext.Current.Request.Url.ToString();
- exceptionLog.ExceptionMessage = filterContext.Exception.Message;
- exceptionLog.ReferenceId = Guid.NewGuid().ToString();
- exceptionLog.UserId = filterContext.HttpContext.User.Identity.Name;
- Models.ExceptionContext exceptionContext = new Models.ExceptionContext();
- exceptionContext.ExceptionLogTable.Add(exceptionLog);
- exceptionContext.SaveChanges();
- }
- }
If we see the OnException method, we are creating the data and inserting it to the exceptionLogging table using Entity Framework.
If we see the above snapshot, we are able to log the data. We can even log the stack trace to know more details about the exception.
Different ways to use Filters
In our application, we can apply filters at three levels.
- Action Level
- Controller Level
- Global Level
Action Level
We decorate the filter attribute for each action that needs to have the custom functionality we have implemented.
Controller Level
Here, we decorate the filter attribute to the Controller. For example, if we decorate the customAuthorize attribute for Home Controller as shown below, each and every action within Controller gets executed only after AuthorizeCore gets executed and returns true. If we want to implement any action without customauthorization, we can decorate that action with AllowAnonymous attribute so the action execution doesnt depends on AuthorizeCore execution.
Global Level
Filters can be added at global level of an application in FilterConfig.cs of App_start Folder within the application. We will be adding the filters at global level if we want to apply custom logic for the actions in all the controllers. So, those filters we will register within the RegisterGlobalFilters method, as show below.
In most of the cases, we register the customAuthorize Attribute at the ActionLevel or Controller Level and we register the Exception Logging filters and Action Filters globally.
That's it for this article. Please comment if you have any questions.