有控制器:
public async Task<IActionResult> GetFoo([FromQuery] FooParams params)
{
// ...
}
该端点应具有参数x=1,2,3
。我要实现的目标:
1,2,3
转换为IReadOnlyCollection<string>
(〜new HashSet<string> { "1", "2", "3" }
)这里的模型:
class FooParams
{
[Required]
[RegularExpression("^\\d+(,\\d+)*$")]
[BindProperty(Name = "x")]
public IReadOnlyCollection<string> Params { get; set; }
// ... more properties here
}
Custom Model Binding in ASP.NET Core指出:
自定义模型活页夹:...通常不应该用于将字符串转换为自定义类型,TypeConverter通常是更好的选择。
所以我要这样写我的自定义TypeConverter
:
public class FooTypeConverter : CollectionConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) =>
sourceType == typeof(string);
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) =>
destinationType == typeof(IReadOnlyCollection<string>);
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
var plainValue = value as string;
if (string.IsNullOrWhiteSpace(plainValue))
{
return null;
}
var values = plainValue
.Split(",", StringSplitOptions.RemoveEmptyEntries)
.Select(v => v.Trim());
return new HashSet<string>(values);
}
}
很遗憾,我无法将[TypeConverter(typeof(FooTypeConverter))]
应用于财产本身。当我为整个模型类设置TypeCovnerterAttribute
时,唯一不被忽略的地方是这样做,但是这样做会使转换器稍微复杂一些。
另一种方法是将我的类型转换器设置为IReadOnlyCollection<string>
(在Startup.cs
中):
TypeDescriptor.AddAttributes(typeof(IReadOnlyCollection<string>), new TypeConverterAttribute(FooTypeConverter));
...但是通过这种方式,我在其他地方“配置”了模型的行为,这可能在几天之内(或者其他任何人)对我来说都不是很清楚。
有更好的方法吗?我是否应该实施IModelBinder
?
我当前使用RegularExpressionAttribute
的尝试失败-看来我只能验证目标类型。但这对于确定参数是否完全丢失还是格式无效已经为时已晚(实现IModelBinder
时,我可以在模型状态中添加验证错误,将绑定和验证结合在一个地方)。