Enforce mandatory request headers on .Net Core WebAPI?

Viewed 225

Is there a standard way to enforce mandatory request headers in .Net Core Web APIs? I want all caller apps to pass some tracking headers so that I have some traceability for call volume.

I am aware that for Swagger, it can be done via OperationFilter and custom header attribute. But for direct calls, I can think of only using custom middleware to enforce this.

Is that the right way to do it or is there other standard way to enforce it or standard libraries available for this purpose?

1 Answers

Here are a few ways to do this. There's not really a "standard" way to do it, but these ways are very common.

Outside of your project

You can enforce required headers by customizing your reverse proxy. For example, Apigee allows you to customize its rules, including enforcing headers for certain URLs. This is great because it relieves pressure and implementation on your project's endpoints. The proxy should be configured to return a 400 BAD REQUEST in those cases.

Within your project, Middleware

Within the project's code, using ASP.NET middleware is one way to take care of this. You can create a middleware that checks for the existence of the headers, and then reject the request if they are missing.

Here is a simple example where the existence of MyHeader allows the next middleware to be called, but the lack of the header avoids invoking the next middleware.

public class HeaderChecker
{
    private readonly RequestDelegate _next;

    public HeaderChecker(RequestDelegate next) => _next = next;

    public async Task Invoke(HttpContext context)
    {
        if (!context.Request.Headers.ContainsKey("MyHeader"))
            context.Response.StatusCode = 400;
        else
            await _next.Invoke(context);
    }
}

with the registration that you would place in Startup.cs

builder.UseMiddleware<HeaderChecker>();

You could avoid the middleware, but then you end up bloating your controller's methods, which is usually frowned on. Either way this SO Q&A backs up the idea of returning the 400 from your code.

Within your project, using [FromHeader]

You can use the [FromHeader] attribute, which is probably the simplest approach that can work, though this does mean you'd have to bind the header to your model. If your intent is simply to ensure a header is present, and not related to your model in any way, then that might not be desirable.

As always, in development, it depends.

Related