На самом деле я бы не рекомендовал использовать FluentValidationModelMetadataProvider - это действительно было только экспериментальным дополнением (которое очень хорошо может быть удалено из следующего выпуска), и оно не поддерживает какие-либо аннотации уровня данных класса (такие какDisplayColumn).Я хотел бы предложить, чтобы вы использовали 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.
Однако я бы порекомендовал этот подход ... библиотека предназначена для выполнения валидации, а не для генерации метаданных пользовательского интерфейса.