.NET Core,将字符串绑定到具有验证的集合

时间:2018-08-23 12:54:19

标签: c# asp.net-core model-binding mode

有控制器:

public async Task<IActionResult> GetFoo([FromQuery] FooParams params)
{
    // ...
}

该端点应具有参数x=1,2,3。我要实现的目标:

  1. 将字符串值1,2,3转换为IReadOnlyCollection<string>(〜new HashSet<string> { "1", "2", "3" }
  2. 在转换之前验证属性值(应用正则表达式)

这里的模型:

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时,我可以在模型状态中添加验证错误,将绑定和验证结合在一个地方)。

0 个答案:

没有答案