asp.net-corefile-upload.net-8.0

.Net 8 file upload limits. Trying to upload an 89MB file to my API controller


For smaller files (i.e. 30MB or so) I have no issues. However, once I attempt to upload an 89MB file to my API Controler it throws (Request Entity Too Large) errors:

From my front end:

POST http://localhost:21971/api/import/MediaUpload?sessionID=***&pid=*** net::ERR_FAILED 413 (Request Entity Too Large)

My backend .Net 8 API project contains an import.controller.cs:

[HttpPost]
 [Route("MediaUpload")]
 public async Task<IActionResult> MediaUpload([FromQuery] string sessionId, [FromQuery] string pid, [FromForm] ImportMediaUploadModel formData)
{
  IFormCollection form;

  try
  {
      form = await Request.ReadFormAsync();
      form.Keys.ToList().ForEach(key =>
      {
          if (key.Equals("MediaInfo", StringComparison.InvariantCultureIgnoreCase))
          {
              formData.MediaInfo = JsonConvert.DeserializeObject<List<MediaInfo>>(form[key]);
          }
      });
  }
  
     for (var i = 0; i < formData.Files?.Count; i++)
   {
       UploadFile(formData.Files[i]);
   }   
   // ...
   return Ok();
 } 
  
   private async void UploadFile(IFormFile file)
  {
      var thisFileName = file.FileName.Trim('\"');
      string? localPath = config[key: "ImportImageFolderPath"];
      string fullPath = Path.Combine(localPath, thisFileName);
      FileInfo fileInfo = new(fullPath);

      using var stream = System.IO.File.Create(fullPath);
      await file.CopyToAsync(stream);
  }

I'm getting this same error uploading in the QA environment (and not just at localhost).

enter image description here

I am reading thru some docs such as this, https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-8.0, but I lack some expertise-level knowledge in latest .Net.

Thanks in advance for any advice on how to deal with file upload limitations in .Net 8.

In our html template, the two relevant parts are here:

<input
    multiple
    #fileInputElement
    type="file"
    style="display:none;"
    (change)="loadImagesFromInput($event)"
    accept=".jpg, .tiff, .png, .gif, .bmp, .pdf, .avi, .wmv, .mp4, .mpg, .mpeg, .mov, .3gp, .3g2, .m4v, .fda"
  />

  <button mat-flat-button color="primary" (click)="openFileBrowser()" title="Add Images" i18n-title="@@addImages">
    <mat-icon svgIcon="add"></mat-icon>
    <span i18n="@@addImages">Add Images</span>
  </button>
  <span class="spacer"></span>
  <button mat-flat-button color="primary" [disabled]="isSaveButtonDisabled()" (click)="save()" title="Save"
    i18n-title="@@save">
    <mat-icon svgIcon="save-to-disk"></mat-icon>
    <span i18n="Button|Generic label for save option@@save">Save</span>
  </button>
  
  

and our typescript:

save(): void {
  this.isLoading = true;
  const sessId = this.appSession.session.SessionID;
  const params = { pID: this.selectedPat.PID };

  // Populate MediaInfo object (some conversions to match the server model)
  const mediaInfo: MediaInfo[] = this.importImages.map((image) => {
      return {
          PID: this.selectedPat.PID,
          /// add'l fields removed for brevity..
      };
  });

  const submitFormData = () => {
      const formData = new FormData();
      formData.append('MediaInfo', JSON.stringify(mediaInfo));
      formData.append('CsiXmlFolder', this.csiXmlFolder);
      for (let i = 0; i < this.importImages.length; i++) {
          if (this.importImages[i].image.date !== '' && this.importImages[i].image.date !== undefined) {
              this.importImages[i].image.date = formatDate(this.importImages[i].image.date, 'shortDate', 'en-US');
          }
      }

      for (const image of this.importImages) {
          formData.append('files', this.dataURItoBlob(image.image.TnUrl), image.image.name);
      }         

      const captureEndpoint = this.selectedDeviceObj.Url;            

      this.importService.saveImportObjects(formData, params, captureEndpoint).subscribe({
          next: (data) => {
    // toast msg, etc.
          },

      });
  };
  
  saveImportObjects(formData: FormData, params, endpointUri: string): Observable<HttpClient> {
    // NOTE: multipart and boundary header added by browser automatically.

    let url = '';
    let pid = '';       

    endpointUri = "http://localhost:21971/api/import/MediaUpload?"; // ** LOCAL DEV TESTING **
    
    if (endpointUri !== null) {
        url = `${endpointUri}sessID=${this.appSession.getSess()}&pId=${pid}`;
    }

    return this.http.post<any>(url, formData);
  }


Solution

  • You could use [RequestSizeLimit(500*1024*1024)] attribute to handle requests up to 500 MB.

    [HttpPost]
    [Route("MediaUpload")]
    [RequestSizeLimit(500*1024*1024)]
    public async Task<IActionResult> MediaUpload([FromQuery] string sessionId, [FromQuery] string pid, [FromForm] ImportMediaUploadModel formData)
    {
    

    Or you can configure in Program.cs like below:

    builder.Services.Configure<FormOptions>(x => {
        //x.ValueCountLimit = int.MaxValue;
        x.MultipartBodyLengthLimit = long.MaxValue;
    });
    

    The third way is to add the web.config file and use [DisableRequestSizeLimit] attribute, refer to this answer.