使用FluentValidation当添加DataAnnotation类 [英] Adding DataAnnotation to class when using FluentValidation

查看:343
本文介绍了使用FluentValidation当添加DataAnnotation类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用FluentValidation框架来验证和注释添加到我的模型在MVC项目。

I use the FluentValidation framework to add validation and annotations to my models in an MVC project.

我需要的数据注解添加到模型的一流水平。即,模型需要有DisplayColumn属性添加。但是,因为我用FluentValidation(并让应用程序的ModelMetadataProvider设置为使用FluentValidation),即使我把模型类的DisplayColumn属性,不使用它。不过,我不能找到一种方法,通过使用FluentValidation补充一点注释。

I need to add data annotations to the class level of a model. Namely, the model needs to have the DisplayColumn attribute added. But, since I use FluentValidation (and have the application's ModelMetadataProvider set to use FluentValidation), even if I put the DisplayColumn attribute on the model class, it isn't used. However, I can't find a way to add that annotation by using FluentValidation.

没有人有任何想法我怎么能得到那个工作?

Does anyone have any idea how I can get that to work?

感谢

推荐答案

我不竟建议使用FluentValidationModelMetadataProvider - 这是唯一真正过一个实验加法(这很可能在未来版本中被删除),并且它不支持任何类级DataAnnotations(如DisplayColumn)。我建议你​​使用FluentValidation只为验证,但与元数据属性坚持下去。

I wouldn't actually recommend using the FluentValidationModelMetadataProvider - this was only really ever an experimental addition (which very well may be removed from the next release), and it doesn't support any of the class-level DataAnnotations (such as DisplayColumn). I would suggest that you use FluentValidation only for validation, but stick with attributes for metadata.

话虽这么说,如果你真的想要得到这个工作,那么你可以通过使用自定义无操作即是仅用于元数据的验证程序实现:

That being said, if you really want to get this working then you could implement by using a custom no-op validator that's used only for metadata:

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);
        }
    }
}

...然后你可以使用这样的:

... Which you could then use like this:

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

    }
}

您会再需要创建一个知道如何处理这种自定义ModelMetadataProvider:

You'd then need to create a custom ModelMetadataProvider that knows how to process this:

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元数据提供商使用此提供。

The provider overrides the GetMetadataForModel method and looks for any properties that use DisplayColumn. This could probably be extended if you want to support any other custom metadata extensions too. You could then use this provider in place of the metadata provider that comes with FluentValidation.

不过,我仍然不会推荐这种方法......该库是专门为执行验证,而不是生成UI的元数据。

However, I still wouldn't recommend this approach...the library is designed for performing validation, not for generating UI metadata.

这篇关于使用FluentValidation当添加DataAnnotation类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆