The support for ActionFilters in ASP.NET MVC and Web Api gives you a nice execution pipeline to run code before or after specific stages in the request processing pipeline:
They are a great fit for a lot of use cases, like validation, caching, … and allow you to have an AOP like approach in your controllers. Their are 2 things I find annoying about the usage of ActionFilters:
- They introduce an extra layer of abstraction with some hidden magic. It is not always clear what’s going on the request pipeline and what happened in a specific filter.
- It is not easy to share state between your action filter and your controller (which can be useful sometimes).
Recently I discovered a great trick that solves the problems above.
Did you know that a controller is also a filter – as it implements both IActionFilter and IAsyncActionFilter interfaces, you can override the related methods and turn your controller into an action filter?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Route("api/products")] | |
[ApiController] | |
public class ProductController : Controller | |
{ | |
private readonly IProductRepository _repository; | |
private Product _foundProduct; | |
public ProductController(IProductRepository repository) | |
{ | |
_repository =repository; | |
} | |
[HttpGet("{id}")] | |
public async Task<ActionResult<Product>> Get(int id) | |
{ | |
//We'll reuse the instance fetched through the filter | |
return Ok(_foundProduct); | |
} | |
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) | |
{ | |
if (context.ActionArguments.ContainsKey("id")) | |
{ | |
var id = (int)context.ActionArguments["id"]; | |
_foundProduct=await _repository.Get(id); | |
if (_foundProduct == null) | |
{ | |
context.Result = new NotFoundResult(); | |
return; | |
} | |
} | |
await next(); | |
} | |
} |