2010-08-31 5 views

ответ

39

У MVC есть крючок, чтобы предоставить свой собственный ModelValidatorProvider. По умолчанию MVC 2 использует подкласс класса ModelValidatorProvider, называемый DataAnnotationsModelValidatorProvider, который может использовать атрибуты System.DataAnnotations.ComponentModel.ValidationAttribute для проверки.

DataAnnotationsModelValidatorProvider использует отражение, чтобы найти все атрибуты ValidationAttributes и просто петли через коллекцию для проверки ваших моделей. Все, что вам нужно сделать, это переопределить метод GetValidators и ввести собственные атрибуты из того источника, который вы выберете. Я использую эту технику для проверки условных условий, свойства с атрибутом DataType.Email всегда передаются через регулярное выражение и используют этот метод для извлечения информации из базы данных, чтобы применить более ограничительные проверки для пользователей, не имеющих полномочий.

Следующий пример просто говорит «всегда делать какие-либо свойства FirstName необходимые»:

public class CustomMetadataValidationProvider : DataAnnotationsModelValidatorProvider 
{ 
    protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes) 
    { 
     //go to db if you want 
     //var repository = ((MyBaseController) context.Controller).RepositorySomething; 

     //find user if you need it 
     var user = context.HttpContext.User; 

     if (!string.IsNullOrWhiteSpace(metadata.PropertyName) && metadata.PropertyName == "FirstName") 
      attributes = new List<Attribute>() {new RequiredAttribute()}; 

     return base.GetValidators(metadata, context, attributes); 
    } 
} 

Все, что вам нужно сделать, это зарегистрировать поставщика в файле Global.asax.cs:

protected void Application_Start() 
    { 
     ModelValidatorProviders.Providers.Add(new CustomMetadataValidationProvider()); 

     AreaRegistration.RegisterAllAreas(); 

     RegisterRoutes(RouteTable.Routes); 
    } 

конечный результат:

end result

ш Ith этой модели:

public class Person 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public DateTime Birthday { get; set; } 
} 
+1

этот замечательный материал jfar! ;) Я думаю, вы спасли меня глубоким погружением в VAB. – mare

+0

Одна из проблем с примером кода в этом ответе - это атрибуты, которые можно обрабатывать дважды: один раз ваш подкласс «DataAnnotationsModelValidatorProvider» и один раз уже существующим. Это может привести к ошибкам. Я думаю, что лучше только передавать атрибуты, которые вы добавляете в вызов 'base.GetValidators', чтобы избежать этого. – Sam

+1

Кроме того, в ASP.NET MVC 4 (и, возможно, другие), 'base.GetValidators' автоматически добавляет' RequiredAttribute', когда 'metadata.IsRequired' является' true'. Один из способов обойти это - установить 'metadata.IsRequired'' false' перед вызовом 'base.GetValidators'. После вызова вы можете вернуть его к исходному значению. – Sam

1

Я не думаю, что вы можете добавлять атрибуты к членам во время выполнения, но вы, вероятно, можете использовать собственный поставщик метаданных для обработки этого для вас.

Вы должны зарегистрироваться this blog post.

+4

Что дает? Отрицательное голосование и без комментариев? –

+1

Разве я не спустил вниз, но я бы сказал, что это не проходит тест на связь только для ссылок. Это была ссылка, чтобы умереть (как это в настоящее время относится кстати). Это указатель, возможно, хороший, но пользователям все равно придется уходить с сайта для реализации. Подумайте о том, чтобы обеспечить более подробную детализацию или преобразование комментария, или принять ошибочное голосование здесь и там. – KyleMit

+2

Что, конечно, ТОЧНО, что произошло, поскольку эта ссылка сейчас мертва. – StevoInco

8

В вашем global.asax вы должны очистить ModelValidatorProviders перед добавлением нового. В противном случае он добавит каждую аннотацию два раза, что даст вам «имена типа проверки в ненавязчивых правилах проверки клиента должны быть уникальными». - ошибка.

protected void Application_Start() 
{ 
    ModelValidatorProviders.Providers.Clear(); 
    ModelValidatorProviders.Providers.Add(new CustomMetadataValidationProvider()); 

    AreaRegistration.RegisterAllAreas(); 

    RegisterRoutes(RouteTable.Routes); 
} 
0

Подход с использованием пользовательских MetadataValidationProvider с перегруженной GetValidators имеет несколько недостатков:

  • Некоторые атрибуты, такие как DisplayAttribute не связанные с проверкой, поэтому добавление их на этапе проверки Безразлично» т работы.
  • Возможно, он не может быть надежным в будущем; обновление базы данных может привести к ее прекращению.

Если вы хотите, чтобы ваши динамически примененные аннотации данных последовательно работать, вы можете создать подкласс DataAnnotationsModelMetadataProvider и DataAnnotationsModelValidatorProvider. После этого замените на фреймворк через ModelMetadataProviders.Current и ModelValidatorProviders.Providers при запуске приложения. (Вы можете сделать это в Application_Start.)

Когда вы подклассифицируете встроенных поставщиков, систематический и, надеюсь, будущий способ применения ваших собственных атрибутов - переопределить GetTypeDescriptor. Я сделал это успешно, но это связано с созданием реализации ICustomTypeDescriptor и PropertyDescriptor, что потребовало большого количества кода и времени.

Смежные вопросы