74

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)

Transcendent
  • 5,598
  • 4
  • 24
  • 47

4 Answers4

152

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.

Transcendent
  • 5,598
  • 4
  • 24
  • 47
  • I don't think setting limits in web.config has any effect in an ASP.NET Core app. – Pawel Nov 01 '16 at 17:17
  • 13
    Thank God I found you I was lost without you – daniherculano Nov 30 '16 at 11:10
  • 2
    Anyone else having problems getting this to work in the latest versions? – Jason Rowe Mar 13 '17 at 23:14
  • 4
    @JasonRowe Yes, I am. Looks like it's not working with the latest version. – Razort4x Apr 06 '17 at 14:08
  • 1
    @pawel, incorrect, I had to change the web.config in my azure app as well – Matthew James Davis Jul 06 '17 at 15:19
  • @MatthewJamesDavis: That is because it has something to do with Azure configurations! web.config is usually meant to be used by IIS, but ASP.Net Core has it's own middleware. So I think in your case, some configs also had to be done on Azure and that's why you needed to change web.config. – Transcendent Jul 07 '17 at 02:28
  • 2
    The OP did not mention Azure or IIS. IIS/Azure do read some settings from the web.config file. Kestrel does not. – Pawel Jul 07 '17 at 04:09
  • This limit will only work for ~2GB files. Is there a different approach recommended for larger uploads? – defect833 Nov 02 '17 at 06:49
  • @defect833: yes, upload your large file in small parts. – Transcendent Nov 02 '17 at 18:07
  • 2
    I set the second variable to the max value of long instead. My controller action has a 10gb limit for uploading the results of the client drag and dropping multiple files. [RequestSizeLimit(10_000_000_000)] //10gb in cheap gigs – Tyeth Mar 13 '18 at 20:38
  • @Tyeth Like the "cheap" gigs. Personally, I call them "peasant" gigs – Alexander May 30 '18 at 18:14
  • 2
    Then what's ```[DisableRequestSizeLimit]``` attribute for?! – Babak Jul 23 '18 at 08:41
  • @Babak: It is for when you target .Net Core 2.0 or higher! – Transcendent Jul 23 '18 at 14:33
  • 1
    The equivalent with the attribute usage : `[HttpPost("upload"), DisableRequestSizeLimit, RequestFormLimits(MultipartBodyLengthLimit = Int32.MaxValue, ValueLengthLimit = Int32.MaxValue)]` – Xav987 Oct 23 '18 at 13:54
  • 4
    Still getting the error ("Multipart body length limit 1000000000 exceeded"). Tried setting `MultipartBodyLengthLimit` to `long.MaxValue`, but it gets ignored for some reason. – user3664254 Apr 05 '19 at 14:03
  • what is the unit of `MultipartBodyLengthLimit`? is it in byte – LP13 Jul 08 '20 at 20:26
  • @user3664254 use `Int32.MaxValue` – user16930239 Oct 04 '21 at 22:14
29

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

[RequestFormLimits(ValueLengthLimit = int.MaxValue, MultipartBodyLengthLimit = int.MaxValue)]
cmorgan091
  • 511
  • 6
  • 7
2

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
    }
}
Chris Halcrow
  • 28,994
  • 18
  • 176
  • 206
1

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.

Ali Alp
  • 691
  • 7
  • 10
Nour Berro
  • 550
  • 5
  • 14
  • For whom it is worth something, for IO you need async IO... Recommended. You can use await file.CopyToAsync(fileStream) (no need for MemoryStream) – Egbert Nierop Sep 10 '22 at 07:41