Transcendent
Transcendent

Reputation: 5755

Multipart body length limit exceeded exception

Although having set the MaxRequestLength and maxAllowedContentLength to the maximum possible values in the web.config section, ASP.Net Core does not allow me to upload files larger than 134,217,728 Bytes. The exact error coming from the web server is:

An unhandled exception occurred while processing the request.

InvalidDataException: Multipart body length limit 134217728 exceeded.

Is there any way to work this around? (ASP.Net Core)

Upvotes: 77

Views: 54632

Answers (5)

Hukar Pcengine
Hukar Pcengine

Reputation: 86

Solution for Minimal API

To configure just one endpoint (which is preferable), here's the code you'll need.

 app.MapPost("/upload", (IFormFile file) =>
{
    // ...
})
.WithFormOptions(multipartBodyLengthLimit: 2_000_000_000L);

Upvotes: 0

Chris Halcrow
Chris Halcrow

Reputation: 31950

If you use int.MaxValue (2,147,483,647) for the value of MultipartBodyLengthLimit as suggested in other answers, you'll be allowing file uploads of approx. 2Gb, which could quickly fill up disk space on a server. I recommend instead setting a constant to limit file uploads to a more sensible value e.g. in Startup.cs

using MyNamespace.Constants;
public void ConfigureServices(IServiceCollection services)
{
        ... other stuff
        services.Configure<FormOptions>(options => {
            options.MultipartBodyLengthLimit = Files.MaxFileUploadSizeKiloBytes;
        })
 }

And in a separate constants class:

namespace MyNamespace.Constants
{
    public static class Files
    {
        public const int MaxFileUploadSizeKiloBytes = 250000000; // max length for body of any file uploaded
    }
}

Upvotes: 3

cmorgan091
cmorgan091

Reputation: 571

Alternatively use the attribute, so the equivalent for an action as resolved by Transcendant would be:

[RequestFormLimits(ValueLengthLimit = int.MaxValue, MultipartBodyLengthLimit = int.MaxValue)]

Upvotes: 34

Nour Berro
Nour Berro

Reputation: 560

in case some one still face this problem i've created a middle-ware which intercept the request and create another body

    public class FileStreamUploadMiddleware
    {
        private readonly RequestDelegate _next;

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

        public async Task Invoke(HttpContext context)
        {
            if (context.Request.ContentType != null)
            {
                if (context.Request.Headers.Any(x => x.Key == "Content-Disposition"))
                {
                    var v = ContentDispositionHeaderValue.Parse(
                        new StringSegment(context.Request.Headers.First(x => x.Key == "Content-Disposition").Value));
                    if (HasFileContentDisposition(v))
                    {
                        using (var memoryStream = new MemoryStream())
                        {
                            context.Request.Body.CopyTo(memoryStream);
                            var length = memoryStream.Length;
                            var formCollection = context.Request.Form =
                                new FormCollection(new Dictionary<string, StringValues>(),
                                    new FormFileCollection()
                                        {new FormFile(memoryStream, 0, length, v.Name.Value, v.FileName.Value)});
                        }
                    }
                }
            }

            await _next.Invoke(context);
        }

        private static bool HasFileContentDisposition(ContentDispositionHeaderValue contentDisposition)
        {
            // this part of code from  https://github.com/aspnet/Mvc/issues/7019#issuecomment-341626892
            return contentDisposition != null
                   && contentDisposition.DispositionType.Equals("form-data")
                   && (!string.IsNullOrEmpty(contentDisposition.FileName.Value)
                       || !string.IsNullOrEmpty(contentDisposition.FileNameStar.Value));
        }
    }

and in the controller we can fetch the files form the request

        [HttpPost("/api/file")]
        public IActionResult GetFile([FromServices] IHttpContextAccessor contextAccessor,
            [FromServices] IHostingEnvironment environment)
        {
            //save the file
            var files = Request.Form.Files;
            foreach (var file in files)
            {
                var memoryStream = new MemoryStream();
                file.CopyTo(memoryStream);

                var fileStream = File.Create(
                    $"{environment.WebRootPath}/images/background/{file.FileName}", (int) file.Length,
                    FileOptions.None);
                fileStream.Write(memoryStream.ToArray(), 0, (int) file.Length);

                fileStream.Flush();
                fileStream.Dispose();

                memoryStream.Flush();
                memoryStream.Dispose();
            }

            return Ok();
        }

you can improve the code for your needs eg: add form parameters in the body of the request and deserialize it.

its a workaround i guess but it gets the work done.

Upvotes: 1

Transcendent
Transcendent

Reputation: 5755

I found the solution for this problem after reading some posts in GitHub. Conclusion is that they have to be set in the Startup class. For example:

public void ConfigureServices(IServiceCollection services)
{
        services.AddMvc();
        services.Configure<FormOptions>(x => {
            x.ValueLengthLimit = int.MaxValue;
            x.MultipartBodyLengthLimit = int.MaxValue; // In case of multipart
        })
 }

This will solve the problem. However they also indicated that there is a [RequestFormSizeLimit] attribute, but I have been unable to reference it yet.

Upvotes: 163

Related Questions