Reputation: 2222
I have a .NET Core 2.2 API with a POST for a large file upload via stream.
I'm getting the exception "Multipart body length limit 16384 exceeded."
The exception appears at the line...
section = await reader.ReadNextSectionAsync();
...at the FileStreamHelper.cs (see below).
I use postman to try the upload. My file has 10 MB. I get this exception when I choose Body/binary. When I choose Body/form-data instead I get the exception "Unexpected end of Stream, the content may have already been read by another component.". But I did not read the file by a different component or before. I guess binary should be right. Right?
At my Startup.cs I define
services.Configure<FormOptions>(options =>
{
options.MemoryBufferThreshold = Int32.MaxValue;
options.ValueCountLimit = 10; //default 1024
options.ValueLengthLimit = int.MaxValue; //not recommended value
options.MultipartBodyLengthLimit = long.MaxValue; //not recommended value
});
I'm using also at the Startup.cs
app.UseWhen(context => context.Request.Path.StartsWithSegments("/File"),
appBuilder =>
{
appBuilder.Run(async context =>
{
context.Features.Get<IHttpMaxRequestBodySizeFeature>().MaxRequestBodySize = (long)( 2 * System.Math.Pow( 1024, 3 )); // = 2GB
await Task.CompletedTask;
});
});
At Program.cs I use
.UseKestrel(options =>
{
options.Limits.MaxRequestBodySize = (long)(2 * System.Math.Pow(1024, 3)); // = 2 GB
})
At my Controller I use the Attribute [DisableRequestSizeLimit].
What could be the reason for this exception?
How to solve this problem?
All code: Controller
[Route("api/v1/dataPicker/fileUploadStream")]
public class FileStreamUploadController : ControllerBase
{
[HttpPost]
[DisableRequestSizeLimit]
[DisableFormValueModelBinding]
public async Task<IActionResult> Upload()
{
var streamer = new FileStreamingHelper();
var paths = "c:\\temp\\";
var tempName = Guid.NewGuid().ToString("N");
using
(
var stream = System.IO.File.Create($"{paths}tempName")
)
await streamer.StreamFile(Request, stream);
string from = $"{paths}tempName";
string to = $"{paths}{streamer.FileNames.FirstOrDefault() ?? tempName}";
System.IO.File.Move(from, to);
return Ok($"Uploaded File {paths}{streamer.FileNames.FirstOrDefault() ?? tempName}");
}
}
FileStreamHelper
public async Task<FormValueProvider> StreamFile(HttpRequest request, Stream targetStream)
{
if (!MultipartRequestHelper.IsMultipartContentType(request.ContentType))
{
throw new Exception($"Expected a multipart request, but got {request.ContentType}");
}
var formAccumulator = new KeyValueAccumulator();
var boundary = MultipartRequestHelper.GetBoundary(
MediaTypeHeaderValue.Parse(request.ContentType),
_defaultFormOptions.MultipartBoundaryLengthLimit);
var reader = new MultipartReader(boundary, request.Body);
MultipartSection section;
try
{
section = await reader.ReadNextSectionAsync();
}
catch (Exception ex)
{
throw;
}
while (section != null) ...}
public static string GetBoundary(MediaTypeHeaderValue contentType, int lengthLimit)
{
var boundary = HeaderUtilities.RemoveQuotes(contentType.Boundary);
if (StringSegment.IsNullOrEmpty(boundary))
{
throw new InvalidDataException("Missing content-type boundary.");
}
if (boundary.Length > lengthLimit)
{
throw new InvalidDataException(
$"Multipart boundary length limit {lengthLimit} exceeded.");
}
return boundary.Value;
}
You need more code to see? Please tell me!
Upvotes: 2
Views: 5393
Reputation: 2222
I had to configure postman differently..
1) Body / form-data
2) under "KEY" enter the field with your mouse, than drop down and choose "File"
3) below Value click the new Button and choose a file
4) write into the field "KEY" the word "File"
That was not easy to find out. ;-) All the Header data wasn't important. Now it works.
Upvotes: 1
Reputation: 11932
Please try to retrieve the boundary this way by parsing the content type first:
var contentType = MediaTypeHeaderValue.Parse(context.Request.ContentType);
var boundary = HeaderUtilities.RemoveQuotes(contentType .Boundary);
var reader = new MultipartReader(boundary.Value, request.Body);
//Rest of the code
Also, please attach a screenshot of your postman request, especially the headers
Upvotes: 3