2010-01-21 15 views
10

WATF projemde IDataErrorInfo arabirimi üzerinden geçerliliği uygulamaya başladım. İşletmemdeki nesne, doğrulama bilgisiyle birden çok özellik içeriyor. Nesne ile ilişkili tüm hata iletilerinin listesini nasıl alabilirim. Benim düşüncem, Error özelliğinin ne olduğudır, ancak birden çok özellik hakkında raporlama yapmak için bunu kullanan herkesi izleyemem.Birden çok BO özelliği için bir IDataErrorInfo Hata Özelliği tanımlayabilirim

Teşekkürler!

public string this[string property] 
    { 
     get { 

      string msg = null; 
      switch (property) 
      { 
       case "LastName": 
        if (string.IsNullOrEmpty(LastName)) 
         msg = "Need a last name"; 
        break; 
       case "FirstName": 
        if (string.IsNullOrEmpty(LastName)) 
         msg = "Need a first name"; 
        break; 

       default: 
        throw new ArgumentException(
         "Unrecognized property: " + property); 
      } 
      return msg; 

     } 
    } 

    public string Error 
    { 
     get 
     { 
      return null ; 
     } 
    } 

cevap

11

Dizinleyiciyi nerede kullanabileceğinizi görüyorum. Gitmek için kötü bir yol değil sanırım. Gerçekten de 'Error' özelliği üzerinde duruldu. İş nesnesinde bulunan hatalara sahip olma fikrini seviyorum.

public string this[string property] 
    { 
     get { 

      string msg = null; 
      switch (property) 
      { 
       case "LastName": 
        if (string.IsNullOrEmpty(LastName)) 
         msg = "Need a last name"; 
        break; 
       case "FirstName": 
        if (string.IsNullOrEmpty(FirstName)) 
         msg = "Need a first name"; 
        break; 
       default: 
        throw new ArgumentException(
         "Unrecognized property: " + property); 
      } 

      if (msg != null && !errorCollection.ContainsKey(property)) 
       errorCollection.Add(property, msg); 
      if (msg == null && errorCollection.ContainsKey(property)) 
       errorCollection.Remove(property); 

      return msg; 
     } 
    } 

    public string Error 
    { 
     get 
     { 
      if(errorCollection.Count == 0) 
       return null; 

      StringBuilder errorList = new StringBuilder(); 
      var errorMessages = errorCollection.Values.GetEnumerator(); 
      while (errorMessages.MoveNext()) 
       errorList.AppendLine(errorMessages.Current); 

      return errorList.ToString(); 
     } 
    } 
+0

Bu güzel. En son hata iletisiyle errorCollection'ı güncel tutmak daha iyi olurdu (eğer anahtar zaten mevcutsa ve mesaj boş değil ise). – danjarvis

+0

'Error' özelliği şu amaç için optimize edilebilir:' get {return string.Join (Environment.NewLine, errorCollection.Values); } ', boşsa, yalnızca" "döndürür; bu, (arabirim belgelerinde yazılıdır) hata olarak kabul edilmez. – Tatranskymedved

1

Anladığım kadarıyla, bu arabirimi kullanmak için, nesnenin özelliklerini numaralandırırsınız ve her özellik için dizinleyiciyi bir kez çağırırsınız. Herhangi bir hata mesajını toplamak, arayanın sorumluluğundadır.

+0

teşekkür benziyor. Sen haklısın İş nesnesinde daha kapsüllenmiş bir çözüm arıyordum, yukarı bakınız. Belki de endişelerin ayrılması için en mükemmel çözüm değildir. – Bob

11
: Bir CarriageReturn, hata listesini ayrılmış şöyle ben doesnt yapmak istediğim doğal bulunduğuna bakın düşünüyorum, bu yüzden sadece nesne üzerinde hatalar (güncellenmiş zaman bir özellik değişiklikleri) ait bir sözlük oluşturulur ve hata geri dönelim

Doğrulama niteliklerini kullanmanın çok daha kolay olduğunu düşünüyorum.

class MyBusinessObject { 
    [Required(ErrorMessage="Must enter customer")] 
    public string Customer { get; set; } 

    [Range(10,99, ErrorMessage="Price must be between 10 and 99")] 
    public decimal Price { get; set; } 

    // I have also created some custom attributes, e.g. validate paths 
    [File(FileValidation.IsDirectory, ErrorMessage = "Must enter an importfolder")] 
    public string ImportFolder { get; set; } 

    public string this[string columnName] { 
     return InputValidation<MyBusinessObject>.Validate(this, columnName); 
    } 

    public ICollection<string> AllErrors() { 
     return InputValidation<MyBusinessObject>.Validate(this); 
    } 
} 

yardımcı sınıfı InputValidation bu

internal static class InputValidation<T> 
    where T : IDataErrorInfo 
{ 
    /// <summary> 
    /// Validate a single column in the source 
    /// </summary> 
    /// <remarks> 
    /// Usually called from IErrorDataInfo.this[]</remarks> 
    /// <param name="source">Instance to validate</param> 
    /// <param name="columnName">Name of column to validate</param> 
    /// <returns>Error messages separated by newline or string.Empty if no errors</returns> 
    public static string Validate(T source, string columnName) { 
     KeyValuePair<Func<T, object>, ValidationAttribute[]> validators; 
     if (mAllValidators.TryGetValue(columnName, out validators)) { 
      var value = validators.Key(source); 
      var errors = validators.Value.Where(v => !v.IsValid(value)).Select(v => v.ErrorMessage ?? "").ToArray(); 
      return string.Join(Environment.NewLine, errors); 
     } 
     return string.Empty; 
    } 

    /// <summary> 
    /// Validate all columns in the source 
    /// </summary> 
    /// <param name="source">Instance to validate</param> 
    /// <returns>List of all error messages. Empty list if no errors</returns> 
    public static ICollection<string> Validate(T source) { 
     List<string> messages = new List<string>(); 
     foreach (var validators in mAllValidators.Values) { 
      var value = validators.Key(source); 
      messages.AddRange(validators.Value.Where(v => !v.IsValid(value)).Select(v => v.ErrorMessage ?? "")); 
     } 
     return messages; 
    } 

    /// <summary> 
    /// Get all validation attributes on a property 
    /// </summary> 
    /// <param name="property"></param> 
    /// <returns></returns> 
    private static ValidationAttribute[] GetValidations(PropertyInfo property) { 
     return (ValidationAttribute[])property.GetCustomAttributes(typeof(ValidationAttribute), true); 
    } 

    /// <summary> 
    /// Create a lambda to receive a property value 
    /// </summary> 
    /// <param name="property"></param> 
    /// <returns></returns> 
    private static Func<T, object> CreateValueGetter(PropertyInfo property) { 
     var instance = Expression.Parameter(typeof(T), "i"); 
     var cast = Expression.TypeAs(Expression.Property(instance, property), typeof(object)); 
     return (Func<T, object>)Expression.Lambda(cast, instance).Compile(); 
    } 

    private static readonly Dictionary<string, KeyValuePair<Func<T, object>, ValidationAttribute[]>> mAllValidators; 

    static InputValidation() { 
     mAllValidators = new Dictionary<string, KeyValuePair<Func<T, object>, ValidationAttribute[]>>(); 
     foreach (var property in typeof(T).GetProperties()) { 
      var validations = GetValidations(property); 
      if (validations.Length > 0) 
       mAllValidators.Add(property.Name, 
         new KeyValuePair<Func<T, object>, ValidationAttribute[]>(
         CreateValueGetter(property), validations)); 
     }  
    } 
} 
+1

Bu başka bir iyi çözüm, teşekkürler. Benim için bir VM mülkünde, standart IDataErrorInfo'nun yapmadığı işe yaradı. Birisi bunu kullanırsa, System.ComponentModel.DataAnnotations öğesine bir başvuru eklemeniz gerekir. – Bob

+0

Bu mükemmel - MVC dünyasından gelen aynı sözleşmeyi kullanabilmek harika. – Cody

İlgili konular