Multipart body length limit exceeded exception

asp.net Coreasp.net Core-Mvc

asp.net Core Problem Overview


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)

asp.net Core Solutions


Solution 1 - asp.net Core

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.

Solution 2 - asp.net Core

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

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

Solution 3 - asp.net Core

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
    }
}

Solution 4 - asp.net Core

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTranscendentView Question on Stackoverflow
Solution 1 - asp.net CoreTranscendentView Answer on Stackoverflow
Solution 2 - asp.net Corecmorgan091View Answer on Stackoverflow
Solution 3 - asp.net CoreChris HalcrowView Answer on Stackoverflow
Solution 4 - asp.net CoreNour BerroView Answer on Stackoverflow