16

I created an asp.net core empty project and whenever I am trying to run my application it gives me the error shown below. I cannot even hit the end point as soon I hit play it gives the error.

System.InvalidOperationException HResult=0x80131509 Message=Body was inferred but the method does not allow inferred body parameters. Below is the list of parameters that we found:

Parameter           | Source                        
---------------------------------------------------------------------------------
ur                  | Service (Attribute)
userLogin           | Body (Inferred)


Did you mean to register the "Body (Inferred)" parameter(s) as a Service or apply the [FromService] or [FromBody] attribute?

No idea why I am getting this error. I then tried adding [FromService] and it says the same error as well. I read this article for the same issue but it says do not add [Bind] which I was not in the first place and to instead use [FromService] but I still get the same error. Is there something wrong I am doing?

Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<ApplicationDbContext>(x =>
    x.UseSqlServer(builder.Configuration.GetConnectionString("Default")));

builder.Services.AddScoped<IUserRepository, UserRepository>();

builder.Services.AddEndpointsApiExplorer();

builder.Services.AddSwaggerGen();

var app = builder.Build();

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

app.MapGet("/userLogin", (IUserRepository ur, UserLogin userLogin) =>
{
    return ur.Get(userLogin);
});

if (app.Environment.IsDevelopment())
{
    app.UseSwagger(x => x.SerializeAsV2 = true);
    app.UseSwaggerUI();
}

app.Run();

UserLogin:

 [Keyless]
public class UserLogin
{
    public string Username { get; set; }
    public string Password { get; set; }
}

UserRepository:

public User Get(UserLogin userLogin)
        {   // get the username and password make sure what was entered matches in the DB then return the user
            var username =_dbContext.Users.Find(userLogin.Username, StringComparison.OrdinalIgnoreCase);

            return username;
        }
MarkCo
  • 810
  • 2
  • 12
  • 29

4 Answers4

13

The exception message is telling you the problem:

Body was inferred but the method does not allow inferred body parameters

The binder has inferred the UserLogin parameter as a parameter from the body, but inferred body parameters are not allowed.

The simplest way to get this working is to add [FromBody] attribute to the UserLogin parameter, however, in that case you should really change the method to POST since GET requests don't have a body.

app.MapPost("/userLogin", (IUserRepository ur, [FromBody]UserLogin userLogin) => {...}

Unfortunately, it's not possible to bind complex objects from query string values using [FromQuery] attribute in minimal APIs so your best option IMO is to use [FromBody] and MapPost.

If you need to use MapGet there is a work-around by adding a static BindAsync method to your UserLogin class - more details can be found in this blog post. Another alternative is to pass HttpContext to the action and take the values from the context - see this similar answer for binding [FromForm] - you'd use ctx.Request.Query["username"] to get the username from the HttpContext.

haldo
  • 14,512
  • 5
  • 46
  • 52
  • 2
    Thank you, I realized after reading your explanation I should have to change it to a POST method instead of a GET. – MarkCo Mar 25 '22 at 19:31
13

In my case I forgot to add the below to my program.cs file above my app.Run();

builder.Services.AddScoped<IUserRepository, UserRepository>();
Zach Gonzalez
  • 792
  • 7
  • 16
0

Been long but from what I've checked.NET 6 wont let You specify model parameters without FromBody attribute but only for verbs that shouldnt base on model anyway, like DELETE or GET. You can in fact write POST/PUT requests without specyfing bind attributes thou.

Wont work:

app.MapDelete("/", (SomeModel model) => ...)
app.MapGet("/", (SomeModel model) => ...)

Will work:

app.MapPost("/", (SomeModel model) => ...)
app.MapPut("/", (SomeModel model) => ...)
0

Since you want to use MapGet, you'll need to add a BindAsync method to the UserLogin class

public class UserLogin
{
    public string Username { get; set; }
    public string Password { get; set; }

    public static ValueTask<UserLogin> BindAsync(HttpContext context)
    {
        var result = new UserLogin
        {
            Username = context.Request.Query[nameof(Username)],
            Password = context.Request.Query[nameof(Password)],
        };

        return ValueTask.FromResult(result);
    }
}
giorgi02
  • 683
  • 6
  • 13