Filters in ASP.NET Core
Tags: csharp, aspnetcore, restapi, softwaredevelopment
Published: 2023-01-26 14:04:06

---
title: Filters in ASP.NET Core
published: true
date: 2022-12-14 19:18:26 UTC
tags: csharpprogramming,aspnetcore,restapi,softwaredevelopment
canonical_url: https://rajdeep-das.medium.com/filters-in-asp-net-core-4010e656c28a
---

How To Create Custom Action Filter In ASP.NET 6 & Above

_Filters_ in ASP.NET Core allow code to run before or after specific stages in the request processing pipeline.

**Inbuild Filters**

- Authorization prevents access to resources a user isn’t authorized for.
- Response caching, short-circuiting the request pipeline to return a cached response.

**Custom Filters**

Custom filters can be created to handle cross-cutting concerns. Examples of cross-cutting concerns include error handling, caching, configuration, authorization, and logging. Filters avoid duplicating code. For example, an error-handling exception filter could consolidate error handling.

There are many filters in ASP.NET Core, but we will focus on Action Filters

[Action filters](https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-7.0#action-filters):

- Run immediately before and after an action method is called.
- Can change the arguments passed into action.
- Can change the result returned from the action.

**How Filters Works**

Filters run within the ASP.NET Core action invocation pipeline, sometimes referred to as the filter pipeline. The filter pipeline runs after ASP.NET Core selects the action to execute:

![](https://cdn-images-1.medium.com/max/336/1*S-NXC-_8zmtOeyhsk2FW7w.png)
_ASP.NET Filters_

We can implement Action Filters as synchronous and asynchronous through different interface definitions

We are going to build a SingleDeviceSessionCheck Filter for example

```
using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace MyService.UserApi.Filters
{
  public class SingleDeviceCheck : IActionFilter
  {
      private readonly IDeviceAccessRepository deviceAccessRepository;
      private readonly ILogger<SingleDeviceCheck> logger;
      private readonly IConfiguration configuration;
    
      /* Constructor for DI */ 
      public SingleDeviceCheck(
      /* This Respository Containts logic for checking session in DB */
          IDeviceAccessRepository deviceAccessRepository,
          ILogger<SingleDeviceCheck> logger,
          IConfiguration configuration)
      {
          this.deviceAccessRepository = deviceAccessRepository;
          this.logger = logger;
          this.configuration = configuration;
      }
  }
   // our code before action executes
   public void OnActionExecuting(ActionExecutingContext context){}
   // our code after action executes
   public void OnActionExecuted(ActionExecutedContext context){}
}

```

We need to implement our logic in these two methods, for my use case I required the onActionExecuting method.

```
public void OnActionExecuting(ActionExecutingContext context)
{
  // Checking single device access ON or OFF (Feature Flag For Dev/Prod Test
  if (this.configuration["SD_ON_OFF"].Equals("OFF")) { return; }

  // our code before action executes
  var deviceId = context.HttpContext.Request?.Headers["Device-Id"];
  if (string.IsNullOrEmpty(deviceId.ToString()))
  {
      context.Result = new BadRequestObjectResult("Device-Id is empty");
      return;
  }
  // if same device login then permission granted
  // Read USER INFO From JWT Claims
  var email = context.HttpContext.User.FindFirst("https://xyz.com/email")?.Value;
  var deviceAccessData = deviceAccessRepository.GetActiveDeviceByEmailAsync(email).Result;
  if (deviceAccessData == null)
  {
      context.Result = new UnauthorizedObjectResult(new { status = false, message = "Couldn't Find Your Device. Please Logout & Login Again." })
      {
          StatusCode = 403
      };
      return;
  }
  if (!(deviceAccessData.DeviceId == deviceId.ToString() && deviceAccessData?.IsActive == true))
  {
      logger.LogInformation("Device Failed To Pass {device} and {email}", deviceId, email);
      context.Result = new UnauthorizedObjectResult(new { status = false, message = "You have already active in another device.\n Access Denied." })
      {
          StatusCode = 403
      };
      return;
  }
  else
  {
      logger.LogInformation("Device Pass {device} and {email}", deviceId, email);
  }
}
```

Now we will register our Action Filter in Program. cs or Startup.cs

```
public void ConfigureServices(IServiceCollection services)
{
  services.AddDbContext<MovieContext>(options =>
   options.UseSqlServer(Configuration.GetConnectionString("sqlConString")));
  //Filters 
  services.AddScoped<SingleDeviceCheck>();
  services.AddControllers();
}
```

Now we will use This Filter In Our Controller

```
//Dev Test Only
[HttpGet("device")]
//Filter Code Run in Request Pipeline
[ServiceFilter(typeof(SingleDeviceCheck))]
public IActionResult CheckDevieID() {
    return Ok("Single Device ID Endpint Check");
}
```

**Summary**

1. Action Filter helps us to reuse code.
2. Run Some Common Logic In SPecific Controller or Methods In the Request Pipeline
3. A middleware can run for all requests while filters will only run for requests that reach the EndpointMiddleware
4. filters will only run on specified actions and controllers unless you register the filter globally in the startup. Since you have full access to the context you can also access the controller and action itself.

I always recommend using Action Filters because they give us reusability in our code and cleaner code in our actions as well.

[Software Developer | Rajdeep Software Engineering & Consulting Services](https://rajdeep-das.com)

[Rajdeep Das | LinkedIn](https://www.linkedin.com/in/rajdeep-das-india/)

Thank You, happy reading 📖 , 😊