jwa*_*zko 7 .net validation asp.net-mvc data-annotations
对于我的ASP.NET MVC应用程序,我创建了自定义验证属性,并指出可以为单个字段或属性指定多个实例:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public sealed class SomeAttribute: ValidationAttribute
Run Code Online (Sandbox Code Playgroud)
我为这样的属性创建了验证器:
public class SomeValidator : DataAnnotationsModelValidator<SomeAttribute>
Run Code Online (Sandbox Code Playgroud)
并在Application_StartGlobal.asax 中将其连接起来
DataAnnotationsModelValidatorProvider.RegisterAdapter(
typeof (SomeAttribute), typeof (SomeValidator));
Run Code Online (Sandbox Code Playgroud)
最后,如果我以所需的方式使用我的属性:
[SomeAttribute(...)] //first
[SomeAttribute(...)] //second
public string SomeField { get; set; }
Run Code Online (Sandbox Code Playgroud)
当框架执行验证时,只调用第一个属性实例.第二个似乎死了.我注意到在每个请求期间只创建了一个验证器实例(对于第一个注释).
如何解决这个问题并解雇所有属性?
让我回答一下.从MSDN(http://msdn.microsoft.com/en-us/library/system.attribute.typeid.aspx,http://msdn.microsoft.com/en-us/library/6w3a7b50.aspx):
在AttributeUsageAttribute.AllowMultiple设置为true的情况下定义自定义属性时,必须覆盖Attribute.TypeId属性以使其唯一.如果属性的所有实例都是唯一的,则覆盖Attribute.TypeId以返回属性的对象标识.如果只有属性的某些实例是唯一的,则返回Attribute.TypeId中的值,该值将在这些情况下返回相等性.例如,某些属性具有构造函数参数,该参数充当唯一键.对于这些属性,从Attribute.TypeId属性返回构造函数参数的值.
实现时,该标识符仅是属性的类型.但是,意图是使用唯一标识符来标识相同类型的两个属性.
总结一下:
TypeId被记录为"用于标识相同类型的两个属性的唯一标识符".默认情况下,TypeId只是属性的类型,因此当遇到两个相同类型的属性时,它们被MVC验证框架视为"相同".
实施:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public sealed class SomeAttribute: ValidationAttribute
{
private string Parameter { get; set; }
public override object TypeId
{
get { return string.Format("{0}[{1}]", GetType().FullName, Parameter); }
}
public SomeAttribute(string parameter)
{
Parameter = parameter;
}
Run Code Online (Sandbox Code Playgroud)
这种TypeId创建方式选择如下:
完成后,服务器端验证案例工作.当这个想法需要与不引人注目的客户端验证相结合时,问题就开始了.假设您已按以下方式定义了自定义验证器:
public class SomeAttributeValidator : DataAnnotationsModelValidator<SomeAttribute>
{
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
var rule = new ModelClientValidationRule {ValidationType = "someattribute"};
rule.ValidationParameters.Add(...)
yield return rule;
}
Run Code Online (Sandbox Code Playgroud)
有这个:
public class Model
{
[SomeAttribute("first")]
[SomeAttribute("second")]
public string SomeField { get; set; }
Run Code Online (Sandbox Code Playgroud)
导致以下错误:
不显眼的客户端验证规则中的验证类型名称必须是唯一的.以下验证类型不止一次出现:someattribute
如上所述,解决方案是拥有独特的验证类型.我们必须区分每个已注册的属性实例,它已用于注释字段,并为其提供相应的验证类型:
public class SomeAttributeValidator : DataAnnotationsModelValidator<SomeAttribute>
{
private string AnnotatedField { get; set; }
public SomeAttributeValidator(
ModelMetadata metadata, ControllerContext context, SomeAttribute attribute)
: base(metadata, context, attribute)
{
AnnotatedField = string.Format("{0}.{1}",
metadata.ContainerType.FullName, metadata.PropertyName);
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
var count = Storage.Get<int>(AnnotatedField) + 1;
Storage.Set(AnnotatedField, count);
var suffix = char.ConvertFromUtf32(96 + count); // gets a lowercase letter
var rule = new ModelClientValidationRule
{
ValidationType = string.Format("someattribute{0}", suffix)
};
Run Code Online (Sandbox Code Playgroud)
(验证类型必须只包含小写字母 - 使用上面的解决方案,如果你有超过26个属性 - 整个字母表用尽,预计会有异常)
其中Storage是简单的实用程序,它存储当前http请求的数据:
internal class Storage
{
private static IDictionary Items
{
get
{
if (HttpContext.Current == null)
throw new ApplicationException("HttpContext not available.");
return HttpContext.Current.Items;
}
}
public static T Get<T>(string key)
{
if (Items[key] == null)
return default(T);
return (T)Items[key];
}
public static void Set<T>(string key, T value)
{
Items[key] = value;
}
}
Run Code Online (Sandbox Code Playgroud)
最后,JavaScript部分:
$.each('abcdefghijklmnopqrstuvwxyz'.split(''), function(idx, val) {
var adapter = 'someattribute' + val;
$.validator.unobtrusive.adapters.add(adapter, [...], function(options) {
options.rules[adapter] = {
...
};
if (options.message) {
options.messages[adapter] = options.message;
}
});
});
$.each('abcdefghijklmnopqrstuvwxyz'.split(''), function(idx, val) {
var method = 'someattribute' + val;
$.validator.addMethod(method, function(value, element, params) {
...
}, '');
});
Run Code Online (Sandbox Code Playgroud)
要获得完整的解决方案,请查看此来源.
| 归档时间: |
|
| 查看次数: |
1110 次 |
| 最近记录: |