Search code examples
c#asp.net-coreswaggerasp.net-core-webapiiformfile

ASP.NET Core 8.0: Swagger Error When Using IFormFile in Upload Endpoint


I am developing an ASP.NET Core 8.0 Web API for my bachelor’s project. The API includes an upload endpoint for processing Excel files containing location data. However, when implementing the endpoint, Swagger fails to load and throws the following error:

Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorException: Error reading parameter(s) for action WebApi.Controllers.LocationsController.UploadFile (WebApi) as [FromForm] attribute used with IFormFile. Please refer to https://github.com/domaindrivendev/Swashbuckle.AspNetCore#handle-forms-and-file-uploads for more information

In Postman, when I send a file via multipart/form-data, I get the error:

{
    "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "errors": { "file": ["The file field is required."] }
}

Controller Code:

[HttpPost("upload")]
[RequestSizeLimit(104857600)] // Set request size limit to 100 MB

        public async Task<IActionResult> UploadFile([FromForm] IFormFile file)
        {
            var validationMessage = UploadHandler.ValidateFile(file);
            if (!string.IsNullOrEmpty(validationMessage))
                return BadRequest(validationMessage);

            try
            {
                using var stream = new MemoryStream();
                await file.CopyToAsync(stream);

                using var package = new ExcelPackage(stream);
                var worksheet = package.Workbook.Worksheets.FirstOrDefault();
                if (worksheet == null)
                    return BadRequest("Invalid Excel file.");

                var locations = new List<Location>();
                for (int row = 2; row <= worksheet.Dimension.End.Row; row++) // Start from row 2 to skip headers
                {
                    var location = new Location
                    {
                        WhId = worksheet.Cells[row, 1].Text,              // Column A
                        LocationId = worksheet.Cells[row, 2].Text,        // Column B
                        ShortLocationId = worksheet.Cells[row, 4].Text,   // Column D
                        NmHallId = worksheet.Cells[row, 43].Text,         // Column AP
                        NmAisle = worksheet.Cells[row, 46].Text           // Column AS
                    };
                    locations.Add(location);

                    // Save data in batches of 1000 rows
                    if (locations.Count >= 1000)
                    {
                        _context.Locations.AddRange(locations);
                        await _context.SaveChangesAsync();
                        locations.Clear();
                    }
                }

                // Save remaining rows
                if (locations.Any())
                {
                    _context.Locations.AddRange(locations);
                    await _context.SaveChangesAsync();
                }

                return Ok(new { Message = "File uploaded successfully.", RowsProcessed = worksheet.Dimension.End.Row - 1 });
            }
            catch (Exception ex)
            {
                return BadRequest($"Error processing file: {ex.Message}");
            }
        }

Model Class:

The Location model is a complex object with multiple properties. However, I believe the issue is related to the [FromForm] usage with IFormFile.

What I've Tried:

  1. Validating the endpoint logic:
  • Reduced the logic to minimal file presence validation.
  • Confirmed that file is passed as [FromForm] IFormFile.
  • Still results in "file field is required" in Postman.
  1. Debugging Swagger:
  • Commenting out the upload controller allows Swagger to load.
  • The [FromForm] parameter with IFormFile seems to cause Swagger crashes.
  1. Checked Postman:
  • Verified Content-Type is automatically set to multipart/form-data.
  • No manually added Content-Type header.

Question:

How can I possibly resolve this issue? I have tried using ChatGPT, but it hasn't been very helpful in troubleshooting with me.


Solution

  • For your scenario which only requires uploading the file, you should not apply the [FromForm] attribute.

    public async Task<IActionResult> UploadFile(IFormFile file)
    

    [FromForm] attribute is implemented only when you need to post the form field.

    Hence, your controller action and its request body (form fields) should be as below:

    public async Task<IActionResult> UploadFile([FromForm] UploadFileModel model)
    
    public class UploadFileModel 
    {
        // Model properties
    
        public IFormFile File { get; set; }
    }