Interfejs IValidatable
Zacznijmy od samego początku ponieważ walidacja musi być łatwo dostępna i wielokrotnego użytku każdy obiekt który będzie posiadał walidacje musi implementować powyższy interfejs. Nic specjalnego:
public interface IValidatable
{
ValidationResult Validate();
}
ValidationResult
Klasa ta składa się ze słownika który przechowuje informacje o błędzie jak i pole którego dotyczy informacja. Natomiast z powodu ze dane pole może posiadać wiele błędów dlatego przechowuje listę stringów. Oprócz tego posiada 2 funkcje 1 do zliczania błędów a druga do dodawania błędów do słownika. Sama klasa wygląda tak:
public class ValidationResult
{
private IDictionary<string, IList<string>> _validationErrors;
public ValidationResult()
{
_validationErrors = new Dictionary<string, IList<string>>();
}
public IDictionary<string, IList<string>> Errors
{
get { return _validationErrors; }
private set { _validationErrors = value; }
}
public int CountErrors()
{
int errorCount = 0;
foreach (var errorMessages in _validationErrors.Values)
{
errorCount += errorMessages.Count;
}
return errorCount;
}
public void AddError(KeyValuePair<string, string> error)
{
if (error.Key != null)
{
if (_validationErrors.ContainsKey(error.Key))
{
_validationErrors[error.Key].Add(error.Value);
}
else
{
IList<string> newErrorList = new List<string>();
newErrorList.Add(error.Value);
_validationErrors.Add(new KeyValuePair<string, IList<string>>(error.Key, newErrorList));
}
}
}
}
ValidationHelper
Żeby troszeczkę sobie ułatwić dodawanie błędów postanowiłem stworzyć klasę pomocnicza która będzie nieco automatyzować dodawanie błędów. Będzie to obiekt który posiada 2 metody które dodają błąd jeżeli warunek jest niespełniony. Różnią się tylko 1 parametrem związanym z kluczem błędu. Zwykle nazywa się tak samo jak dane pole którego dotyczy. I w tym celu służy wersja metody z wyrażeniem lambda. Natomiast druga przyjmuje parametr string. Czyli jest bardziej uogólniona. Klasa wygląda tak:
public class ValidationHelper<T>
{
public ValidationHelper()
{
}
public KeyValuePair<string, string> CreateErrorIf(bool condition, string errorKey, string errorMessageKey)
{
if (!condition)
return new KeyValuePair<string, string>(errorKey, ResourceHelper.GetErrorMessage(errorMessageKey));
else
return new KeyValuePair<string, string>();
}
public KeyValuePair<string, string> CreateErrorIf<TResult>(bool condition, Expression<Func<T, TResult>> errorKey, string errorMessageKey)
{
var expressionMember = errorKey.Body as MemberExpression;
return CreateErrorIf(condition, expressionMember.Member.Name, errorMessageKey);
}
}
Metoda która używa wyrażenia lambda po prostu pobiera z niego nazwę danego pola. A teraz przykładowe wykorzystanie powyższych klas:public class User : BaseEntity, IEntity, IValidatable
{
...
public virtual ValidationResult Validate()
{
ValidationResult validationResult = new ValidationResult();
ValidationHelper<User> validationHelper = new ValidationHelper<User>();
validationResult.AddError(validationHelper.CreateErrorIf(!String.IsNullOrEmpty(Username), f => f.Username, ResourceKey.Common.RequiredField));
validationResult.AddError(validationHelper.CreateErrorIf(Username.Length >= 256, f => f.Username, ResourceKey.Common.FieldLength));
...
return validationResult;
}
}
Oprócz pisania tego mechanizmu powolutku uzupełniam brakujące testy w projekcie związane już z gotową funkcjonalnością. To tyle na dziś :)

1 komentarz:
Czekam na więcej:) Zawsze można tu czegoś ciekawego się dowiedzieć. W biznesie także super się sprawdzi system od http://zimbra.pl, jest on świetny do sprawnej komunikacji w firmie.e
Prześlij komentarz