I'm using an ASP.NET Core Azure Web App to provide a RESTful API to a client, and the client doesn't handle chunking correctly.
Is it possible to completely turn off Transfer-Encoding: chunked
, either at the controller level or in file web.config?
I'm returning a JsonResult somewhat like this:
[HttpPost]
[Produces("application/json")]
public IActionResult Post([FromBody] AuthRequest RequestData)
{
AuthResult AuthResultData = new AuthResult();
return Json(AuthResultData);
}
ASP.NET Core defaults to chunked if you do not set the content-length. This allows responses to be sent immediately without buffering and helps minimize latency, memory overhead, etc.. Why is chunking a problem for you? Sorry, something went wrong. We have a relay service that forwards requests and responses to and from a server.
All HTTP/1.1 responses must set Content-Length or Transfer-Encoding: chunked. ASP.NET Core defaults to chunked if you do not set the content-length. This allows responses to be sent immediately without buffering and helps minimize latency, memory overhead, etc..
Specifically, implement the WriteXml and ReadXml methods to chunk the data. On the server machine, the Web method must turn off ASP.NET buffering and return a type that implements IXmlSerializable. The type that implements IXmlSerializable chunks the data in the WriteXml method.
When copying headers in a proxy/relay you should filter out the Transfer-Encoding: chunked header, most servers will re-add it if needed. Is there a way to easily turn chunking off from the server sending the responses? No. Chunking can only be disabled by setting the Content-Length header, which often requires buffering to calculate.
How to get rid of chunking in .NET Core 2.2:
The trick is to read the response body into your own MemoryStream, so you can get the length. Once you do that, you can set the content-length header, and IIS won't chunk it. I assume this would work for Azure too, but I haven't tested it.
Here's the middleware:
public class DeChunkerMiddleware
{
private readonly RequestDelegate _next;
public DeChunkerMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var originalBodyStream = context.Response.Body;
using (var responseBody = new MemoryStream())
{
context.Response.Body = responseBody;
long length = 0;
context.Response.OnStarting(() =>
{
context.Response.Headers.ContentLength = length;
return Task.CompletedTask;
});
await _next(context);
// If you want to read the body, uncomment these lines.
//context.Response.Body.Seek(0, SeekOrigin.Begin);
//var body = await new StreamReader(context.Response.Body).ReadToEndAsync();
length = context.Response.Body.Length;
context.Response.Body.Seek(0, SeekOrigin.Begin);
await responseBody.CopyToAsync(originalBodyStream);
}
}
}
Then add this in Startup:
app.UseMiddleware<DeChunkerMiddleware>();
It needs to be before app.UseMvC()
.
In ASP.NET Core, this seems to work across hosts:
response.Headers["Content-Encoding"] = "identity";
response.Headers["Transfer-Encoding"] = "identity";
Indicates the identity function (i.e., no compression, nor modification). This token, except if explicitly specified, is always deemed acceptable.
This also works when you explicitly disable response buffering:
var bufferingFeature = httpContext.Features.Get<IHttpBufferingFeature>();
bufferingFeature?.DisableResponseBuffering();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With