0

I've build very simple middleware that encrypts response, it works fine. Because this middleware is added as first inside Configuration in Startup.cs is applies to all requests. I'd like to be able to encrypt only responses from certain controllers and/or methods, ideally by adding attribute to them.
I've searched a bit and I found that it is impossible to get controller and method inside middleware - Web Api 2 get controller and action name in OWIN middleware?

My question is how can I create such functionality? What are my other options?
I thought about using Filters, but they are used for authentications and don't allow to modify response, another way of doing this would be to create custom TypeFormatter, but this involves changing every method.

What I would like to achieve is ability to add attribute to controller or method that would result in encrypted response.

For now I'm using context.Request.Path inside Invoke in my middleware to exclude path I'd like to skip when encrypting, but as I wrote I'd like to use attribute base inclusion/exclusion.

Below is my current middleware code:

public static class ResponseEncrypterMiddlewareExtensions
{
    public static void UseResponseEncrypterMiddleware(this IAppBuilder app)
    {
        app.Use<ResponseEncrypterMiddleware>();
    }
}

public class ResponseEncrypterMiddleware : OwinMiddleware
{
    public ResponseEncrypterMiddleware(OwinMiddleware next) : base(next)
    {
    }

    public override async Task Invoke(IOwinContext context)
    {
        using (var stream = context.Response.Body)
        {
            using (var buffer = new MemoryStream())
            {
                context.Response.Body = buffer;
                await Next.Invoke(context);
                buffer.Seek(0, SeekOrigin.Begin);

                using (var reader = new StreamReader(buffer))
                {
                    string responseBody = await reader.ReadToEndAsync();

                    /*excludes*/
                    if (!string.IsNullOrWhiteSpace(responseBody)
                        && !context.Request.Path.Value.Contains("test1/")
                         && !context.Request.Path.Value.Contains("nothing_special/")
                        )
                    {
                        try
                        {
                            responseBody = /*encrypt here*/;
                        }
                        catch (Exception ex)
                        {
                            Debug.WriteLine(ex);
                            responseBody = string.Empty;
                            context.Response.StatusCode = 500;
                        }
                    }

                    var bytes = Encoding.UTF8.GetBytes(responseBody);
                    buffer.SetLength(0);
                    buffer.Write(bytes, 0, bytes.Length);
                    buffer.Seek(0, SeekOrigin.Begin);
                    context.Response.ContentLength = buffer.Length;
                    buffer.CopyTo(stream);
                }
            }
        }
    }
}

EDIT1: I'm able to modify response using custom ActionFilterAttribute, but this just a partial solution. I know I can include globally that attribute, bit I'd like a way to exclude some actions and controllers (by another attribute), so everything will be encrypt as default, but attribute on controller or action will allow clear (not encrypted) response.

EDIT2: Inside my Startup.cs I'm adding multiple middlewares. First one is responsible for encrypting response and second for tracing, below is my code inside Configuration method:

app.UseResponseEncrypterMiddleware();
app.UseRequestLogger();

Having them added in that order allows me to trace (log) request and response just before encrypting - middlewares start from top to bottom and end in opposite direction.
I've tried creating custom ActionFilter but this encrypts my content before it gets to tracing middleware.

Community
  • 1
  • 1
Misiu
  • 4,738
  • 21
  • 94
  • 198
  • 1
    You could just check for "marker attributes" in the ActionFilterAttribute you created, and not use your encoding if present – BlakeH Nov 08 '16 at 13:07
  • @BlakeH thanks for suggestion. I'll try that. It won't be a big problem to check for attribute, but I'm concern about other middlewares, I'm using tracing middleware. Idea was to store to db original response and then encode it. If I use ActionFilter my tracing wont work, but I must confirm that. – Misiu Nov 08 '16 at 13:34
  • @BlakeH I've did a quick test, if I modify (encode) response content inside my ActionFilter then my tracing middleware will get that new content, having middleware for encoding and having all or my middlewares in correct order (first encrypt, below tracing) allows me to trace request and response (not encoded) and return secure (encoded) response. I'll add that to my question – Misiu Nov 09 '16 at 07:55
  • why not create a custom middleware to handle your logic then? – BlakeH Nov 09 '16 at 14:54
  • or another option (if available in WebAPI 2.2) https://docs.asp.net/en/latest/mvc/controllers/filters.html#result-filters – BlakeH Nov 09 '16 at 14:56

0 Answers0