在ASP.NET Core 2.2中嵌套属性的模型绑定 [英] Model binding of nested properties in asp.net core 2.2
问题描述
我正在尝试为我的模型(动作参数)创建一个通用的复杂对象,并在许多地方重复使用.
I'm trying to create a common complex object for my models (action parameters) and reuse it in many places.
以下是一些示例代码:
[HttpGet("/api/values")]
public ActionResult<string> Get([FromQuery] MyModel model) {
var sb = new StringBuilder();
sb.AppendLine(model.Id);
sb.AppendLine($"{model.Id}-{model.Generated?.DateStart}-{model.Generated?.DateEnd}");
sb.AppendLine($"{model.Id}-{model.Reference?.DateStart}-{model.Reference?.DateEnd}");
return sb.ToString();
}
public class MyModel {
public string Id { get; set; }
public DateInfo Generated { get; set; } = new DateInfo();
public DateInfo Reference { get; set; } = new DateInfo();
}
public class DateInfo {
public DateTime? DateStart { get; set; }
public DateTime? DateEnd { get; set; }
public RelativeTime? RelativeTime { get; set; }
}
想象一下,DateInfo类将具有可在许多模型中使用的验证和通用属性.
Imagine the DateInfo class would have validation and common properties to be used in many models.
在嵌套属性中添加[FromQuery(Name = "Something")]
可以使您大摇大摆,但是却无法拥有两个具有相同类型的嵌套属性.
Adding [FromQuery(Name = "Something")]
to the nested properties does the trick for swagger, but it makes it impossible to have two nested properties with the same type.
我知道添加完全限定的属性名称( .../values?Id = 1& Generated.DateInfo = 2& Reference.DateInfo = 3 )可以使其正常工作,但这可以是调用任何API的一种非常丑陋的方式.连字符是方式,不是点.
I understand that adding the fully qualified property name (.../values?Id=1&Generated.DateInfo=2&Reference.DateInfo=3) would make it work, but that would be a really ugly way to call any API. Hyphens are the way, not dots.
我想以与映射常规属性相同的方式来映射绑定.
I would like to map the binding in the same way as mapping a regular property.
如何实现?
推荐答案
我看到两个选择.
选项1:只需创建一个新的扁平化类{Id, Foo, Bar}
用作操作方法的参数即可.然后,您可以将其映射到MyModel.这是我建议最可维护的方法.
Option 1: Just create a new, flattened class {Id, Foo, Bar}
to use as the parameter of your action method. You can then map that to MyModel. That's the approach I would recommend as most maintainable.
选项2:自定义模型绑定,如下所示:
Option 2: Custom model binding, as follows:
[ModelBinder(BinderType = typeof(MyModelBinder))]
public class MyModel
{
public string Id { get; set; }
[FromQuery]
public Info ComplexNestedProperty { get; set; }
}
public class AuthorEntityBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var model = new MyModel
{
Id = bindingContext.ValueProvider.GetValue("id"),
ComplexNestedProperty = new Info
{
Foo = bindingContext.ValueProvider.GetValue("foo"),
Bar = bindingContext.ValueProvider.GetValue("bar")
}
};
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
}
}
作为选项2 的扩展,您可以合理地编写一些反射来获取嵌套模型的所有叶子属性名称.
As an expansion on Option 2 you could reasonably write some reflection that gets all the leaf property names of your nested model.
这篇关于在ASP.NET Core 2.2中嵌套属性的模型绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!