asp.net-mvc DataAnnotations 动态附加属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3607247/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
DataAnnotations dynamically attaching attributes
提问by mare
Apparently it is possible to dynamically attach DataAnnotation attributes to object properties at runtime and as such achieve dynamic validation.
显然,可以在运行时动态地将 DataAnnotation 属性附加到对象属性,从而实现动态验证。
Can someone provide code sample on this?
有人可以提供这方面的代码示例吗?
回答by John Farrell
MVC has a hook to provide your own ModelValidatorProvider. By default MVC 2 uses a sub class of ModelValidatorProvider called DataAnnotationsModelValidatorProvider that is able to use System.DataAnnotations.ComponentModel.ValidationAttribute attributes for validation.
MVC 有一个钩子来提供你自己的 ModelValidatorProvider。默认情况下,MVC 2 使用名为 DataAnnotationsModelValidatorProvider 的 ModelValidatorProvider 子类,它能够使用 System.DataAnnotations.ComponentModel.ValidationAttribute 属性进行验证。
The DataAnnotationsModelValidatorProvider uses reflection to find all the ValidationAttributes and simply loops through the collection to validate your models. All you need to do is override a method called GetValidators and inject your own attributes from whichever source you choose. I use this technique to do convention validations, the properties with DataType.Email attribute always gets passed through a regex, and use this technique to pull information from the database to apply more restrictive validations for "non-power" users.
DataAnnotationsModelValidatorProvider 使用反射来查找所有 ValidationAttributes 并简单地循环遍历集合以验证您的模型。您需要做的就是覆盖一个名为 GetValidators 的方法,并从您选择的任何来源注入您自己的属性。我使用此技术进行约定验证,具有 DataType.Email 属性的属性始终通过正则表达式传递,并使用此技术从数据库中提取信息以对“非电源”用户应用更严格的验证。
The following example simply says "always make any FirstName properties required":
下面的例子只是说“总是需要任何 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);
}
}
All you have to do is register the provider in your Global.asax.cs file:
您所要做的就是在 Global.asax.cs 文件中注册提供程序:
protected void Application_Start()
{
ModelValidatorProviders.Providers.Add(new CustomMetadataValidationProvider());
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
The end result:
最终结果:
with this model:
使用此模型:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime Birthday { get; set; }
}
回答by Frank Horemans
In your global.asax you have to clear the ModelValidatorProviders before adding the new one. Otherwise it will add every annotation two times which will give you a "Validation type names in unobtrusive client validation rules must be unique."-error.
在您的 global.asax 中,您必须在添加新的之前清除 ModelValidatorProviders。否则它会将每个注释添加两次,这会给你一个“不显眼的客户端验证规则中的验证类型名称必须是唯一的。”-错误。
protected void Application_Start()
{
ModelValidatorProviders.Providers.Clear();
ModelValidatorProviders.Providers.Add(new CustomMetadataValidationProvider());
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
回答by Sam
The approach of using a custom MetadataValidationProvider
with an overridden GetValidators
has a few weaknesses:
使用MetadataValidationProvider
带有覆盖的自定义的方法GetValidators
有一些弱点:
- Some attributes such as
DisplayAttribute
aren't related to validation, so adding them at the validation stage doesn't work. - It may not be future-proof; a framework update could cause it to stop working.
- 某些属性(例如)
DisplayAttribute
与验证无关,因此在验证阶段添加它们不起作用。 - 它可能不是面向未来的;框架更新可能会导致它停止工作。
If you want your dynamically-applied data annotations to work consistently, you can subclass DataAnnotationsModelMetadataProvider
and DataAnnotationsModelValidatorProvider
. After doing this, replacethe framework's ones via ModelMetadataProviders.Current
and ModelValidatorProviders.Providers
at application start-up. (You could do it in Application_Start
.)
如果您希望动态应用的数据注释始终如一地工作,您可以子类化DataAnnotationsModelMetadataProvider
和DataAnnotationsModelValidatorProvider
。执行此操作后,通过和在应用程序启动时替换框架的。(你可以在.)ModelMetadataProviders.Current
ModelValidatorProviders.Providers
Application_Start
When you subclass the built-in providers, a systematic and hopefully future-proof way to apply your own attributes is to override GetTypeDescriptor
. I've done this successfully, but it involved creating an implementation of ICustomTypeDescriptor
and PropertyDescriptor
, which required a lot of code and time.
当您对内置提供程序进行子类化时,应用您自己的属性的一种系统且希望面向未来的方法是覆盖GetTypeDescriptor
. 我已经成功地做到了这一点,但它涉及创建ICustomTypeDescriptor
and的实现PropertyDescriptor
,这需要大量的代码和时间。
回答by Matthew Abbott
I don't think you can add attributes to members at runtime, but you could probably use a custom metadata provider to handle this for you.
我认为您不能在运行时向成员添加属性,但您可能可以使用自定义元数据提供程序来为您处理此问题。
You should check out this blog post.
你应该看看这篇博文。