2010-10-06 11 views
9

मैं इस ASP.NET MVC tutorial में से एक के समान दृष्टिकोण का उपयोग कर रहा हूं जहां आप एक नियंत्रक के ModelState संग्रह के चारों ओर एक रैपर पास करते हैं, ताकि नियंत्रक त्रुटि जानकारी तक पहुंच सके।सेवा परत निर्भरता में एएसपी.नेट एमवीसी नियंत्रक संपत्ति इंजेक्षन?

यहाँ एक अप पकाया उदाहरण है:

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

आईओसी/DI के लिए Castle Windsor कंटेनर का उपयोग करना, मैं IProductService कैसे बना सकता हूँ? आमतौर पर, मैं होगा:

MvcApplication.IocContainer.Resolve<IProductService>() 

लेकिन इस ProductValidator के लिए निर्माता में नियंत्रक ModelState संपत्ति के मूल्य इंजेक्षन करने में सक्षम नहीं है। मैं संभवतः इसे कन्स्ट्रक्टर पैरामीटर का उपयोग कर तार सकता हूं, लेकिन यह वास्तव में बदसूरत लगता है।

+0

क्या आपने जांच की: http://stackoverflow.com/questions/2077055/ioc-on-ivalidationdictionary-with-castle-windsor – bzarah

+0

यह एक बहुत ही समान प्रश्न है: मेरे मामले में, मैं कोशिश भी नहीं करता एक वैधकर्ता को तुरंत चालू करने के लिए - मैं कंटेनर को हल करना चाहता हूं। किसी भी मामले में, आपके द्वारा लिंक किए गए प्रश्न का मेरे लिए कोई जवाब नहीं है। मैं इसे खड़ा करूंगा और कुछ अतिरिक्त अंतर्दृष्टि के लिए आशा करूंगा। – user403830

+0

मैं उम्मीद कर रहा था कि मौजूदा कंट्रोलर कॉन्टेक्स्ट को स्थिर रूप से प्राप्त करने का कोई तरीका था, जैसे कि आप वर्तमान HttpContext को HttpContext.Current के साथ प्राप्त कर सकते हैं। दुर्भाग्य से, मुझे एक नहीं मिला। एक अन्य विचार IProductValidator पर एक अतिरिक्त विधि होगी जो "ModelStateWrapper" स्वीकार करेगा और सत्यापन त्रुटियों को वहां कॉपी करेगा। निर्भरता इंजेक्शन के रूप में उतना अच्छा नहीं है, लेकिन इसे बहुत आसानी से काम करना चाहिए। – PatrickSteele

उत्तर

2

मुझे लगता है कि आप चाहते हैं कि मॉडलस्टेट आपके मॉडल में किसी भी त्रुटि को इंजेक्ट करने के लिए पारित हो जाए? आईएमएचओ, मॉडलस्टेट जहां रहना चाहिए, और आप इसे सत्यापन त्रुटियां लाते हैं। यहां बताया गया है कि मैं त्रुटियों को उदाहरण के रूप में कैसे संभालता हूं। मैं यह नहीं कह रहा हूं कि यह सबसे अच्छा तरीका है या एकमात्र तरीका है, लेकिन यह एक तरीका है जहां आपकी सत्यापन परत को यह जानने की आवश्यकता नहीं है कि कौन सी या सत्यापन त्रुटियों का उपभोग करता है।

सबसे पहले, मेरे पॉको में, मैं सत्यापन नियमों के लिए 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 
} 

और अंत में, जैसा कि आप देख सकते हैं, मेरी सत्यापन नियम नियम अपवाद को फेंकता है। यह वर्ग सभी त्रुटियों के लिए एक रैपर है।

[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); 
     } 
    } 

इस तरह, मैं अभी भी अपने सेवाओं/खजाने के लिए डि उपयोग करते हैं, और उन्हें एक त्रुटि ऊपर फेंक कि मेरा मॉडल अमान्य है दे सकते हैं। फिर मैंने सामने वाला अंत दिया - चाहे वह एक एमवीसी ऐप, वेब सेवा, या विंडोज ऐप है - तय करें कि उन त्रुटियों के साथ क्या करना है।

मुझे लगता है कि एमवीसी नियंत्रक/मॉडल/मॉडल/सेवाओं/भंडार/आदि में वापस राज्य को इंजेक्शन करना परतों के बीच मूल अलगाव का उल्लंघन है।

+0

मेरे लिए अच्छा लग रहा है! सुनिश्चित नहीं है कि आपके नियम अपवाद वर्ग क्यों serialiazable है? क्या आप कृपया समझा सकते हैं? – Haroon

+0

मैंने इसे धारावाहिक बना दिया है, इसलिए नियमों को अपवादित किया जा सकता है और एक वेब सेवा के माध्यम से मेरे कोड को कॉल करने वाले ऐप में प्रस्तुत किया जा सकता है। – Josh

संबंधित मुद्दे