2016-07-15 6 views
1

무겁거나 장기간 실행되는 동기 작업에 대한 래퍼 역할을하는 C#에서 cmdlet을 작성했습니다. 이 방법 (다른 사람의 코드)은 이벤트 핸들러를 통해이 장기 실행 작업 동안 백분율 진행률을보고합니다.이 코드를 powershell의 표준 WriteProgress 메서드에 연결하여 예쁜 출력 진행률 표시 줄을 얻으려고합니다.보고 이벤트 핸들러에서 Powershell 진행

다음

The WriteObject and WriteError methods cannot be called from outside the overrides of the BeginProcessing, ProcessRecord, and EndProcessing methods, and they can only be called from within the same thread.

것은 내 코드 것 : 발견 할 수

overrride void ProcessRecord() 
{ 
    LongRunningOperation op = new LongRunningOperation(); 
    op.ProgressChanged += ProgressUpdate; 
    op.Execute(); 
    op.ProgressChanged -= ProgressUpdate; 
} 

void ProgressUpdate(object sender, ProgressChangeEventArgs e) 
{ 
    ProgressRecord progress = new ProgressRecord(activityId: 1, activity: "Moving data", statusDescription: "Current operation"); 
    progress.PercentComplete = e.ProgressPercentage; 
    WriteProgress(progress); 
} 

누구든지 무엇을 내가 잘못 그러나, 나는 다음과 같은 오류 메시지가 받고 있어요?

업데이트 : 이벤트 핸들러가 ProcessRecord()과 다른 스레드에서 트리거되는 것처럼 보입니다. 다시 필요한 정보를 ProcessRecord()과 동일한 스레드로 가져올 수 있습니까?

+1

당신은''op.Execute은()'라는 동일한 스레드에서 제기 op.ProgressChanged' 있는지 확인 있습니까? – PetSerAl

+0

@PetSerAl Whelp, 문제 (a?) 문제 인 것 같습니다. op.Execute()가 새로운 스레드를 회전시킬 것이라고 생각하지 않았습니다. 어떤 생각을 어떻게 해결할 수 있습니까? – Benjin

+0

어떤 PowerShell 및 .NET 버전을 타겟팅합니까? – PetSerAl

답변

0

ProgressChanged 이벤트 처리기를 PowerShell 파이프 라인 스레드로 수동으로 마샬링해야합니다. 생산자 - 소비자 패턴을 적용하여 수행 할 수 있습니다. ProgressChanged 이벤트 처리기는 생산자이고 PowerShell 파이프 라인 스레드의 이벤트 루프는 소비자가됩니다. 그것은 쉽게 .NET 프레임 워크 4.0에 도입 BlockingCollection<T>의 지원을 구현할 수 있습니다

overrride void ProcessRecord() { 
    Task longRunningOperation; 
    using(BlockingCollection<ProgressRecord> queue = new BlockingCollection<ProgressRecord>()) { 
     //offload LongRunningOperation to different thread to keep control on PowerShell pipeline thread 
     longRunningOperation=Task.Run(() => { 
      try { 
       //replace EventHandler<ProgressChangeEventArgs> with ProgressChanged type 
       EventHandler<ProgressChangeEventArgs> handler = 
        //implemented as anonymous method to capture queue local variable 
        (object sender, ProgressChangeEventArgs e) => { 
         ProgressRecord progress = new ProgressRecord(activityId: 1, activity: "Moving data", statusDescription: "Current operation"); 
         progress.PercentComplete = e.ProgressPercentage; 
         //queue ProgressRecord for processing in PowerShell pipeline thread 
         queue.Add(progress); 
        } 
       LongRunningOperation op = new LongRunningOperation(); 
       op.ProgressChanged += handler; 
       op.Execute(); 
       op.ProgressChanged -= handler; 
      } finally { 
       queue.CompleteAdding(); 
      } 
     }); 
     //event loop 
     for(;;) { 
      ProgressRecord progress; 
      if(!queue.TryTake(out progress, Timeout.Infinite)) { 
       break; 
      } 
      WriteProgress(progress); 
     } 
    } 
    //get any exception from LongRunningOperation 
    longRunningOperation.GetAwaiter().GetResult(); 
} 
관련 문제