【问题标题】:Set property is rule is valid with FluentValidation设置属性是规则对 FluentValidation 有效
【发布时间】:2015-02-17 16:25:56
【问题描述】:

我有一个看起来像这样的验证器

public class ImageValidator : AbstractValidator<Image>
{
    public ImageValidator()
    {
        RuleFor(e => e.Name).NotEmpty().Length(1, 255).WithMessage("Name must be between 1 and 255 chars");

        RuleFor(e => e.Data).NotNull().WithMessage("Image must have data").When(e => e.Id == 0);

        RuleFor(e => e.Height).GreaterThan(0).WithMessage("Image must have a height");

        RuleFor(e => e.Width).GreaterThan(0).WithMessage("Image must have a width");
    }
}

现在我的单元测试失败了,因为高度和宽度是根据数据中的值填充的。

Data 包含一个创建位图图像的字节数组。如果 Data 不为空(并且 Id 等于 0,因此它是一个新图像),我可以创建一个位图图像并获取高度和宽度值。更新后,Height 和 Width 已经被填充,Data 可能为 null,因为它已经存储在数据库中。

如果数据的验证规则在我的验证器中为真,我是否可以填充高度和宽度的值?

在我有支票之前

if (myObject.Data == null) throw new ApplicationException(...

但我认为这是一个验证规则,应该在验证器中,还是我只需要将规则拆分?

【问题讨论】:

  • 这里有一个建议。我很喜欢 Fluent,这意味着我一直在制作静态方法。在这种情况下,您想知道 e.Data 检查的 Bool 值返回。如果 RuleFor 是一个静态方法并且它返回一个 RuleFor 实例,你可以像这样链接它。
  • @JohnPeters RuleFor 是在通用 AbstractValidator 类中定义的实例方法,该类是 FluentValidation 包的一部分。我不确定你的“Fluent”是什么意思。
  • 我正试图为你指明一条路。给定以下代码: RuleFor(e => e.Data).NotNull() 您可能希望使用 CallBack 将 NotNullCheck 替换为类似于下面代码中所示的内容。我当时只是猜测 RuleFor 是一种具有扩展方法的类型,但您在设计上纠正了我。所以这里的问题是在您当前的代码中,为什么 NotNULL 检查作为 Fluent 接口工作。您可以简单地添加另一个扩展方法,例如“CheckIIfNull(p=>{ //callback here}); 现在可以在与数据行相同的行上插入高度和宽度规则。
  • 刚刚更新了答案以反映我之前试图展示的内容。

标签: c# .net validation fluentvalidation fluentvalidation-2.0


【解决方案1】:

目前的代码是这样的,注意 .NotNull() fluent 接口作用于 RuleFor 的结果。

  RuleFor(e => e.Data)
 .NotNull()
 .WithMessage("Image must have data")
 .When(e => e.Id == 0);

假设你可以这样做:

var rf = RuleFor(e => e.Data)
.CheckNull(p=>{
   if(p){ 
       // this is the true branch when data is null don't set height/width}
       rf.WithMessage("Image must have data");
       .When(e=>e.id==0); 
   else{  
       //data is not null set the height and with. 
        rf(e => e.Height).GreaterThan(0).WithMessage("Image must have a height");
        rf(e => e.Width).GreaterThan(0).WithMessage("Image must have a width");
   });

为了让您能够做到这一点,新的 CheckNull 例程必须能够采用与今天的 .NotNull() 方法相同的类型。

【讨论】:

    【解决方案2】:

    感谢约翰·彼得斯为我指明了正确的方向,但这是我最终按照建议所做的事情。

    首先我创建了一个新的验证器来测试字节数组是否有效。此验证器接受将对象和位图作为输入的操作。仅当验证器有效时才会调用此操作。

    public class IsImageValidator<T> : PropertyValidator
    {
        private Action<T, Bitmap> _action;
    
        public IsImageValidator(Action<T, Bitmap> action) : base("Not valid image data")
        {
            _action = action;
        }
    
        protected override bool IsValid(PropertyValidatorContext context)
        {
            var isNull = context.PropertyValue == null;
    
            if (isNull)
            {
                return false;
            }
    
            try
            {
                // we need to determine the height and width of the image
                using (var ms = new System.IO.MemoryStream((byte[])context.PropertyValue))
                {
                    using (var bitmap = new System.Drawing.Bitmap(ms))
                    {
                        // valid image, so call action
                        _action((T)context.Instance, bitmap);                        
                    }
                }
    
            }
            catch (Exception e)
            {
                return false;
            }
    
            return true;
        }
    }
    

    为了更容易调用这个验证器,我创建了一个简单的扩展,就像这样

    public static class SimpleValidationExtensions
    {
        public static IRuleBuilderOptions<T, TProperty> IsImage<T, TProperty>(this IRuleBuilder<T, TProperty> ruleBuilder, Action<T, Bitmap> action)
        {
            return ruleBuilder.SetValidator(new IsImageValidator<T>(action));
        }
    }
    

    现在我可以在我的 ImageValidator 中调用验证器方法,所以我的 ImageValidator 现在看起来像这样。如您所见,我现在可以设置高度和宽度属性。

    public ImageValidator()
    {
        RuleFor(e => e.Name).NotEmpty().Length(1, 255).WithMessage("Name must be between 1 and 255 chars");
    
        RuleFor(e => e.Data).IsImage((e, bitmap) =>
        {
            e.Height = bitmap.Height;
            e.Width = bitmap.Width;
        }).WithMessage("Image data is not valid").When(e => e.Id == 0);
    
        RuleFor(e => e.Height).GreaterThan(0).WithMessage("Image must have a height");
    
        RuleFor(e => e.Width).GreaterThan(0).WithMessage("Image must have a width");
    }
    

    【讨论】:

      猜你喜欢
      • 2013-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-21
      相关资源
      最近更新 更多