2010-10-06 125 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