Search code examples
asp.net-corefile-uploadasp.net-core-webapi

How to make upload file size limit for ASP.NET Core controller method configurable


I have a FileContoller which accepts large file uploads. To allow for files larger than 30Mb, I use the RequestSizeLimit attribute, like so:

private const long _maxFileSize = 1000 * 1000 * 150; // 150 Mb

[HttpPost]
[RequestSizeLimit(_maxFileSize)]
public async Task<ActionResult<IList<UploadResult>>> PostFile([FromForm] IEnumerable<IFormFile> files)
{
    // ....
}

This works, but I would like to put the hard coded file limit in a configuration file - which does not work when using the attribute.

Quite a few answers on this site, eg.

Define different APIs to accept different size limits in ASP.Net Core 2.2

suggest setting the limit by changing the middleware pipeline in Program.cs, which opens up the possibility to read an injected configuration, like so:

app.UseWhen(context => context.Request.Path.StartsWithSegments("/api"), appBuilder =>{
        context.Features.Get<IHttpMaxRequestBodySizeFeature>()
            .MaxRequestBodySize = 1000 * 1000 * 150; // 150 Mb;
            //TODO: read hardcoded limit from configuration
  });

But this doesn't even compile:

CS0103 - The name 'context' does not exist in the current context

How can I change the above to work in current version of .NET Core? I'm currently working on .NET 6 switching to .NET 8.

Alternatively, is there any other method to set the RequestSizeLimit from configuration?

SOLUTION:

Thanks to Ahmad Pirouze, my final code looked like this:

var app = builder.Build();

const long _defaultMaxRequestBodySize = 1024 * 1024 * 75;
app.UseWhen(context => context.Request.Path.StartsWithSegments("/api/File"), appBuilder => {
    appBuilder.Use(async (context, next) =>
    {
        var maxRequestBodySizeFeature = context.Features.Get<IHttpMaxRequestBodySizeFeature>() ?? throw new ArgumentNullException("IHttpMaxRequestBodySizeFeature");
        maxRequestBodySizeFeature.MaxRequestBodySize = builder.Configuration.GetValue<long>("MaxRequestBodySize", _defaultMaxRequestBodySize);
        await next.Invoke();
    }); 
});

Solution

  • The reason why your code does not compile is that you are missing a parameter in the UseWhen method. The UseWhen method takes two parameters: a predicate function that returns a boolean value based on the HttpContext, and a configuration action that takes an IApplicationBuilder. You have only provided the first parameter, but not the second one. To fix this, you need to add a lambda expression that takes an IApplicationBuilder as a parameter and configures the middleware pipeline for the matching requests. For example:

    app.UseWhen(context => context.Request.Path.StartsWithSegments("/api"), appBuilder =>
    {
    // This is the second parameter that you are missing
    appBuilder.Use(async (context, next) =>
    {
    context.Features.Get<IHttpMaxRequestBodySizeFeature>()
    .MaxRequestBodySize = 1000 * 1000 * 150; // 150 Mb;
    //TODO: read hardcoded limit from configuration
    await next.Invoke();
    });
    });
    

    This way, you can set the MaxRequestBodySize feature for the requests that start with "/api" path segment. Note that you also need to invoke the next middleware in the pipeline by calling await next.Invoke().