Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HttpContext.Response.Body.Position = 0 - "Specified method is not supported" error

I've got some logging middleware I've setup that grabs and logs information utilizing HttpContext.

I need to set the position of the HttpResponse.Body to 0 in order to read the whole stream, however, no matter what I try, it throws "Specified method is not supported" and fails.

This is very weird to me because position is built right into HttpResponse.Body and I've used it before successfully.

I also tried to use HttpResponse.Body.Seek with the same result.

At this point I'm stuck, any help would be appreciated.

UPDATE: I was able to get the response.body position to change once I moved it into a new memory stream, however, now it returns an empty body back.

public async Task Invoke(HttpContext context)
        {
            //Retrieve request & response
            var request = context.Request;
            var response = context.Response;

            if (request.Path != "/")
            {
                var reqBody = request.Body;
                var resBody = response.Body;
                string path = request.Path;
                string method = request.Method;
                string queryString = HttpUtility.UrlDecode(request.QueryString.ToString());
                int statusCode = context.Response.StatusCode;

                var buffer = new byte[Convert.ToInt32(request.ContentLength)];
                await request.Body.ReadAsync(buffer, 0, buffer.Length);
                var reqBodyText = Encoding.UTF8.GetString(buffer);
                request.Body = reqBody;

                var responseBodyStream = new MemoryStream();
                context.Response.Body = responseBodyStream;

                await _next(context);

                responseBodyStream.Seek(0, SeekOrigin.Begin);
                var resBodyText = new StreamReader(responseBodyStream).ReadToEnd();
                responseBodyStream.Seek(0, SeekOrigin.Begin);
                await responseBodyStream.CopyToAsync(context.Response.Body);

                ...
            }
        }
like image 694
expenguin Avatar asked Jul 03 '18 19:07

expenguin


2 Answers

I was able to solve this:

Firstly, I set the response to its own memory stream and call await _next(context) after the stream was set:

var responseBodyStream = new MemoryStream();
context.Response.Body = responseBodyStream;

await _next(context);

Then once I did this, I noticed I was getting an empty body back, this was due to trying to set an empty body back as the response context:

await responseBodyStream.CopyToAsync(context.Response.Body);

I removed this line and everything started working correctly.

like image 144
expenguin Avatar answered Sep 19 '22 12:09

expenguin


As per the comment that solved this GitHub issue, you need to enable buffering.

To do so, add the following snippet to your Startup.cs Configure method:

app.Use(async (context, next) =>
{
    context.Request.EnableBuffering();
    await next();
});
like image 34
jhhwilliams Avatar answered Sep 21 '22 12:09

jhhwilliams