[英]Specify equality comparer for model binding to collection types
我有一个API,您可以在其中指定要获取的名称列表。 不允许使用重复的名称,如果两个名称之间只有大小写不同,则将它们视为重复的名称。
GET /api/people?names=john&names=alice
在我自己的.NET代码中,我将使用自定义的相等比较器将所有这些名称收集在HashSet
。
var names = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
但是我认为ASP.NET Core模型绑定没有足够的灵活性。
// GET /api/people?names=john&names=JOHN
[HttpGet("api/people")]
public GetPeople([FromQuery] HashSet<string> names)
{
// this works but names contains both john and JOHN
}
我必须更改什么才能使names
集仅包含john而不包含JOHN?
您可以在方法标题中使用List<string>
,然后根据您的规则将其加载到HashSet中:
public GetPeople([FromQuery] List<string> names)
{
var hashed = new HashSet<string>(names, StringComparer.OrdinalIgnoreCase);
}
作为替代方案,您可以研究自定义模型绑定,但是只有在多个地方都需要时,才值得付出努力。
您可以使用设置为始终使用StringComparer.OrdinalIgnoreCase
的HashSet<string>
派生类:
// Case Insensitive String HashSet, or CIStringSet for short.
public class CIStringSet : HashSet<string>
{
public CIStringSet() : base(StringComparer.OrdinalIgnoreCase)
{
}
}
这样,使用它非常简单:
public object GetPeople([FromQuery] CIStringSet names)
{
return Json(names);
}
经过测试,可以正常工作:
一种可能的解决方案是创建一个指定相等比较器的派生类型,然后绑定到该派生类型。
public class StringSetIgnoreCase : HashSet<string>
{
public StringSetIgnoreCase()
: base(StringComparer.OrdinalIgnoreCase)
{
}
}
// GET /api/people?names=john&names=JOHN&names=alice
[HttpGet("api/people")]
public GetPeople([FromQuery] StringSetIgnoreCase names)
{
// names contains only john and alice
}
该解决方案的问题在于扩展性不佳:您必须为每种比较类型创建一个派生类型。
一个完全静态的解决方案,完全没有错误处理,但是可以解决以下问题
活页夹:
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
var values = valueProviderResult.Values.Select(value => value).ToHashSet(StringComparer.OrdinalIgnoreCase);
bindingContext.Result = ModelBindingResult.Success(values);
return Task.CompletedTask;
}
终点:
[HttpGet]
public IActionResult Test([ModelBinder(typeof(HashSetBinder))] IEnumerable<string> values)
{
return Ok(new
{
values
});
}
然后只需打开网址,例如这样:
http:// localhost:5000 / api / mycontroller?values = 1&values = 1&values = 1&values = 2
结果将是{"values":["1","2"]}
可以使用modelbinding-provider在全球范围内进行注册,但为此需要执行更多检查。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.