【问题标题】:Adding DataAnnotation to class when using FluentValidation使用 FluentValidation 时向类添加 DataAnnotation
【发布时间】:2012-06-18 08:39:20
【问题描述】:

我使用 FluentValidation 框架向 MVC 项目中的模型添加验证和注释。

我需要将数据注释添加到模型的类级别。即,模型需要添加 DisplayColumn 属性。但是,由于我使用 FluentValidation(并将应用程序的 ModelMetadataProvider 设置为使用 FluentValidation),即使我将 DisplayColumn 属性放在模型类上,它也不会被使用。但是,我找不到使用 FluentValidation 添加该注释的方法。

有人知道我怎样才能让它工作吗?

谢谢

【问题讨论】:

标签: asp.net-mvc data-annotations fluentvalidation


【解决方案1】:

我实际上并不推荐使用 FluentValidationModelMetadataProvider - 这只是一个实验性添加(很可能会从下一个版本中删除),并且它不支持任何类级别的 DataAnnotations(例如显示列)。我建议您仅将 FluentValidation 用于验证,但坚持使用元数据的属性。

话虽这么说,如果您真的想让它工作,那么您可以使用仅用于元数据的自定义无操作验证器来实现:

public static class MetadataExt {
    public static IRuleBuilderOptions<T, TProperty> DisplayColumn<T, TProperty>(this IRuleBuilder<T, TProperty> rule) {
        var ruleBuilder = (FluentValidation.Internal.RuleBuilder<T, TProperty>)rule;
        ruleBuilder.Rule.AddValidator(new DisplayColumnWrapper(ruleBuilder.Rule.PropertyName));
        return ruleBuilder;
    }

    public class DisplayColumnWrapper : NoopPropertyValidator, IAttributeMetadataValidator {
        private string name;

        public DisplayColumnWrapper(string name) {
            this.name = name;
        }

        public override IEnumerable<ValidationFailure> Validate(PropertyValidatorContext context) {
            return Enumerable.Empty<ValidationFailure>();
        }

        public Attribute ToAttribute() {
            return new DisplayColumnAttribute(name);
        }
    }
}

...然后您可以像这样使用它:

public class Validator : AbstractValidator<SomeModel> {
    public Validator() {
        RuleFor(x => x.DisplayColumnProperty)
            .DisplayColumn();

    }
}

然后您需要创建一个知道如何处理的自定义 ModelMetadataProvider:

public class ExtendedFVModelMetadataProvider : FluentValidationModelMetadataProvider {
    IValidatorFactory _validatorFactory;

    public ExtendedFVModelMetadataProvider(IValidatorFactory validatorFactory)
        : base(validatorFactory) {
        this._validatorFactory = validatorFactory;
    }

    public override ModelMetadata GetMetadataForType(Func<object> modelAccessor, Type modelType) {
        var validator = _validatorFactory.GetValidator(modelType);

        if (validator == null) {
            return base.GetMetadataForType(modelAccessor, modelType);
        }

        // Only look for the DisplayColumnWrapper 
        // There is a mismatch as MVC expects this to be defined at class-level, but FV defines everything at the property level.
        var displayColumns = from memberWithValidator in validator.CreateDescriptor().GetMembersWithValidators()
                             from propertyValidator in memberWithValidator
                             let wrapper = propertyValidator as MetadataExt.DisplayColumnWrapper
                             where wrapper != null
                             select wrapper.ToAttribute();

        var displayColumn = displayColumns.FirstOrDefault();

        // we found a displaycolumn, so pass it over to MVC to build the metadata.
        if (displayColumn != null) {
            return CreateMetadata(new[] { displayColumn }, null /* containerType */, modelAccessor, modelType, null /* propertyName */);
        }

        return base.GetMetadataForType(modelAccessor, modelType);

    }
}

提供程序覆盖 GetMetadataForModel 方法并查找使用 DisplayColumn 的任何属性。如果您也想支持任何其他自定义元数据扩展,这可能会被扩展。然后,您可以使用此提供程序代替 FluentValidation 附带的元数据提供程序。

但是,我仍然不推荐这种方法...该库旨在执行验证,而不是用于生成 UI 元数据。

【讨论】:

  • 谢谢杰里米。我以为会是这样的。我在 FluentValidation 中使用了这个工具,因为我使用实体框架,并且不太喜欢伙伴类“污染”,因为属性简单。你知道是否有另一种方法可以让我只使用 FluentValidation 进行验证而避免使用伙伴类?
  • 哥们级的做法确实是相当的恐怖。我知道的唯一其他元数据提供程序是weblogs.asp.net/rashid/archive/2009/12/24/… 中提到的“Fluent MetadataProvider”,但不幸的是,代码似乎不再可用。我可能会考虑在 FluentValidation 的未来版本中实现更好的元数据提供程序,但目前我只专注于验证方面。
猜你喜欢
  • 2012-03-21
  • 1970-01-01
  • 2011-10-16
  • 2021-10-16
  • 2018-08-10
  • 1970-01-01
  • 1970-01-01
  • 2011-06-17
  • 1970-01-01
相关资源
最近更新 更多