2010-10-06 97 views
9

我正在使用类似于这个ASP.NET MVC tutorial中的方法,其中您将控制器的ModelState集合的包装传递到验证类中,以便控制器可以访问错误信息。注入ASP.NET MVC控制器属性到服务层依赖?

这里是一个炮制例如:

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) { } 
} 

使用了IOC/DI的Castle Windsor容器,我怎么创建IProductService?通常情况下,我会:

MvcApplication.IocContainer.Resolve<IProductService>() 

,但这是无法将控制器的ModelState属性的值注入到构造函数ProductValidator。我可以使用构造函数参数来连接它,但这看起来很难看。

+0

您退房: http://stackoverflow.com/questions/2077055/ioc-on-ivalidationdictionary-with-castle-windsor – bzarah 2010-10-06 15:56:28

+0

这是一个非常类似的问题:在我的情况下,我甚至不尝试实例化验证器 - 我希望容器解决它。无论如何,你链接的问题对我来说没有任何答案。我会让这个立场,并希望有一些额外的见解。 – user403830 2010-10-06 16:23:11

+0

我希望有一些方法来静态获取当前的ControllerContext,就像你可以通过HttpContext.Current获取当前的HttpContext一样。不幸的是,我找不到一个。另一个想法是在IProductValidator上有一个额外的方法,它会接受一个“ModelStateWrapper”,并将验证错误复制到那里。不如依赖注入好,但它应该很容易工作。 – PatrickSteele 2010-10-07 13:13:57

回答

2

我假设你想让modelstate传入来自动将任何错误注入到模型中?恕我直言,ModelState应该保持它的位置,并且将验证错误带给它。以下是我如何处理错误的例子。我并不是说这是最好的方法或唯一的方法,但它是验证层不需要了解谁或什么会消耗验证错误的一种方法。

首先,在我的poco中,我使用System.ComponentModel.DataAnnotations作为验证规则。例如,这是我的帐户类。因为我想自己发起验证(除了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; 
    } 
} 

为了包装这验证了一个非常基本的类的所有漂亮和整洁用我的poco类,我从一个基类继承。为了验证,通用的地方是继承的孩子必须告诉基类是类型的。它感觉是圆形的,但它起作用。

[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(除息);是我写的一个扩展方法。这很简单。

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​​控制器/模型/视图状态返回到模型/服务/存储库/等是违反层之间的基本分离。

+0

对我很好!不知道为什么你的RulesException类是可序列化的?你能解释一下吗? – Haroon 2011-06-10 09:24:12

+0

我使它成为可序列化的,因此规则异常可以在应用程序中通过Web服务调用我的代码来使用和呈现。 – Josh 2011-06-10 12:30:35