在ASP.NET Core 2.2中嵌套属性的模型绑定

时间:2018-11-06 22:33:08

标签: asp.net-core binding asp.net-core-mvc

我正在尝试为我的模型(动作参数)创建一个通用的复杂对象,并在许多地方重复使用。

以下是一些示例代码:

[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类将具有可在许多模型中使用的验证和通用属性。

在嵌套属性中添加[FromQuery(Name = "Something")]可以使您大张旗鼓,但是却不可能拥有两个具有相同类型的嵌套属性。

UDPATE:

我知道添加完全限定的属性名称( ... / values?Id = 1&Generated.DateInfo = 2&Reference.DateInfo = 3 )会使它起作用,但这确实很丑陋调用任何API的方式。连字符,而不是点。

我想以与映射常规属性相同的方式来映射绑定。

如何实现?

1 个答案:

答案 0 :(得分:0)

我看到两个选择。

选项1:只需创建一个新的扁平化类{Id, Foo, Bar}即可用作您的操作方法的参数。然后,您可以将其映射到MyModel。这是我建议最可维护的方法。

选项2:自定义模型绑定,如下所示:

[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 的扩展,您可以合理地编写一些反射,以获取嵌套模型的所有叶子属性名称。