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!
Top comments (2)
Very helpful !
Nice.