Я предполагаю, что вы хотите, чтобы передаваемое состояние модели автоматически добавляло какие-либо ошибки в вашу модель?ИМХО, ModelState должен оставаться там, где он есть, и вы вносите в него ошибки валидации.Вот как я обрабатываю ошибки в качестве примера.Я не говорю, что это лучший или единственный способ, но это единственный способ, когда ваш уровень проверки не должен знать, кто или что потребляет ошибки проверки.
Во-первых, в моем pocoЯ использую System.ComponentModel.DataAnnotations
для правил проверки.Вот мой класс учетной записи, например.
public class Account : CoreObjectBase<Account>
{
public virtual int AccountId { get; set; }
[Required(ErrorMessage = "Email address is required.")]
public virtual string EmailAddress { get; set; }
[Required(ErrorMessage = "A password is required.")]
public virtual string Password { get; set; }
}
Поскольку я хочу иметь возможность инициировать валидацию самостоятельно (за исключением того, что MVC делает это самостоятельно), мне пришлось реализовать собственный валидатор.
public class Validator<T> where T : CoreObjectBase<T>
{
public ValidationResponse Validate(T entity)
{
var validationResults = new List<ValidationResult>();
var context = new ValidationContext(entity, null, null);
var isValid = Validator.TryValidateObject(entity, context, validationResults);
return new ValidationResponse(validationResults.ToArray());
}
}
Вот ValidationResult, который я передаю обратно
[Serializable]
public class ValidationResponse
{
public IList<ValidationResult> Violations { get; private set; }
public IList<ErrorInfo> Errors { get; private set; }
public bool HasViolations
{
get { return Violations.Count > 0; }
}
public ValidationResponse(params ValidationResult[] violations)
{
Violations = new List<ValidationResult>(violations);
var errors = from v in Violations
from n in v.MemberNames
select new ErrorInfo(n, v.ErrorMessage);
Errors = errors.ToList();
}
}
ErrorInfo - очень простой класс с информацией о моей ошибке
[Serializable]
public class ErrorInfo
{
public string ErrorMessage { get; private set; }
public object Object { get; private set; }
public string PropertyName { get; private set; }
public ErrorInfo(string propertyName, string errorMessage)
: this(propertyName, errorMessage, null)
{
}
public ErrorInfo(string propertyName, string errorMessage, object onObject)
{
PropertyName = propertyName;
ErrorMessage = errorMessage;
Object = onObject;
}
}
, чтобы завершить эту проверку всехс моими классами поко, я унаследован от базового класса.Для валидации, чтобы сделать ее родовой, где унаследованный потомок должен сообщить базовому классу, что это за тип.Это кажется круглым, но это работает.
[Serializable]
public class CoreObjectBase<T> : IValidatable where T : CoreObjectBase<T>
{
#region IValidatable Members
public virtual bool IsValid
{
get
{
// First, check rules that always apply to this type
var result = new Validator<T>().Validate((T)this);
// return false if any violations occurred
return !result.HasViolations;
}
}
public virtual ValidationResponse ValidationResults
{
get
{
var result = new Validator<T>().Validate((T)this);
return result;
}
}
public virtual void Validate()
{
// First, check rules that always apply to this type
var result = new Validator<T>().Validate((T)this);
// throw error if any violations were detected
if (result.HasViolations)
throw new RulesException(result.Errors);
}
#endregion
}
И, наконец, как вы можете видеть, моя проверка выдает исключение RulesException.Этот класс является оболочкой для всех ошибок.
[Serializable]
public class RulesException : Exception
{
public IEnumerable<ErrorInfo> Errors { get; private set; }
public RulesException(IEnumerable<ErrorInfo> errors)
{
Errors = errors != null ? errors : new List<ErrorInfo>();
}
public RulesException(string propertyName, string errorMessage) :
this(propertyName, errorMessage, null)
{
}
public RulesException(string propertyName, string errorMessage, object onObject) :
this (new ErrorInfo[] { new ErrorInfo(propertyName, errorMessage, onObject) } )
{
}
}
Итак, с учетом сказанного моя проверка в моем контроллере выглядит примерно так:
public ActionResult MyAction()
{
try
{
//call validation here
}
catch (RulesException ex)
{
ModelState.AddModelStateErrors(ex);
}
return View();
}
ModelState.AddModelStateErrors (ex);это метод расширения, который я написал.это очень просто.
public static void AddModelStateErrors(this System.Web.Mvc.ModelStateDictionary modelState, RulesException exception)
{
foreach (ErrorInfo info in exception.Errors)
{
modelState.AddModelError(info.PropertyName, info.ErrorMessage);
}
}
Таким образом, я все еще могу использовать DI для своих сервисов / репозиториев и позволить им выдавать ошибку, когда моя модель недействительна.Затем я позволил внешнему интерфейсу - будь то приложение MVC, веб-служба или приложение Windows - решить, что делать с этими ошибками.
Я чувствую, что введение контроллера / модели / представления MVC обратно в модель/ services / repositories / etc - это нарушение основного разделения между слоями.