2010-06-30 14 views
5

का उपयोग कर रहा है मेरी Global.aspx में निम्न कोडबेस नियंत्रक में संपत्ति इंजेक्शन Ninject 2

protected override void OnApplicationStarted() 
{ 
    AreaRegistration.RegisterAllAreas(); 
    RegisterRoutes(RouteTable.Routes); 
    RegisterAllControllersIn(Assembly.GetExecutingAssembly()); 
} 

protected override IKernel CreateKernel() 
{ 
    return new StandardKernel(new ServiceModule()); 
} 

मैं भी निम्नलिखित Ninject मॉड्यूल है:

internal class ServiceModule : NinjectModule 
{ 
    public override void Load() 
    { 
     Bind<IProductService>().To<ProductService>().InRequestScope(); 
    } 
} 

मैं भी एक आधार नियंत्रक है:

public class BaseController : Controller 
{ 
    [Inject] 
    public IProductService ProductService 
    { 
     get; 
     set; 
    } 
} 

यह कोड काम करता है। मेरी समस्या यह है कि मैं आधार नियंत्रक से इंजेक्ट विशेषता को हटाना चाहता हूं और इसे इसके बजाय Ninject ServiceModule में निर्दिष्ट करना चाहता हूं। मैं दूसरे शब्दों में, सेवामैप्यूल में बाध्यकारी नियम लिखने के बारे में कैसे जाउंगा जो निनजेक्ट को बेस नियंत्रक में संपत्ति में उत्पाद सेवा को इंजेक्ट करने के लिए कहता है?

यदि मैं विशेषता को हटा देता हूं तो मुझे एक NullReferenceException मिलेगा।

उत्तर

3

कन्वेंशन-आधारित बाध्यकारी जीवन http://github.com/ninject/ninject.extensions.conventions में - एक IBindingGenerator लागू करता है। हालांकि यह मुख्य रूप से इंटरफेस और सेवाओं की खोज के साथ चिंतित है।

सामान्य रूप से, कन्स्ट्रक्टर इंजेक्शन एक अच्छा डिफ़ॉल्ट दृष्टिकोण है। हालांकि जिस तरीके से एएसपी.नेट एमवीसी काम करता है, यह करना कठिन होता है (इसलिए FubuMVC आदि)। तो संपत्ति इंजेक्शन अगले सबसे अच्छा विकल्प है।

आप पाते हैं कि OnActivation का उपयोग Bind में आपको पर्याप्त करने की अनुमति दे सकता है - और यदि आप कर सकते हैं, तो यह सबसे सरल है।

मैं विशेषता करता हूं कि आप परंपरा-आधारित सक्रियण के रूप में क्या करने की कोशिश कर रहे हैं। समस्या यह है:

  • यह तय करना कि आप ऑटो-इंजेक्ट करने जा रहे हैं। क्या आप उन सब कुछ इंजेक्ट करने जा रहे हैं जो ठोस नहीं हैं? सब कुछ जो आपके कर्नेल के बारे में जानता है? जब तक आप जो करना चाहते हैं उसकी एक साफ परिभाषा के साथ नहीं आ सकते हैं, इंजेक्शन प्रक्रिया अप्रत्याशित और समझने में मुश्किल हो सकती है। आप डिबगिंग समाप्त करते हैं और सहकर्मियों को समझाते हैं।

  • इसे कुशल बनाते हैं। निनजेक गतिशील रूप से दृश्यों के पीछे कोड उत्पन्न करता है ताकि एक उदाहरण कुशल को सक्रिय किया जा सके (यानी, [Inject] मार्करों की तलाश में कक्षा चलाने के समय यह एक बार कोड उत्पन्न करता है जो तब होता है जैसे कि आप इसे लंबे समय से लिखते हैं)।

कोड में देख रहे हैं, ओओटीबी का कोई आसान तरीका नहीं है। ऐसा लगता है कि कस्टम IInjectionHeuristic जोड़ने से चाल चलती है।

लेकिन यदि आप कंटेनरों में गहरी इस हो रही है, आप के लिए

  1. ठहराव की जरूरत है और देखते हैं कि यह सड़क
  2. Ninject मेलिंग सूची और खोज करने के लिए जाने के लिए नीचे नहीं जा रहा द्वारा यदि आप इसे सरल रखने कर सकते हैं इसी तरह की चीजों के लिए
  3. यदि आप अभी भी ऐसा करना चाहते हैं, तो वहां एक मेल भेजें।
+0

रुबेन, क्या आप प्रदान कर सकते हैं और उदाहरण के लिए मैं सेवा मॉड्यूल में बाध्यकारी नियम लिखने के बारे में कैसे कहूंगा जो निनजेक्ट को बेस नियंत्रक में संपत्ति में उत्पाद सेवा को इंजेक्ट करने के लिए कहता है? धन्यवाद! – Thomas

+0

@ थॉमस: मैंने कभी भी उस प्रकृति का अनुकूलन नहीं किया है (और जैसा कि मुझे विश्वास नहीं है कि यह एक अच्छा दृष्टिकोण है, इसकी कोई इच्छा नहीं है), दुर्भाग्य से ऐसा करने में समय नहीं लगेगा - क्षमा करें ... (और जैसा मेरा जवाब अब तक मूल्य-कम होने का अनुमान लगाया गया है, मैं ऐसा क्यों करूं - ऐसा नहीं है कि मेरे पास कोई प्रतिक्रिया है कि मेरा उत्तर समझा गया है या सही है?) –

2

रुबेन बार्टेलिंक द्वारा विचारों पर विस्तार से आप IInjectionHeuristic का एक कस्टम कार्यान्वयन कर सकते हैं।

public class ControllerInjectionHeuristic : NinjectComponent, IInjectionHeuristic 
{ 
    private readonly IKernel kernel; 

    public BaseControllerInjectionHeuristic(IKernel kernel) 
    { 
     this.kernel = kernel; 
    } 

    public bool ShouldInject(MemberInfo member) 
    { 
     if (member.ReflectedType != typeof(BaseController)) 
     { 
      return false; 
     } 

     var propertyInfo = member.ReflectedType.GetProperty(member.Name); 
     object service = kernel.TryGet(propertyInfo.PropertyType); 

     return service != null; 
    } 
} 

ControllerInjectionHeuristicBaseController पर किसी भी संपत्ति (सेवा) इंजेक्षन जाएगा जिसके लिए कर्नेल सेवा को हल करने में सक्षम है।

कर्नेल के साथ कस्टम कार्यान्वयन पंजीकृत करें।

var kernel = new StandardKernel(); 
kernel.Components.Add<IInjectionHeuristic, ControllerInjectionHeuristic>(); 

समस्या का एक और समाधान OnActivation का उपयोग करना है। (यह समाधान एक अवांछित है, लेकिन यह आपको आगे बढ़ने के बारे में एक विचार देना चाहिए)।

public class ControllerModule : NinjectModule 
{ 
    public override void Load() 
    { 
     // Get all controller types. You could use 
     // Ninject.Extensions.Conventions. 
     IEnumerable<Type> controllerTypes = null; 
     foreach (var controllerType in controllerTypes) 
     { 
      Bind(controllerType).ToSelf().InRequestScope() 
       .OnActivation(ControllerActivation); 
     } 
    } 

    private static void ControllerActivation(IContext context, object obj) 
    { 
     var controller = obj as BaseController; 
     if (controller == null) 
     { 
      return; 
     } 

     controller.ProductService = context.Kernel.Get<IProductService>(); 
    } 
} 
+0

+1 अच्छा काम मेरे जैसे जुआ खेलने के बजाय नमूना प्रदान करना ! सुनिश्चित नहीं है कि जिस तरह से आप कनवर्ट करते हैं, queryInfo से PropertyInfo को सही है, हालांकि शायद आपको 'is' /' as' का उपयोग करना चाहिए? साथ ही, 'TryGet' एक पूर्ण ऑब्जेक्ट बिल्डअप करेगा जो आप को हटा देंगे। आप एक CanResolve ऑपरेशन चाहते हैं (कि मैं इस नाम के बारे में सोच नहीं सकता)। इस उदाहरण में मैं पहली नज़र में विश्वास करता हूं कि यह ठीक है, लेकिन मैं व्यक्तिगत रूप से 'आरफलेक्टेड टाइप' के लिए एमएसडीएन दस्तावेज़ों पर कुछ मिनट बिताता हूं, यह पता लगाने के लिए कि क्या यह ** बिल्कुल ** मेरा मतलब है। –

+0

मैंने सोचा कि यह कुछ सीखने का एक अच्छा मौका होगा। कारण मैं 'var propertyInfo = member.ReflectedType.GetProperty (सदस्य नाम); 'क्योंकि, मेरी परीक्षा प्रोजेक्ट में,' सदस्य 'एक' RuntimePropertyInfo' 'बन गया, जो एक आंतरिक वर्ग है। तो मैं बस अगली सबसे अच्छी चीज के साथ भाग गया जो सोच सकता था। मैंने 'kernel.CanResolve (IRequest) 'के बजाय' kernel.ryService (टाइप) 'चुना है क्योंकि यह एक पूर्ण अनुरोध बनाने से कम सरल था। हालांकि, मुझे लगता है कि 'नियंत्रक इंजेक्टर ह्यूरिस्टिक' बहुत अच्छा प्रदर्शन नहीं करेगा। यह निश्चित रूप से _production-ready_ नहीं है। – mrydengren

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