简体   繁体   中英

Setting Content-Length header in ASP.NET 5 response

TL; DR I have an ASP.NET 5 (MVC 6) application and just trying to set a HTTP Content-Length header in order to avoid chunked response.

To my surprise, it happens that this is a quite tricky task to accomplish in ASP.NET 5. Everything is running on Kestrel which from ASP.NET 5 Beta7 supports writing chunked responses automatically when no content length is specified for the response .

There is a similar question here , but the difference is that the OP just wants to count a response size, while I need to ensure that the Content-Length header is sent within a response. Tried with many things so far, and the only thing that works is writing a custom Middleware:

public class WebApiMiddleware {
    RequestDelegate _next;

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

    public async Task Invoke(HttpContext context) {
         using (var buffer = new MemoryStream()) {
            var response = context.Response;

            var bodyStream = response.Body;
            response.Body = buffer;

            await _next(context);

            response.Headers.Add("Content-Length", new[] { buffer.Length.ToString()});
            buffer.Position = 0;
            await buffer.CopyToAsync(bodyStream);
        }
     }
}

However, this is highly inefficient since we are using additional memory while processing every request. Using a custom stream that just wraps around the context.Response.Body stream and additionally counts bytes doesn't work since the Microsoft team states thatonce the amount of data they're willing to buffer has been written, it goes out on the wire and they don't store it any more , so I can, at best, add Content-Length to the last chunk which is not the wished behavior - I want to avoid chunking completely.

Any help is highly appreciated!

ps I am aware that chunking is a regular feature of HTTP/1.1, but in my scenario it degrades performance so I want to avoid it without forcing the clients to send HTTP/1.0 requests.

You need to send header before sending response so you need to store whole response before sending it to determine length.

As you said context.Response.Body stream doesn't store to much before sending so overhead is not that big.

There is middleware that does similar thing: https://github.com/aspnet/BasicMiddleware/blob/master/src/Microsoft.AspNetCore.Buffering/ResponseBufferingMiddleware.cs it is very similar to what you wrote but supports additional features like IHttpBufferingFeature to allows other middleware control buffering.

Checking for bufferStream.CanSeek is there to make sure nobody already wrapped response stream into buffering stream and avoid double buffering.

For your second question: this place is middlware.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM