source

PowerShell을 사용한 종속성 주입

nicesource 2023. 8. 22. 22:13
반응형

PowerShell을 사용한 종속성 주입

Windows PowerShell에서 DI(의존성 주입)를 사용할 수 있습니까?

제 초기 실험은 그렇지 않다는 것을 시사합니다.CmdLet에서 Constructor Injection을 사용하려고 하면 자체 등록조차 되지 않습니다.다시 말해, 이것은 불가능합니다.

[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을 등록하여 사용할 수 있지만 기본 생성자가 없으면 사용할 수 없습니다.

서비스 로케이터를 사용하여 종속성을 검색할 수 있다는 것을 알고 있습니다. 하지만 안티패턴이라고 생각하기 때문에 그런 식으로 가고 싶지는 않습니다.

PowerShell API에 WCF의 ServiceHostFactory와 유사한 'Factory' 후크가 있었으면 좋았을 텐데, 있다면 찾을 수 없습니다.

cmdlet 클래스의 인스턴스는 PowerShell에서 cmdlet을 사용할 때마다 빈 생성자에서 생성됩니다.PowerShell이 어떤 생성자를 선택할지 제어할 수 없기 때문에 제안하는 것을 직접적으로 수행할 수 없습니다(그리고 저는 당신이 왜 그렇게 하고 싶어하는지 상상하기가 정말 어렵습니다).그래서 이 질문에 대한 간단한 대답은 아니오입니다.

비슷한 효과를 얻기 위해 cmdlet 모양의 인터페이스(BeginProcessing/EndProcessing/ProcessRecord/StopProcessing 포함)를 만들고 실제 코드에 얇은 래퍼인 cmdlet 묶음을 채우는 데 사용할 수 있습니다.IMHO 이것은 너무 복잡한 접근 방식일 것입니다.

저는 당신이 왜 이것을 하려고 하는지 정말 이해할 수 없습니다.시나리오에 대해 좀 더 설명해 주시겠습니까?

PSCmdlet을 기본 클래스로 사용하려면 RunSpace를 실행해야 하며 문자열로 실행할 명령만 지정할 수 있습니다.예를 보려면 이 링크를 참조하십시오.

기본 클래스로 Cmdlet으로 다시 전환하고 Property injection을 사용하여 종속성을 설정했습니다.가장 깨끗한 해결책은 아니지만, 저에게는 효과가 있었습니다.기본 클래스로서의 Cmdlet의 좋은 점은 다음과 같이 유닛 테스트에서 직접 호출할 수 있다는 것입니다.

        var cmdlet = new MyCmdlet {
                             Dependency = myMockDependencyObject
                         };

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

        Assert.IsTrue(result.MoveNext());

자동화 시작 시 확장하기

기본적으로 PSCmdlet(WriteObject, WriteError, WriteProgress 등)에 대한 작업을 정의하는 IV View 인터페이스가 있으며, 이를 통해 실제 Commandlet이 되는 View를 구현할 수 있습니다.

또한 실제 기능인 컨트롤러도 사용할 수 있습니다.생성자에서 컨트롤러는 IP 제공자(모킹하려는 IP 제공자)와 IV 보기를 수신합니다.공급자가 공급자에게 호출을 수행하고 결과를 IView에 기록합니다. IView(Powershell Commandlet)에 반영됩니다.

보기를 초기화하는 동안 컨트롤러를 생성하고 자체(IView) 및 공급자를 전달한 다음 컨트롤러에 대한 작업을 수행합니다.

이 접근 방식을 사용하면 Cmdlet은 비즈니스 로직을 수행하지 않는 얇은 계층이며 모든 것이 컨트롤러에 있으며 이는 테스트 가능한 구성 요소입니다.

여기에는 생성자 주입을 사용할 수 없지만 cmdlet 자체를 사용할 수 있습니다.초기화하도록 설정된 하나의 매개 변수에 대해 첫 번째 호출을 하고, 관련 정보를 현재 세션 상태로 저장한 다음, 이후 호출을 통해 저장된 값을 세션 상태에서 다시 가져오도록 합니다.

여서저는끈하사용다니습했나를기,▁string▁single다▁a라는 단일 문자열을 사용했습니다.message저장된 값을 나타내지만 원하는 유형의 매개 변수를 얼마든지 가질 수 있습니다.

NB: 아래의 C#은 PowerShell로 포장되어 있으므로 PS에서 직접 전체를 테스트할 수 있습니다.

$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

언급URL : https://stackoverflow.com/questions/1945572/dependency-injection-with-powershell

반응형