How to use IActionFilter, IAsyncActionFilter in ASP.NET Core MVC?
ASP.NET Core MVC allows us to run code before or after specific stages in the request processing pipeline, It has different Filters but in this article scope, we are focusing on only one Filter that is ActionFilters. We discus bout other Filter in a different article.
In ASP.NET Core MVC if we need to have common code for all the actions to Filter request or we can say if we need some block of code which will run on every request then we have ActionFilters and we can use them for cross-cutting concerns. Filters can avoid duplicate code across actions.
How Filter works,
After MVC selects the action to execute, a filter pipeline comes into action or we can say Filters run within MVC action invocation pipeline. A diagram shown below will show the flow of control goes from request to response(MVC action invocation pipeline).
A diagram shown below shows how filter types interact in the filter pipeline,
Now, How to use IActionFilter and IAsyncActionFilter,
Let's try to use IActionFilter, to use IActionFilter we need to have a class which will implement interface IActionFilter.
IActionFilter have two method that we have to implement i.e. OnActionExecuting and OnActionExecuted. To make our code simple I am just going to check for QueryString value and if it have some fix key in querystring, then I am just adding some text in ViewData. So as per our requirement we can do any thing conditionally that we need, we have context so it offer us all that we need too. So my class will looks like,
public class CustomActionFilter : IActionFilter
{
public void OnActionExecuting(
ActionExecutingContext context)
{
// do something before the action executes
if (context.HttpContext.Request.
QueryString.Value.Contains("myKey"))
{
if (context.Controller is Controller controller)
{
controller.ViewData["myKey"] =
"A data from Action filter!!!";
}
}
}
public void OnActionExecuted(
ActionExecutedContext context)
{
// do something after the action executes
}
}
Now we need add our ActionFilter in our Execution pipeline from Startup.cs class file,
services.AddTransient<CustomActionFilter>();
services.AddMvc(options =>
{
options.Filters.AddService<CustomActionFilter>();
}
);
Now, we are done, to check our ActionFilter we need to add a some code somewhere with key "myKey"
@ViewData["myKey"]
And when we have URL with QueryString myKey then it will add a text in our View
"A data from Action filter!!!".
So in this easy way, we can reduce our code which needs to be executed before and after every action. It seems easy and great if you have logic which needs this flow.
Now to use IAsyncActionFilter, again we need to implement a method OnActionExecutionAsync, so my class looks like,
public class CustomActionFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(
ActionExecutingContext context,
ActionExecutionDelegate next)
{
//Action before action
if (context.HttpContext.Request.
QueryString.Value.Contains("myKey"))
{
//we can cast as base class
//if we have all control derived from it
if (context.Controller is Controller controller)
{
//Do some work which need await
//as we are using async method
//we need to have at least one task which has await
//await Task.Delay(10);
controller.ViewData["myKey"] =
"A data from IAsyncActionFilter";
}
}
await next(); //need to pass the execution to next
//Do some action after ActionFilter
}
}
Note:- Implement either the synchronous or the async version of a filter interface, not both. The framework checks first to see if the filter implements the async interface, and if so, it calls that. If not, it calls the synchronous interface's method(s). If you were to implement both interfaces on one class, only the async method would be called.
Note:- This article is not for Razor Pages. ASP.NET Core 2.1 and later supports IPageFilter and IAsyncPageFilter for Razor Pages. So for this, we will have a different post.
If you are new in ASP.NET Core MVC then you may have a question what this AddTransient is doing ConfigureServices method. So to make it little easy, please read the section below to have some idea before you start using it.
What is the difference between services. AddTransient or AddScoped or AddSingleton methods in ASP.NET Core?
Basically all these services. Add options have a different life time, so while adding services we should choose them as per our requirement. It's easy for one who has a good understanding of Dependency Injection (DI).
ASP.NET Core supports the dependency injection software design pattern, which is nothing but a technique for achieving Inversion of Control (IoC) between classes and their dependencies. For more Learn more on asp.net docs
As per life time of these,
AddTransient
Transient Lifetime services are created each time they're requested. This lifetime works best for lightweight, stateless services.
AddScoped
Scoped lifetime services are created once per request.
Note:- When using a scoped service in a middleware, inject the service into the Invoke or InvokeAsync method. Don't inject via constructor injection because it forces the service to behave like a singleton.
AddSingleton
Singleton Creates a single instance throughout the application. It creates the instance for the first time and reuses the same object in the all calls.
Note:- It's dangerous to resolve a scoped service from a singleton. It may cause the service to have an incorrect state when processing subsequent requests.
So hoping it will provide you some help while using ActionFilters.