How to use route handler filters in minimal APIs in ASP.NET Core 7


ASP.NET Core 6 introduced a simplified hosting model that allows us to build lightweight APIs with minimal dependencies. Minimal APIs in ASP.NET Core 6 don’t use controllers, and they lack support for a number of useful ASP.NET features. One of these missing features is filters.

However, with ASP.NET Core 7 (now available in a release candidate), we can take advantage of the newly introduced IRouteHandlerFilter interface to incoporate filters in our minimal APIs. These filters can be used to modify the request or response objects as desired or to short-circuit the request processing pipeline.

This article discusses how we can work with route handler filters when building minimal API apps in ASP.NET Core 7. To use the code examples provided in this article, you should have Visual Studio 2022 Preview installed in your system. If you don’t already have a copy, you can download Visual Studio 2022 here.

Create an ASP.NET Core 7 minimal Web API project in Visual Studio 2022

First off, let’s create an ASP.NET Core 7 project in Visual Studio 2022 Preview. Follow these steps:

  1. Launch the Visual Studio 2022 Preview IDE.
  2. Click on “Create new project.”
  3. In the “Create new project” window, select “ASP.NET Core Web API” from the list of templates displayed.
  4. Click Next.
  5. In the “Configure your new project” window, specify the name and location for the new project.
  6. Optionally check the “Place solution and project in the same directory” check box, depending on your preferences.
  7. Click Next.
  8. In the “Additional Information” window shown next, uncheck the check box that says “Use controllers…” since we’ll be using minimal APIs in this example. Leave the “Authentication Type” as “None” (default).
  9. Ensure that the check boxes “Enable Docker,” “Configure for HTTPS,” and “Enable Open API Support” are unchecked as we won’t be using any of those features here.
  10. Click Create.

We’ll use this ASP.NET Core 7 Web API project to create a minimal API and implement route handler filters in the sections below.

What are filters? Why should we use them?

Filters allow you to run code at certain stages of the request processing pipeline. In other words, a filter is a piece of code that is executed before or after an action method is executed. For example, you could use a filter to log every time someone accesses a web page or to validate the request parameters sent to an endpoint.

Filters offer a number of benefits:

  • Filters make your application more secure by allowing you to reject requests that don’t meet specific criteria (including authorization). 
  • Filters can help you clean up your code by creating reusable functions and classes.
  • Filters allow you to focus on the business logic of your application instead of spending time writing code for cross-cutting concerns such as logging, exception handling, and security.

Why should we use filters in minimal APIs?

You can take advantage of filters in minimal APIs to write code that can do the following:

  • Execute code before and after an endpoint handler.
  • Inspect and edit the parameters when an endpoint handler executes.
  • Inspect the response behavior of an endpoint handler.
  • Log request and response metadata.
  • Ensure that a request targets a supported API version.
  • Validate a request and request parameters.

The IRouteHandlerFilter interface in ASP.NET Core 7

You can take advantage of the IRouteHandlerFilter interface to modify the request or response or to short-circuit the request processing pipeline. You can also add cross-cutting concerns such as authentication, authorization, and logging. At a quick glance, here’s what you can achieve using this interface:

  • Write custom logic for handling incoming requests.
  • Intercept a request and modify the request object as required.
  • Make changes to the response before it is sent out.
  • Short-circuit a request, meaning that any remaining action filters will not execute.

The following code snippet illustrates the IRoutehandler interface:

namespace Microsoft.AspNetCore.Http;
public interface IRouteHandlerFilter
{
    ValueTask<object?> InvokeAsync(
        RouteHandlerInvocationContext context,
        RouteHandlerFilterDelegate next);
}

Create a custom route handler filter in ASP.NET Core 7

You can create a custom filter class via the IRouteHandlerFilter interface as shown in the code listing given below.

public class DemoFilter : IRouteHandlerFilter
{
    private ILogger _logger;
    public DemoFilter(ILoggerFactory loggerFactory)
    {
       _logger = logger;
    }
    public async ValueTask<object?> InvokeAsync(RouteHandlerInvocationContext context, RouteHandlerFilterDelegate next)
   {
        var text = context.GetParameters[0];
       if (text.Equals("Error"))
       {
          _logger.LogInformation(“Error.”);
          return Results.Problem("This is a minimal example of an error.");
       }
       _logger.LogInformation(“Success.”);
       return await next(context);
   }
}

Next, you should register the filter as a service in the Program.cs file using the following code snippet.

builder.Services.AddSingleton<DemoFilter>();

It is possible to register a filter by using the RouteHandlerFilterDelegate or the AddFilter extension method. In this example, we’ll use the AddFilter extension method. Write the following code snippet in the Program.cs file.

app.MapGet("/v1/MyDemoEndpoint{text}", “Hello”)
   .AddFilter<DemoFilter>();

Create a short circuit in ASP.NET Core 7

You might often need to short-circuit the filter pipeline. For example, let’s say you’ve built a microservices-based application and one of the services is not responding. In this case, all requests to this service would fail. Instead, you could short-circuit the request processing pipeline and fall back on some other service that is healthy.

Here is how you can implement a custom short-circuit filter for your minimal API:

public class MyShortCircuitFilter: IRouteHandlerFilter
{
    public ValueTask<object?> InvokeAsync(
        RouteHandlerInvocationContext context,
        RouteHandlerFilterDelegate next)
    {
        return new ValueTask<object?>(Results.Json
        (new { Message = "Terminated" }));
    }
}

Filters allow you to run custom code before or after a certain point in the request processing pipeline. They also help you avoid the duplication of code across actions. The IRouteHandlerFilter Interface is a special filter that can be applied to an entire route or a single handler. It allows you to access the request object and then modify the request or response as required.

Copyright © 2022 IDG Communications, Inc.



Source link

Leave a Reply