โ† Back to blog
24 November 2021 ยท 7 min read

Uploading files with ASP.NET Minimal APIs

With the .net 6 release, I was extremely excited to play with Minimal APIs.

One of the first things that I've done was to move an existing project to .net 6 and convert my Controllers into a Minimal API.

I've found the process easy, but I was surprised when the tests for an Upload endpoint failed.

My implementation after converting into Minimal API Endpoint was this. ๐Ÿ‘‡

app.MapPost("/upload",
    async Task<IResult>(IFormFile request) =>
    {
        if (request.Length == 0)
            return Results.BadRequest();

        await using var stream = request.OpenReadStream();

        var reader = new StreamReader(stream);
        var text = await reader.ReadToEndAsync();

        return Results.Ok(text);
    });

And the test this. ๐Ÿ‘‡

await using var application = new Application();
using var client = application.CreateClient();

using var formData = new MultipartFormDataContent();
await using var file = File.OpenRead("text.txt");
var streamContent = new StreamContent(file);
formData.Add(streamContent, "file", "text.txt");

var response = await client.PostAsync("/upload",
    formData);

response.StatusCode.Should().Be(HttpStatusCode.OK);
var data = await response.Content.ReadAsStringAsync();
data.Should().Be("\"Hello World!\"");

The expected 200 OK status code was now a 415 Unsupported Media Type ๐Ÿค”

That was strange. My first thought was that I was missing to define the content type accepted by that endpoint.

.Accepts<IFormFile>("multipart/form-data");

I realized I was stupid by thinking that since the code above is just about adding OpenAPI Metadata. ๐Ÿ˜…

Then, finally, I got it. Minimal APIs will try to bind attributes with the assumption that content is JSON.

So, how do I handle it?

I had to receive the HttpRequest request as an argument.

Then, I was able to read the Form and look for files.

app.MapPost("/upload",
    async Task<IResult>(HttpRequest request) =>
    {
        if (!request.HasFormContentType)
            return Results.BadRequest();

        var form = await request.ReadFormAsync();
        var formFile = form.Files["file"];

        if (formFile is null || formFile.Length == 0)
            return Results.BadRequest();

        await using var stream = formFile.OpenReadStream();

        var reader = new StreamReader(stream);
        var text = await reader.ReadToEndAsync();

        return Results.Ok(text);
    });

In the end, it requires a lit bit of extra effort, but it's not a big deal. Maybe in a future version, we may have a simple way of accomplishing it.

I hope that this was useful! To get more tips like this, follow me on Twitter (@gsferreira) and let's keep in touch!

Developer Insights

What I'm building, learning, and discovering each week.

By signing up, you'll get my free weekly newsletter plus occasional updates about my courses. You can unsubscribe anytime.