ServiceFilter vs TypeFilter in ASP.NET Core Web API

ServiceFilter vs TypeFilter in ASP.NET Core Web API

In this article, I will discuss ServiceFilter vs TypeFilter in ASP.NET Core Web API Applications with Examples. Please read our previous article discussing Exception Filters in ASP.NET Core Web API Applications. In ASP.NET Core Web API, filters are a powerful mechanism that allows us to execute code before or after certain stages in the request processing pipeline. Sometimes, we want to apply custom filters globally, at the controller level, or at the action level. Two common ways to apply custom filters that require dependency injection (DI) are ServiceFilter and TypeFilter. Let’s explore what they are, when to use each, and with practical examples.

What is ServiceFilter in ASP.NET Core Web API?

ServiceFilter is an attribute that enables us to apply a filter (such as action, resource, authorization, or exception) that is registered as a service in the dependency injection (DI) container. When we apply [ServiceFilter(typeof(MyFilter))] on a controller or action, ASP.NET Core will resolve the filter instance from the DI container.

When we use ServiceFilter, we are telling ASP.NET Core to look up the filter as a registered service. This means the filter must be registered as a service in the Program.cs class. In short, ServiceFilter works with filters already registered in DI.

When Should We Use ServiceFilter in ASP.NET Core Web API?

We need to use ServiceFilter when:

  • We have a filter class that is already registered as a service in the DI container.
  • We want to share the same instance or the DI container to create the filter instance.
  • We need full DI support inside our filter and want to manage the filter’s lifecycle using the service container.
  • We want to keep filter registrations centralized for better management.

Example scenarios:

  • Logging filters that require injected logging services.
  • Authorization or validation filters that depend on external services.
Create a Custom Action Filter for ServiceFilter

Let’s create a filter that requires DI, making ServiceFilter the appropriate choice. The following custom action filter example logs the action execution time and requires a logger via DI. First, create a new ASP.NET Core Web API project named FiltersDemo. Then, create a new folder named Filters at the project root directory.

Next, create a class file named ExecutionTimeLoggingFilter.cs within the Filters folder and copy and paste the following code. The following filter depends on ILogger<ExecutionTimeLoggingFilter>, which is registered in DI. To inject this logger into the filter, the filter itself must be resolved by the DI container. Hence, the filter must be registered as a service. The ServiceFilter uses the DI container to create the filter, allowing constructor injection.

using Microsoft.AspNetCore.Mvc.Filters;
using System.Diagnostics;

namespace FiltersDemo.Filters
{
    public class ExecutionTimeLoggingFilter : IActionFilter
    {
        private readonly ILogger<ExecutionTimeLoggingFilter> _logger;
        private Stopwatch? _stopwatch;

        // Constructor injection of logger
        public ExecutionTimeLoggingFilter(ILogger<ExecutionTimeLoggingFilter> logger)
        {
            _logger = logger;
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            _stopwatch = Stopwatch.StartNew();
            _logger.LogInformation("Action execution started.");
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            _stopwatch?.Stop();
            _logger.LogInformation($"Action executed in {_stopwatch?.ElapsedMilliseconds} ms.");
        }
    }
}
Registering the filter in the Program.cs

Please modify the Program class as follows:

using FiltersDemo.Filters;
namespace FiltersDemo
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // Add services to the container.
            builder.Services.AddControllers()
            .AddJsonOptions(options =>
            {
                // Disable camelCase in JSON output, preserve property names as defined in C# classes
                options.JsonSerializerOptions.PropertyNamingPolicy = null;
            });

            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();

            //Register the filter
            builder.Services.AddScoped<ExecutionTimeLoggingFilter>();

            var app = builder.Build();

            // Configure the HTTP request pipeline.
            if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }

            app.UseHttpsRedirection();

            app.UseAuthorization();

            app.MapControllers();

            app.Run();
        }
    }
}
What is TypeFilter in ASP.NET Core Web API?

The TypeFilter attribute is another way to attach filters to controllers/actions. Unlike ServiceFilter, it creates a filter instance using the service provider, but it does not require you to register the filter in the DI container. TypeFilter can also pass constructor arguments to the filter, allowing you to set properties or configuration at the point of use.

When Should We Use TypeFilter in ASP.NET Core Web API?

We need to use TypeFilter when:

  • We want to apply a filter but don’t want to explicitly register it in DI.
  • We want to pass parameters to the filter’s constructor dynamically at the attribute usage site.
  • We want a simpler way to apply filters without modifying DI registration.

Example scenarios:

  • Filters that require some configuration or parameters per usage.
  • Situations where you want on-the-fly parameterization of filters.
Create a Custom Action Filter for TypeFilter:

Let’s create a filter where we need to pass a runtime parameter, making TypeFilter the right fit. So, create a class file named CustomValidationFilter.cs within the Filters folder and copy and paste the following code. The filter needs a custom header parameter, which is only known at attribute usage. This parameter cannot be injected via DI, so it must be passed dynamically. The TypeFilter enables passing this parameter while still resolving other dependencies via DI. You don’t need to register this filter in DI explicitly.

using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;

namespace FiltersDemo.Filters
{
    public class CustomValidationFilter : IActionFilter
    {
        private readonly string _requiredHeader;
        private readonly ILogger<CustomValidationFilter> _logger;

        public CustomValidationFilter(string requiredHeader, ILogger<CustomValidationFilter> logger)
        {
            _requiredHeader = requiredHeader;
            _logger = logger;
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            if (!context.HttpContext.Request.Headers.ContainsKey(_requiredHeader))
            {
                _logger.LogWarning("Missing required header: {Header}", _requiredHeader);
                context.Result = new BadRequestObjectResult($"Missing required header: {_requiredHeader}");
            }
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            // No-op
        }
    }
}
Applying ServiceFilter and TypeFilter Attribute

Create an API Controller showing the use of Custom Action Filters using both ServiceFilter and TypeFilter attributes. So, please create an API Empty Controller named DemoController within the Controllers folder and then copy and paste the following code:

using FiltersDemo.Filters;
using Microsoft.AspNetCore.Mvc;

namespace FiltersDemo.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class DemoController : ControllerBase
    {
        // Uses ServiceFilter: filter is registered in DI and uses injected dependencies
        [HttpGet("with-servicefilter")]
        [ServiceFilter(typeof(ExecutionTimeLoggingFilter))]
        public IActionResult WithServiceFilter()
        {
            return Ok("ServiceFilter executed!");
        }

        // Uses TypeFilter: filter takes a runtime argument plus injected dependencies
        [HttpGet("with-typefilter")]
        [TypeFilter(typeof(CustomValidationFilter), Arguments = new object[] { "X-Api-Key" })]
        public IActionResult WithTypeFilter()
        {
            return Ok("TypeFilter executed!");
        }
    }
}
Differences Between ServiceFilter and TypeFilter in ASP.NET Core Web API

The following are the key differences between ServiceFilter and TypeFilter in ASP.NET Core Web API.

DI Registration:
  • ServiceFilter requires the filter class to be registered in the DI container.
  • TypeFilter does not require prior registration; it creates the filter instance on the fly.
Constructor Arguments:
  • ServiceFilter does not support passing constructor arguments dynamically.
  • TypeFilter supports passing constructor arguments via the Arguments property.
Performance:
  • ServiceFilter uses DI to resolve the instance directly, potentially better for scoped/singleton lifetimes.
  • TypeFilter uses ActivatorUtilities.CreateInstance internally, which may have a minor performance cost but adds flexibility.
Use Case:
  • Use ServiceFilter when the filter is a service you want to manage via the DI container, especially when you want to share instances or manage lifetimes explicitly.
  • Use TypeFilter when you want to apply a filter without prior DI registration or when you want to pass specific constructor parameters dynamically at the filter usage site.

Both ServiceFilter and TypeFilter enable dependency injection for filters in ASP.NET Core Web API, but they have different use cases. ServiceFilter is best when your filter is already a service and has no per-use parameters. TypeFilter is ideal for filters needing per-use customization or when you want to avoid registering filters globally.

In the next article, I will discuss the ASP.NET Core Request Processing Life Cycle. In this article, I explain ServiceFilter vs TypeFilter in an ASP.NET Core Web API Application with Examples. I hope you enjoy this ServiceFilter vs TypeFilter in ASP.NET Core Web API article.

Leave a Reply

Your email address will not be published. Required fields are marked *