首页 > 解决方案 > .NET Core,通过验证将字符串绑定到集合

问题描述

有控制器:

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

端点应该有参数x=1,2,3。我想要达到的目标:

  1. 将字符串值转换1,2,3IReadOnlyCollection<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
}

捆绑

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

标签: c#asp.net-coremodel-bindingmode

解决方案


推荐阅读