Uploading Large Files in ASP.NET Core

Enabling Kestrel Support for the Large Files

builder.WebHost.ConfigureKestrel(serverOptions =>
{
    serverOptions.Limits.MaxRequestBodySize = long.MaxValue;
});


public class FileUploadSummary
{
    public int TotalFilesUploaded { get; set; }
    public string TotalSizeUploaded { get; set; }
    public IList<string> FilePaths { get; set; } = new List<string>();
    public IList<string> NotUploadedFiles { get; set; } = new List<string>();
}


[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class MultipartFormDataAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        var request = context.HttpContext.Request;

        if (request.HasFormContentType 
            && request.ContentType.StartsWith("multipart/form-data", StringComparison.OrdinalIgnoreCase))
        {
            return;
        }

        context.Result = new StatusCodeResult(StatusCodes.Status415UnsupportedMediaType);
    }
}


Upload Large Files Using Streams

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
{
    public void OnResourceExecuting(ResourceExecutingContext context)
    {
        var factories = context.ValueProviderFactories;
        factories.RemoveType<FormValueProviderFactory>();
        factories.RemoveType<FormFileValueProviderFactory>();
        factories.RemoveType<JQueryFormValueProviderFactory>();
    }

    public void OnResourceExecuted(ResourceExecutedContext context)
    {
    }
}


[HttpPost("upload-stream-multipartreader")]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status415UnsupportedMediaType)]
[MultipartFormData]
[DisableFormValueModelBinding]
public async Task<IActionResult> Upload()
{
    var fileUploadSummary = await _fileService.UploadFileAsync(HttpContext.Request.Body, Request.ContentType);

    return CreatedAtAction(nameof(Upload), fileUploadSummary);
}


public async Task<FileUploadSummary> UploadFileAsync(Stream fileStream, string contentType)
{
    var fileCount = 0;
    long totalSizeInBytes = 0;

    var boundary = GetBoundary(MediaTypeHeaderValue.Parse(contentType));
    var multipartReader = new MultipartReader(boundary, fileStream);
    var section = await multipartReader.ReadNextSectionAsync();

    var filePaths = new List<string>();
    var notUploadedFiles = new List<string>();
    
    while (section != null)
    {
        var fileSection = section.AsFileSection();
        if (fileSection != null)
        {
            totalSizeInBytes += await SaveFileAsync(fileSection, filePaths, notUploadedFiles);
            fileCount++;
        }

        section = await multipartReader.ReadNextSectionAsync();
    }

    return new FileUploadSummary
    {
        TotalFilesUploaded = fileCount,
        TotalSizeUploaded = ConvertSizeToString(totalSizeInBytes),
        FilePaths = filePaths,
        NotUploadedFiles = notUploadedFiles
    };
}