![](/img/trans.png)
[英]IValidatableObject.Validate() vs Validator.TryValidateObject()
[英]Why does Validator.TryValidateObject does not validate class if I have validation attribute in a property?
我創建了一個針對類的自定義 ValidationAttribute。 每當我嘗試調用 Validator.TryValidateObject 時,這都會正確驗證。 但是當我的類內的屬性中有其他 ValidationAttribute 時,驗證結果不包含類級別驗證的結果。
這是一個示例代碼:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class IsHelloWorldAttribute : ValidationAttribute
{
public object _typeId = new object();
public string FirstProperty { get; set; }
public string SecondProperty { get; set; }
public IsHelloWorldAttribute(string firstProperty, string secondProperty)
{
this.FirstProperty = firstProperty;
this.SecondProperty = secondProperty;
}
public override bool IsValid(object value)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
string str1 = properties.Find(FirstProperty, true).GetValue(value) as string;
string str2 = properties.Find(SecondProperty, true).GetValue(value) as string;
if (string.Format("{0}{1}", str1,str2) == "HelloWorld")
return true;
return false;
}
public override object TypeId
{
get
{
return _typeId;
}
}
}
這是我需要驗證的類的代碼
[IsHelloWorld("Name", "Code", ErrorMessage="Is not Hello World")]
public class MyViewModel : BaseViewModel
{
string name;
string code;
[Required]
public string Name
{
get { return model.Name; }
set
{
if (model.Name != value)
{
model.Name = value;
base.RaisePropertyChanged(() => this.Name);
}
}
}
public string Code
{
get { return code; }
set
{
if (code != value)
{
code = value;
base.RaisePropertyChanged(() => this.Code);
}
}
}
}
下面是我如何調用 TryValidateObject 方法:
var validationContext = new ValidationContext(this, null, null);
var validationResults = new List<ValidationResult>();
Validator.TryValidateObject(this, validationContext, validationResults, true);
現在,如果我在 Name 屬性中有 [Required] 屬性並且我嘗試調用 Validator.TryValidateObject,則驗證結果只有一個,這就是必需驗證的結果。 但是當我從 Name 中刪除 [Required] 屬性並留下 IsHellowWorld 屬性然后調用 TryValidateObject 時,它會給我一個結果,那就是 HellowWorldValidation 的結果。
我需要做的是獲得類級別和屬性級別的所有驗證。 我可以在不實現我自己的 TryValidateObject 方法的情況下實現這一點嗎?
這是因為如果檢測到屬性錯誤,則檢查會短路。 這是有道理的,因為類級別驗證可能更昂貴,可能涉及回調、其他數據源調用等。
如果檢測到屬性錯誤,則邏輯就這樣簡單地停止。
在 System.ComponentModel.DataAnnotations.Validator 源代碼中:
public static bool TryValidateObject(object instance, ValidationContext validationContext,
ICollection<ValidationResult> validationResults, bool validateAllProperties)
{
if (instance == null)
throw new ArgumentNullException("instance");
if (validationContext != null && instance != validationContext.ObjectInstance)
throw new ArgumentException(DataAnnotationsResources.
Validator_InstanceMustMatchValidationContextInstance, "instance");
bool flag = true;
bool breakOnFirstError = validationResults == null;
foreach (Validator.ValidationError validationError in
Validator.GetObjectValidationErrors(instance, validationContext,
validateAllProperties, breakOnFirstError))
{
flag = false;
if (validationResults != null)
validationResults.Add(validationError.ValidationResult);
}
return flag;
}
請注意對Validator.GetObjectValidationErrors
的調用,它又被定義為:
private static IEnumerable<Validator.ValidationError> GetObjectValidationErrors(
object instance, ValidationContext validationContext,
bool validateAllProperties, bool breakOnFirstError)
{
if (instance == null)
throw new ArgumentNullException("instance");
if (validationContext == null)
throw new ArgumentNullException("validationContext");
List<Validator.ValidationError> list = new List<Validator.ValidationError>();
//Check for property errors here
list.AddRange(Validator.GetObjectPropertyValidationErrors(instance, validationContext,
validateAllProperties, breakOnFirstError));
// Short circuits here if any found
if (Enumerable.Any<Validator.ValidationError>(
(IEnumerable<Validator.ValidationError>) list))
return (IEnumerable<Validator.ValidationError>) list;
// Class level validation occurs below this point
IEnumerable<ValidationAttribute> validationAttributes =
Validator._store.GetTypeValidationAttributes(validationContext);
list.AddRange(Validator.GetValidationErrors(instance, validationContext,
validationAttributes, breakOnFirstError));
if (Enumerable.Any<Validator.ValidationError>(
(IEnumerable<Validator.ValidationError>) list))
return (IEnumerable<Validator.ValidationError>) list;
IValidatableObject validatableObject = instance as IValidatableObject;
if (validatableObject != null)
{
foreach (ValidationResult validationResult in
Enumerable.Where<ValidationResult>(validatableObject.Validate(validationContext),
(Func<ValidationResult, bool>) (r => r != ValidationResult.Success)))
list.Add(new Validator.ValidationError((ValidationAttribute) null, instance,
validationResult));
}
return (IEnumerable<Validator.ValidationError>) list;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.