将ASP.NET MVC Controller属性注入服务层依赖项?

我正在使用类似于ASP.NET MVC教程中的方法 ,您将控制器的ModelState集合中的包装器传递给validation类,以便控制器可以访问错误信息。

这是一个熟练的例子:

 interface IProductValidator { void Validate(Product item); } class ProductValidator { // constructor public ProductValidator(ModelStateWrapper validationDictionary) { } } interface IProductService { void AddProduct(); } public class ProductService : IProductService { // constructor public ProductService(IProductValidator validator) { } } 

使用Castle Windsor容器进行IoC / DI,如何创建IProductService ? 通常,我会:

 MvcApplication.IocContainer.Resolve() 

但是这不能将Controller的ModelState属性的值注入到ProductValidator的构造函数中。 我可以使用构造函数参数来连接它,但这看起来真的很难看。

我假设您希望传递的模型状态自动将任何错误注入您的模型中? 恕我直言,ModelState应该保持原样,并将validation错误带到它。 以下是我如何处理错误的例子。 我不是说这是最好的方式或唯一的方法,但它是一种方法,您的validation层不必知道谁或什么消耗validation错误。

首先,在我的poco中,我使用System.ComponentModel.DataAnnotations作为validation规则。 例如,这是我的帐户类。

 public class Account : CoreObjectBase { 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; } } 

因为我希望能够自己启动validation(在MVC之外自己做),我必须实现自己的validation器。

 public class Validator where T : CoreObjectBase { public ValidationResponse Validate(T entity) { var validationResults = new List(); 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 Violations { get; private set; } public IList Errors { get; private set; } public bool HasViolations { get { return Violations.Count > 0; } } public ValidationResponse(params ValidationResult[] violations) { Violations = new List(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; } } 

为了将这个validation包装好我的poco类,我inheritance了一个基类。 对于validation,使其成为通用的inheritance子必须告诉基类的类型。 它感觉循环,但它的工作原理。

 [Serializable] public class CoreObjectBase : IValidatable where T : CoreObjectBase { #region IValidatable Members public virtual bool IsValid { get { // First, check rules that always apply to this type var result = new Validator().Validate((T)this); // return false if any violations occurred return !result.HasViolations; } } public virtual ValidationResponse ValidationResults { get { var result = new Validator().Validate((T)this); return result; } } public virtual void Validate() { // First, check rules that always apply to this type var result = new Validator().Validate((T)this); // throw error if any violations were detected if (result.HasViolations) throw new RulesException(result.Errors); } #endregion } 

最后,正如您所看到的,我的validation会抛出一个RulesException。 此类是所有错误的包装器。

 [Serializable] public class RulesException : Exception { public IEnumerable Errors { get; private set; } public RulesException(IEnumerable errors) { Errors = errors != null ? errors : new List(); } 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) } ) { } } 

所以,说到这一点,我在控制器中的validation看起来更像是这样

 public ActionResult MyAction() { try { //call validation here } catch (RulesException ex) { ModelState.AddModelStateErrors(ex); } return View(); } 

ModelState.AddModelStateErrors(前); 是我写的扩展方法。 这很简单。

  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应用程序,Web服务还是Windows应用程序 – 决定如何处理这些错误。

我觉得将MVC控制器/模型/视图状态注入模型/ services / repositories / etc是违反了层之间的基本分离。