"no body provided" response when POSTing to a minimal endpoint

Viewed 815

I'm experimenting with converting some simple controller methods to using endpoint routing on the latest RC of aspnet core 6. The controller works fine, and it looks like this:

[HttpPost]
public async Task<IActionResult> CreateUser(NewUserRequest newUser)
{
    /* do stuff with newUser */
    /* return CreatedAtRoute(...); */
}

I've tried converting to using IEndpointRouteBuilder, like so:

endpoints.MapPost("/api/user/test",
    (NewUserRequest request) =>
    {
        /* same thing as controller method */
    });

// prints error to the log:
// Implicit body inferred for parameter "request" but no body was provided. Did you mean to use a Service instead?

I'm using the exact same test request (through Postman, usually), so I know it's not the client's problem. What's more, if I just take an HttpRequest parameter, I can read the body into a json blob.

endpoints.MapPost("api/user/test2",
    async (HttpRequest request) =>
    {
        using (var sr = new StreamReader(request.BodyReader.AsStream()))
        {
            var body = await sr.ReadToEndAsync();

            /* body is valid json here */
        }
    });

I'm really at a loss here, especially since it works in some cases, but not when I'm binding a type to one of the minimal endpoints.

1 Answers

The syntax you used is available in Minimal APIs first introduced in ASP.NET Core 6 Preview 4. At that time it wasn't possible to bind to specific objects yet. It's not related to Endpoint routing which was added in ASP.NET Core 3.1.

If you create a new "empty" web app with dotnet new web you get:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World!");
app.Run();

This is using endpoint routing through the new WebApplication class. To add the POST endpoint you can use :

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World!");
app.MapPost("/api/user/test",(NewUserRequest request) =>
    {
        Console.WriteLine(request.Name);
        return request;
        /* same thing as controller method */
    });

app.Run();

class NewUserRequest
{
    public string Name{get;set;}
}

Additional classes and methods must be defined at the end of the file.

Testing this with curl :

curl -X POST https://localhost:7153/api/user/test -d '{ "Name":"A"}' -H 'Content-Type: application/json' -v

Logs A in the service's console and returns

{"name":"A"}%

to the client.

The reason you get this error :

Implicit body inferred for parameter "request" but no body was provided. Did you mean to use a Service instead?

Is that in ASP.NET Core 6 Preview 6 it became possible to inject services without using the [FromServices] attribute. In the following code, the DbContext is injected:

app.MapGet("/todos", async (TodoDbContext db) =>
{
    return await db.Todos.ToListAsync();
});
Related