MinimalAPI - 你是否想将 "Body (Inferred)" 参数注册为一个服务,或者应用 [FromService] 或 [FromBody] 属性?

18
我创建了一个空的 ASP.NET Core 项目,但每当我尝试运行应用程序时,它都会给出下面显示的错误。我甚至不能访问终结点,只要点击播放按钮就会出现这个错误。

System.InvalidOperationException HResult=0x80131509 Message=已推断出正文,但该方法不允许推断正文参数。 下面是我们发现的参数列表:

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?
不清楚为什么会出现这个错误。我尝试添加 [FromService],但它也显示相同的错误。我阅读了这篇文章,针对同样的问题,但它说不要添加[Bind](而我一开始并没有添加),相反要使用[FromService],但我仍然收到同样的错误。我做错了什么吗? 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;
        }
4个回答

15
在我的情况下,我忘记在我的 program.cs 文件中在 app.Run(); 上面添加以下内容:
builder.Services.AddScoped<IUserRepository, UserRepository>();

1
不错的发现,很容易被忽视。帮助节省了大量在线搜索的时间。谢谢! - Cydaps
这对我也起作用,但是我仍然不明白为什么在运行时 MapGet 失败并抛出 System.InvalidOperationException 异常。 - undefined
可能是因为接口类缺少依赖注入的原因吗? - undefined

14

异常消息告诉你问题所在:

已推断为请求正文,但该方法不允许推断的正文参数。

绑定器将UserLogin参数推断为来自请求正文的参数,但是不允许推断正文参数。

最简单的解决方法是将[FromBody]属性添加到UserLogin参数中。但是,在这种情况下,您应该将方法更改为POST,因为GET请求没有请求正文。

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

不幸的是,在最小API中使用[FromQuery]属性无法将复杂对象与查询字符串值绑定,因此我认为你最好的选择是使用[FromBody]MapPost

如果您需要使用MapGet,可以通过在UserLogin类中添加静态的BindAsync方法来解决问题 - 更多详细信息可以在这篇博客文章中找到。另一种选择是将HttpContext传递给操作并从上下文中获取值 - 参见用于绑定[FromForm]的类似答案 - 您可以使用ctx.Request.Query["username"]从HttpContext中获取用户名。


2
谢谢,阅读了您的解释后我意识到应该将它改为POST方法而不是GET。 - MarkCo

0

由于您想要使用MapGet,所以您需要在UserLogin类中添加一个BindAsync方法。

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);
    }
}

0

虽然我检查过很久,但从我所知,.NET 6 将不允许您在没有 FromBody 属性的情况下指定模型参数,但仅适用于不应基于模型的动词,例如 DELETE 或 GET。但事实上,您可以编写不指定绑定属性的 POST/PUT 请求。

无法工作:

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

可以工作:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接