Pea Kay See Es
Pea Kay See Es

Reputation: 454

Adding an Attribute for Response processing

Using C#, Net Core 3.1

I am wondering if someone can kindly help. I would like to add "middleware" but I think an Attribute is needed for my requirements as I want to do this selectively on specific API Actions only. How can I do some process (such as Signing a message and add it the response header) on a Response just before it is sent to the requesting client?

For example

    [HttpGet]
    [PostResponseProcessAttribute]
    public IActionResult GetFoo(int id) {
        return MyFoo();
    }

So for this GetFoo Action, I would like to do something like this:

public class PostResponseProcessAttribute : Attribute {
    public OnBeforeSendingResponse(){
      var response = Response.Content.ReadAsStringAsync;
     //do some stuff
      response.Headers.Add(results from stuff)
    }
}

Is it an Attribute that I need to implement and what is the function that I need override please? Also, a key bit is that Response is in the format and state that would be sent to to the client (i.e. passed other formatting middleware processing etc.) - this is important for Signing because any discrepancies would mean the client is verifying a response of a different version and therefore always fail.

Thanks

Upvotes: 1

Views: 956

Answers (1)

Sergey Nazarov
Sergey Nazarov

Reputation: 706

Finally, I wrote this:

public sealed class AddHeadersRequiredAttribute : Attribute
{
}

public class AddHeadersMiddleware
{
    private readonly RequestDelegate _next;

    public AddHeadersMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        await using var memory = new MemoryStream();
        var originalStream = context.Response.Body;
        context.Response.Body = memory;

        await _next(context);

        memory.Seek(0, SeekOrigin.Begin);
        var content = await new StreamReader(memory).ReadToEndAsync();
        memory.Seek(0, SeekOrigin.Begin);

        // Now you can manipulate with content
        var attribute = GetAddHeadersRequiredAttributeFromMatchedAction(context);
        if (attribute != null)
            context.Response.Headers.Add("X-Header-1", content);

        await memory.CopyToAsync(originalStream);
        context.Response.Body = originalStream;
    }

    private Attribute GetAddHeadersRequiredAttributeFromMatchedAction(HttpContext context)
    {
        var endpoint = context.GetEndpoint();
        var controllerActionDescriptor = endpoint?.Metadata.GetMetadata<ControllerActionDescriptor>();
        return controllerActionDescriptor?.MethodInfo.GetCustomAttribute<AddHeadersRequiredAttribute>();
    }
}

You can mark controller method with AddHeadersRequiredAttribute. Then use middleware at your Startup.Configure method like this

app.UseMiddleware<AddHeadersMiddleware>();

Upvotes: 1

Related Questions