Request body size is part of the endpoint contract.
A small JSON command and a document-upload endpoint should not inherit the same limit by accident. When Kestrel owns the request-body limit, start with a conservative Kestrel-wide limit, then override it only where the use case requires more:
builder.WebHost.ConfigureKestrel(options =>
{
options.Limits.MaxRequestBodySize = 1L * 1024 * 1024;
});
For a buffered MVC upload action, separate the maximum file size from the complete request-body limit:
private const long MaxFileSize = 25L * 1024 * 1024;
// Example headroom. Derive this from the accepted multipart shape.
private const long MaxRequestSize = 26L * 1024 * 1024;
[HttpPost("documents")]
[RequestSizeLimit(MaxRequestSize)]
public async Task<IActionResult> UploadAsync(
IFormFile file,
[FromServices] IDocumentUploadHandler uploadHandler,
CancellationToken cancellationToken)
{
if (file.Length == 0)
{
return BadRequest("The file is empty.");
}
if (file.Length > MaxFileSize)
{
return StatusCode(
StatusCodes.Status413PayloadTooLarge,
"The file exceeds 25 MiB.");
}
await uploadHandler.HandleAsync(file, cancellationToken);
return NoContent();
}
IDocumentUploadHandler represents the application-specific validation and storage work. The relevant boundary here is that the complete request and the individual file have separate limits.
RequestSizeLimit applies to the complete request body, not only file.Length. Multipart boundaries, headers, other fields, and additional files count too. Keep the file-size check separate and choose request headroom from the multipart shape you actually accept. The values above are MiB, not decimal MB.
This is not only a Kestrel setting. IIS, a reverse proxy, an API gateway, or a cloud ingress can reject the request before ASP.NET Core sees it. For total-body limits, the smallest enforced limit across the complete request path wins. When an app runs out of process behind the ASP.NET Core Module, IIS sets the limit and Kestrel’s request-body limit is disabled.
Multipart parsing has separate limits for section bodies, headers, form values, and value counts. Configure FormOptions globally or use RequestFormLimitsAttribute when an action needs different parser limits. IFormFile uses buffered model binding, so large or highly concurrent uploads also require deliberate memory and temporary-storage planning.
Choose the number from the actual operation:
- expected payload size
- serialization or multipart overhead
- memory and temporary-storage behavior
- concurrent request volume
- downstream service limits
Return a predictable client error when the platform allows it, and document the accepted size. An upstream server or Kestrel may reject an oversized request before the endpoint can produce its own response, so the application cannot always customize the error. Do not disable limits globally to fix one upload endpoint.
A larger request-body limit does not make uploaded content trustworthy. Validate authorization, file type, parsed content, and processing cost separately.
Keep the default small enough for normal requests and make exceptional endpoints visibly exceptional.