2009-12-22 16 views
23

के साथ निर्भरता इंजेक्शन क्या Windows PowerShell के साथ निर्भरता इंजेक्शन (DI) का उपयोग करना संभव है?PowerShell

मेरे प्रारंभिक प्रयोगों से पता चलता है कि यह नहीं है। अगर मैं कन्स्ट्रक्टर इंजेक्शन को सीएमडीएलट में उपयोग करने का प्रयास करता हूं तो यह खुद को पंजीकृत भी नहीं करता है। दूसरे शब्दों में, यह संभव नहीं है:

[Cmdlet(VerbsDiagnostic.Test, "Ploeh")] 
public class PloehCmdlet : Cmdlet 
{ 
    public PloehCmdlet(IFoo foo) 
    { 
     if (foo == null) 
     { 
      throw new ArgumentNullException("foo"); 
     } 

     // save foo for later use 
    } 

    protected override void ProcessRecord() 
    { 
     this.WriteObject("Ploeh"); 
    } 
} 

अगर मैं एक डिफ़ॉल्ट निर्माता जोड़ने के लिए, cmdlet पंजीकृत है और इस्तेमाल किया जा सकता, लेकिन डिफ़ॉल्ट निर्माता के बिना, यह बस उपलब्ध नहीं है।

मैं मैं अपने निर्भरता प्राप्त करने के लिए सेवा लोकेटर इस्तेमाल कर सकते हैं पता है, लेकिन मैं विचार है कि एक विरोधी पैटर्न ताकि रास्ते जाने के लिए नहीं करना चाहती।

मुझे उम्मीद थी कि पावरशेल एपीआई के पास डब्ल्यूसीएफ की सर्विसहोस्ट फैक्ट्री के समान कुछ 'फैक्ट्री' हुक था, लेकिन यदि ऐसा है, तो मुझे यह नहीं मिल रहा है।

+0

मैं भी उत्सुक हूँ। –

+1

मुझे इसके लिए एक अच्छा उपयोग केस के साथ आने में मुश्किल हो रही है। – yfeldblum

+0

मैं एक सेवा लोकेटर का उपयोग कर रहा हूँ। :) –

उत्तर

10

पावरशेल में cmdlet का उपयोग हर बार एक खाली कन्स्ट्रक्टर से cmdlet वर्ग का एक उदाहरण बनाया जाता है। आपके पास कोई नियंत्रण नहीं है कि कौन सा कन्स्ट्रक्टर पावरशेल उठाएगा, इसलिए आप जो भी कर रहे हैं वह सीधे नहीं कर सकते हैं (और मुझे वास्तव में यह समझने में कठिनाई होती है कि आप क्यों चाहते हैं)। तो इस सवाल का सरल जवाब नहीं है।

इसी तरह के प्रभाव को प्राप्त करने के लिए, आप एक इंटरफ़ेस बना सकते हैं जो एक cmdlet (BeginProcessing/EndProcessing/ProcessRecord/StopProcessing) जैसा दिखता है और वास्तविक कोड पर पतले रैपर वाले cmdlets के समूह को पॉप्युलेट करने के लिए उपयोग करता है। आईएमएचओ यह एक जटिल दृष्टिकोण होगा।

मैं वास्तव में नहीं देखता कि आप ऐसा करने का प्रयास क्यों कर रहे हैं। क्या आप परिदृश्य के बारे में कुछ और बता सकते हैं?

+12

टेस्टेबिलिटी मेरा मुख्य कारण होगा, लेकिन डीआई का उपयोग करने का कोई भी कारण सीएमडीलेट्स पर समान रूप से लागू होता है - वे मेरे बाकी कोड से अलग क्यों होना चाहिए? –

3

बेस क्लास के रूप में पीएससीएमडलेट का उपयोग करने के लिए रनस्पेस को निष्पादित करने की आवश्यकता होती है और केवल आपको स्ट्रिंग के रूप में निष्पादित करने के लिए कमांड निर्दिष्ट करने देता है। उदाहरण के लिए this link देखें।

मैंने बेस क्लास के रूप में सीएमडीलेट पर वापस स्विच किया और निर्भरता निर्धारित करने के लिए प्रॉपर्टी इंजेक्शन का उपयोग किया। सबसे साफ समाधान नहीं, लेकिन यह मेरे लिए काम किया।

 var cmdlet = new MyCmdlet { 
          Dependency = myMockDependencyObject 
         }; 

     var result = cmdlet.Invoke().GetEnumerator(); 

     Assert.IsTrue(result.MoveNext()); 
+1

हाँ मैं इसके बारे में सोच रहा था लेकिन मैं सीएमडीलेट के उपयोग से बचने की कोशिश कर रहा हूं, मैं पावरहेल के वर्तमान सत्र स्थिति का उपयोग कर रहा हूं। तो यह मेरे लिए एक विकल्प नहीं है :( –

2

प्रारंभ-स्वचालित जवाब पर विस्तार करने के लिए:: एक आधार वर्ग के रूप में cmdlet के बारे में अच्छी बात यह है कि आप इसे इस तरह से इकाई परीक्षण से सीधे आह्वान कर सकते हैं है

अनिवार्य रूप से आप अपने IVIEW इंटरफेस होगा PSCmdlet (WriteObject, WriteError, WriteProgress, और इसी तरह के लिए) के संचालन को परिभाषित करेगा, आपके पास उस दृश्य का कार्यान्वयन होगा जो वास्तविक कमांडलेट होगा।

इसके अलावा आपके पास एक नियंत्रक होगा, जो वास्तविक कार्यशीलता है। कन्स्ट्रक्टर पर नियंत्रक को एक आईप्रोवाइडर प्राप्त होता है (जिसे आप नकल करना चाहते हैं) और एक IView। प्रदाता प्रदाता को कॉल करता है और IView के परिणामों को लिखता है, जो IView (पावरहेल कमांडलेट) पर प्रतिबिंबित होगा।

व्यू के आरंभ के दौरान आप एक नियंत्रक बनाएंगे, स्वयं के साथ (IView) और एक प्रदाता पास करेंगे, और फिर यह नियंत्रक के खिलाफ ऑपरेशन करेगा।

इस दृष्टिकोण के साथ आपका सीएमडीलेट एक पतली परत है जो किसी भी व्यावसायिक तर्क नहीं करती है, और सबकुछ आपके नियंत्रक पर है, जो एक घटक है जो परीक्षण योग्य है।

0

हालांकि आप इसके लिए कन्स्ट्रक्टर इंजेक्शन का उपयोग नहीं कर सकते हैं, आप स्वयं cmdlet का उपयोग कर सकते हैं। प्रारंभ करने के लिए एक पैरामीटर सेट पर इसे पहली बार कॉल करें, वर्तमान सत्र स्थिति में प्रासंगिक जानकारी संग्रहीत करें, और बाद की कॉल संग्रहित मान को सत्र स्थिति से वापस खींचें।

यहां मैंने संग्रहीत मूल्य का प्रतिनिधित्व करने के लिए एक एकल स्ट्रिंग, message का उपयोग किया है; लेकिन जाहिर है कि आप जितने चाहें उतने पैरामीटर/कई पैरामीटर प्राप्त कर सकते हैं।

एनबी: नीचे सी # पावरशेल में लपेटा गया है, ताकि आप पीएस में पूरी चीज का परीक्षण कर सकें।

$cs = @' 
using System.Management.Automation; 

[Cmdlet(VerbsDiagnostic.Test, "Ploeh", DefaultParameterSetName = "None")] 
public class PloehCmdlet : PSCmdlet 
{ 
    const string InitialiseParameterSetName = "Initialise"; 
    const string MessageVariable = "Test_Ploeh_Message_39fbe50c_25fc_48b1_8348_d155cad99e93"; //since this is held as a variable in the session state, make sure the name will not clash with any existing variables 

    [Parameter(Mandatory=true, ParameterSetName = InitialiseParameterSetName)] 
    public string InitialiseMessage 
    { 
     set { SaveMessageToSessionState(value); } 
    } 

    protected override void ProcessRecord() 
    { 
     if (this.ParameterSetName != InitialiseParameterSetName) //do not run the cmdlet if we're just initialising it 
     { 
      this.WriteObject(GetMessageFromSessionState()); 
      base.ProcessRecord(); 
     } 
    } 

    void SaveMessageToSessionState(string message) 
    { 
     this.SessionState.PSVariable.Set(MessageVariable, message); 
    } 
    string GetMessageFromSessionState() 
    { 
     return (string)this.SessionState.PSVariable.GetValue(MessageVariable); 
    } 

} 
'@ 
#Trick courtesy of: http://community.idera.com/powershell/powertips/b/tips/posts/compiling-binary-cmdlets 
$DLLPath = Join-Path $env:temp ('CSharpPSCmdLet{0:yyyyMMddHHmmssffff}.dll' -f (Get-Date)) 
Add-Type -OutputAssembly $DLLPath -Language 'CSharp' -ReferencedAssemblies 'System.Management.Automation.dll' -TypeDefinition $cs 
Import-Module -Name $DLLPath -Force -Verbose 

#demo commands 

Test-Ploeh -InitialiseMessage 'this is a test' 
Test-Ploeh 
Test-Ploeh 

Test-Ploeh -InitialiseMessage 'change value' 
Test-Ploeh 
Test-Ploeh 

"NB: Beware, your value can be accessed/amended outside of your cmdlet: $Test_Ploeh_Message_39fbe50c_25fc_48b1_8348_d155cad99e93" 
$Test_Ploeh_Message_39fbe50c_25fc_48b1_8348_d155cad99e93 = "I've changed my mind" 
Test-Ploeh 

उदाहरण आउटपुट

VERBOSE: Loading module from path 'C:\Users\UserNa~1\AppData\Local\Temp\CSharpPSCmdLet201711132257130536.dll'. 
VERBOSE: Importing cmdlet 'Test-Ploeh'. 
this is a test 
this is a test 
change value 
change value 
NB: Beware, your value can be accessed/amended outside of your cmdlet: change value 
I've changed my mind