我有一个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,我需要更改什么?
答案 0 :(得分:3)
您可以在方法标题中使用List<string>
,然后根据您的规则将其加载到HashSet中:
public GetPeople([FromQuery] List<string> names)
{
var hashed = new HashSet<string>(names, StringComparer.OrdinalIgnoreCase);
}
作为替代方案,您可以研究自定义模型绑定,但是只有在多个地方需要它时,才值得付出努力。
答案 1 :(得分:2)
您可以使用设置为始终使用HashSet<string>
的{{1}}派生类:
StringComparer.OrdinalIgnoreCase
使用它非常简单,就像这样:
// Case Insensitive String HashSet, or CIStringSet for short.
public class CIStringSet : HashSet<string>
{
public CIStringSet() : base(StringComparer.OrdinalIgnoreCase)
{
}
}
经过测试,可以正常工作:
答案 2 :(得分:0)
一种可能的解决方案是创建一个指定相等比较器的派生类型,然后绑定到该派生类型。
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
}
此解决方案的问题在于扩展性不佳:您必须为每种比较类型创建一个派生类型。
答案 3 :(得分:0)
一个完全静态的解决方案,完全没有错误处理,但是下面的方法可以解决
活页夹:
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在全球范围内注册,但是为此,它需要执行更多检查。