На самом деле я бы не рекомендовал использовать 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.
Тем не менее, я бы все равно не рекомендовал этот подход... библиотека предназначена для выполнения проверки, а не для создания метаданных пользовательского интерфейса.
person
Jeremy Skinner
schedule
28.04.2011