将逗号分隔的查询参数(模型属性)绑定到模型集合(AspNetCore 2.0 和 Swashbuckle)

chr*_*ris 1 c# swagger swashbuckle asp.net-core asp.net-core-2.0

与将逗号分隔的查询参数字符串绑定到这些逗号标记值的数组相比,这是一个更复杂的场景。

基本上我有一个名为 User 的简单实体模型:

public class User
{
    public string Name { get; set }
    public int Age { get; set; }
    // rest ommited
}
Run Code Online (Sandbox Code Playgroud)

我希望能够在我的 Web api 端点中提供多个姓名和年龄,如下所示:

http://localhost/api/data/user/query?name=chris,john,alex&age=28,35
Run Code Online (Sandbox Code Playgroud)

它将绑定到用户过滤器的数组(我只是使用实体模型)。Swagger 还会显示测试输入表单,就像您正在输入的单个用户字段一样。

如何使用 AspDotNetCore 2.0 Web Api 和 Swashbucke 来完成此操作,而无需使用字符串创建新模型并在逗号上标记化。我很想创建某种 Swashbuckle/AspNetCore 挂钩(用某些属性装饰方法参数),然后它知道将输入拆分为单独的模型。

我的想法是生成过滤器 Expression>,用于使用过滤器值的集合过滤存储库中的数据:

var exampleExpression = entity => (entity.Name.Contains("chris") || entity.Name.Contains("john") || entity.Name.Contains("alex")) && (entity.Age == 28 || entity.Age == 35);
Run Code Online (Sandbox Code Playgroud)

我可以以编程方式生成表达式树。

我什至考虑了在生成过滤器表达式时获取输入并将其放入字典中进行查找的想法。但我很想听听您的想法和解决方案。

Ray*_*lli 5

我知道这样做的唯一方法是编写IModelBinder. 我在这里做的事情非常相似。

CsvModelBinder.cs

public class CsvModelBinder<T> : IModelBinder where T : IConvertible
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        var fieldName = bindingContext.FieldName;
        var valueProviderResult = bindingContext.ValueProvider.GetValue(fieldName);

        if (valueProviderResult == ValueProviderResult.None)
        {
            return Task.CompletedTask;
        }

        bindingContext.ModelState.SetModelValue(fieldName, valueProviderResult);

        var model = new List<T>();

        foreach(string delimitedString in valueProviderResult.Values)
        {
            var splitValues = delimitedString
                .Split(',')
                .Cast<string>();

            var convertedValues = splitValues
                .Select(str => Convert.ChangeType(str, typeof(T)))
                .Cast<T>();

            model.AddRange(convertedValues);
        }

        bindingContext.Result = ModelBindingResult.Success(model);

        return Task.CompletedTask;
    }
}
Run Code Online (Sandbox Code Playgroud)

ModelsController.cs

[Route("models")]
public class ModelsController : Controller
{
    [HttpGet]
    [Route("{ids}")]
    [Produces(typeof(IEnumerable<Model>))]
    public IActionResult Get
    (
        [ModelBinder(typeof(CsvModelBinder<string>))] IEnumerable<string> ids
    )
    {
        // Get models

        return Ok(models);
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!另外,如果您对我的相关问题有任何见解,我将不胜感激。