简体   繁体   English

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.我正在尝试为我的模型(动作参数)创建一个通用的复杂对象,并在许多地方重用它。

Here is some sample code:下面是一些示例代码:

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

Imagine the DateInfo class would have validation and common properties to be used in many models.想象一下 DateInfo 类将具有要在许多模型中使用的验证和通用属性。

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.[FromQuery(Name = "Something")]到嵌套属性中可以实现 swagger 的技巧,但它使得两个嵌套属性不可能具有相同的类型。

UDPATE: UDPATE:

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.我知道添加完全限定的属性名称( .../values?Id=1&Generated.DateInfo=2&Reference.DateInfo=3 )会使其工作,但这将是调用任何 API 的一种非常丑陋的方式。 Hyphens are the way, not dots.连字符是方式,而不是点。

I would like to map the binding in the same way as mapping a regular property.我想以与映射常规属性相同的方式映射绑定。

How to achieve that?如何做到这一点?

I see two options.我看到两个选项。

Option 1: Just create a new, flattened class {Id, Foo, Bar} to use as the parameter of your action method.选项 1:只需创建一个新的扁平化类{Id, Foo, Bar}用作操作方法的参数。 You can then map that to MyModel.然后您可以将其映射到 MyModel。 That's the approach I would recommend as most maintainable.这是我推荐的最易于维护的方法。

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

As an expansion on Option 2 you could reasonably write some reflection that gets all the leaf property names of your nested model.作为选项 2的扩展,您可以合理地编写一些反射来获取嵌套模型的所有叶属性名称。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM