Rest PUT Web API中的模型属性绑定不是wokring-ASP.NET Core 3.1
我有一个PUT Rest API,我想从主体和路由参数进行绑定 代码 模型类是Rest PUT Web API中的模型属性绑定不是wokring-ASP.NET Core 3.1,rest,asp.net-core,asp.net-core-3.1,Rest,Asp.net Core,Asp.net Core 3.1,我有一个PUT Rest API,我想从主体和路由参数进行绑定 代码 模型类是 public class StatusRequest { [FromRoute(Name = "Id")] [Required(ErrorMessage = "'Id' attribute is required.")] public string Id { get; set; } [FromBody] [Required(Error
public class StatusRequest
{
[FromRoute(Name = "Id")]
[Required(ErrorMessage = "'Id' attribute is required.")]
public string Id { get; set; }
[FromBody]
[Required(ErrorMessage = "'Status' attribute is required.")]
public string Status { get; set; }
}
当我向这个API发出请求时,即使我显式地添加了
FromRoute
属性,Id也没有映射到模型。有什么建议吗?模型绑定将有效覆盖模型类中的[FromRoute]选项。这是故意的(为什么,我不确定,但这是微软的决定)。请参阅此文档的“[FromBody]属性”部分:。正如上面所指出的:“当[FromBody]应用于复杂类型参数时,任何应用于其属性的绑定源属性都会被忽略。”因此,在模型中添加“[FromRoute]”属性没有任何作用……它会被忽略。您可以从模型中删除这两个属性
因此,解决方法是将路由绑定作为方法参数放入put操作中,然后在使用模型之前将其手动添加到控制器中的模型中
[HttpPut("{Id}/someStuffApi")]
public ActionResult UpdateStatus(int Id, [FromBody] StatusRequest StatusRequest)
{
StatusRequest.Id = Id;
// remaining code...
}
此方法的缺点是所需属性不能保留在Id参数上。在模型绑定时它将为空,如果.Net Core 3.1自动模型验证处于活动状态,那么它将始终返回422。因此,如果您必须在将其添加到模型之前手动检查
[HttpPut("{Id}/someStuffApi")]
public ActionResult UpdateStatus(int Id, [FromBody] StatusRequest StatusRequest)
{
StatusRequest.Id = Id;
// remaining code...
}
如果您想要更大的灵活性,可以查看类似HybridModelBinding NuGet包的东西,该包允许使用属性进行各种模型绑定组合。但这是一个第三方依赖,您可能不希望。()您可以使用自定义模型绑定,下面是一个演示: TestModelBinderProvider:
public class TestModelBinderProvider : IModelBinderProvider
{
private readonly IList<IInputFormatter> formatters;
private readonly IHttpRequestStreamReaderFactory readerFactory;
public TestModelBinderProvider(IList<IInputFormatter> formatters, IHttpRequestStreamReaderFactory readerFactory)
{
this.formatters = formatters;
this.readerFactory = readerFactory;
}
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context.Metadata.ModelType == typeof(StatusRequest))
return new StatusBinder(formatters, readerFactory);
return null;
}
}
行动:
[HttpPut("{Id}/someStuffApi")]
public ActionResult UpdateStatus(StatusRequest StatusRequest)
{
return Ok();
}
结果:
这完全是我所知道的,我认为有办法实现这一点,我将看看HybridModelBinding:(我想微软没有考虑到他们一次验证了更多的参数(想象一下,从标题、路线、正文中分为20个部分)使用例如IValidator要困难得多,这需要付出努力,但您可以通过HybridModelBinding库轻松实现这一点
public class StatusBinder: IModelBinder
{
private BodyModelBinder defaultBinder;
public StatusBinder(IList<IInputFormatter> formatters, IHttpRequestStreamReaderFactory readerFactory)
{
defaultBinder = new BodyModelBinder(formatters, readerFactory);
}
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
// callinng the default body binder
await defaultBinder.BindModelAsync(bindingContext);
if (bindingContext.Result.IsModelSet)
{
var data = bindingContext.Result.Model as StatusRequest;
if (data != null)
{
var value = bindingContext.ValueProvider.GetValue("Id").FirstValue;
data.Id = value.ToString();
bindingContext.Result = ModelBindingResult.Success(data);
}
}
}
}
[Required(ErrorMessage = "'Status' attribute is required.")]
public string Status { get; set; }
}
[HttpPut("{Id}/someStuffApi")]
public ActionResult UpdateStatus(StatusRequest StatusRequest)
{
return Ok();
}