4

I did encounter a wierd problem with kestrel. I am not able to upload the multiple files which exceed the kestrel's MaxRequestBodySize.

The expected behaviour is to throw the BadHttpRequestException when I am trying to reader this.Request.Form.Files.GetFiles(). I do expect to recieve request to controller action only once.

What is happening is that the upload action is hit a few time and browser with message "conection lost". I did not find a patter on how mamy times the action is called.

Controller action:

[HttpPost("upload")]
public IActionResult Upload()
{
    try
    {
        var files = this.Request.Form.Files.GetFiles("files");
        files.Select(async file => await this.SaveFile(file))
        return this.RedirectToAction(nameof(VueController.FilesList),"Vue");
    }
    catch (BadHttpRequestException exp)
    {
        return new string[]
        {
            exp.Message
        };
    }
}

view:

<form method="post"
          enctype="multipart/form-data"
          action="/api/v1/files/upload"
          novalidate="novalidate">
      <input type="file"
             name="files"
             multiple="multiple"
             required="required"
             accept=""
             capture="capture" />
    </form>

asp.net core logs:

info: Microsoft.AspNetCore.Server.Kestrel[17] Connection id "0HLDB9K94VV9M" bad request data: "Request body too large." Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: Request body too large. at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Frame.ThrowRequestRejected(RequestRejectionReason reason) at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.MessageBody.ForContentLength.OnReadStart() at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.MessageBody.TryInit() at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.MessageBody.d__24.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Frame`1.d__2.MoveNext() info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] Request finished in 7618.6319ms 413

Edited I am aware that I can disabled the limit but it is not possible in this case.

Yehor Androsov
  • 4,885
  • 2
  • 23
  • 40
Assassin
  • 1,296
  • 2
  • 14
  • 17
  • Check this announcement https://github.com/aspnet/Announcements/issues/267 ^^ – Tseng Apr 26 '18 at 08:39
  • You can also override it per request as noted in the linked announcement, via `[RequestSizeLimit(100000000)]` – Tseng Apr 26 '18 at 08:40

2 Answers2

11

You must configure two things:

In your Program.cs

public static IWebHost BuildWebhost(string[] args) => 
   WebHost.CreateDefaultBuilder(args)
      .UseStartup<Startup>()
      .UseKestrel(options => {
           options.Limits.MaxRequestBodySize = null; // or a given limit
      })
     .Build();

In your Startup.cs in the ConfigureService method

services.Configure<FormOptions>(options => options.MultipartBodyLengthLimit = long.MaxValue); // or other given limit

Also change your controller endpoint to use [FromForm]

public IActionResult Upload([FromForm] IEnumerable<IFormFile> files)... // name must be same as name attribute of your multipart form

Now ASP.NET Core will do the work and inject the files from the form as sequence.

Edit:

I created an example that can be cloned from github:

git clone https://github.com/alsami/example-fileupload-aspnet-core.git
cd example-fileupload-aspnet-core
dotnet restore
dotnet run --project src/file-upload-api/file-upload-api.csproj

Then navigate to http://localhost:5000/index.html and try uploading huge files.

alsami
  • 8,996
  • 3
  • 25
  • 36
  • Did you also configure the form options? If so, what's the error now? Please update the OP. – alsami Apr 26 '18 at 08:40
  • I did not configure the options in services, let me try this. – Assassin Apr 26 '18 at 08:41
  • I updated the answer, please have a look and try changing your controller endpoint as suggested. – alsami Apr 26 '18 at 08:51
  • I have added configuratiob for FromOption but is still does not work. The behaviour is exactly the same. – Assassin Apr 26 '18 at 08:54
  • Updated the answer with an executable sample. – alsami Apr 26 '18 at 09:25
  • Must be related to your code. Please use the example project I provided and compare it to your code and do the adjustment as I said. – alsami Apr 26 '18 at 10:35
  • The solution you have proposed is working, the key was to set the value of Kestrel limit to null and not to have it empty. – Assassin Apr 30 '18 at 15:00
  • Yeah, is what I wrote in the first place anyway. – alsami May 01 '18 at 07:16
  • There is another issue. When I set tu kester limit to null and the MultipartBodyLengthLimit is higher than 30Mb( which is default Kestrel body limit) there is no limit to a file size at all. – Assassin May 02 '18 at 14:49
2

As per this announcement the max limit can be override globally for all actions or specifically for a single one using the [RequestSizeLimit(100000000)] (or [DisableRequestSizeLimit] to disable the limit) on a given action.

Tseng
  • 61,549
  • 15
  • 193
  • 205