C# 从事件处理程序报告Powershell进度
我已经用C#编写了一个cmdlet,它充当重载/长时间运行的同步操作的包装器。该方法(其他人的代码)通过事件处理程序报告此长期运行操作期间的进度百分比,我想将其与powershell的标准C# 从事件处理程序报告Powershell进度,c#,.net,powershell,C#,.net,Powershell,我已经用C#编写了一个cmdlet,它充当重载/长时间运行的同步操作的包装器。该方法(其他人的代码)通过事件处理程序报告此长期运行操作期间的进度百分比,我想将其与powershell的标准WriteProgress方法挂钩,以获得打印精美的进度条。但是,我收到以下错误消息: 不能从BeginProcessing、ProcessRecord和EndProcessing方法重写之外调用WriteObject和WriteError方法,只能从同一线程内调用它们。 这是我的密码: overrride v
WriteProgress
方法挂钩,以获得打印精美的进度条。但是,我收到以下错误消息:
不能从BeginProcessing、ProcessRecord和EndProcessing方法重写之外调用WriteObject和WriteError方法,只能从同一线程内调用它们。
这是我的密码:
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()
相同的线程中?您需要手动将ProgressChanged
事件处理程序封送回PowerShell管道线程。这可以通过应用生产者-消费者模式来实现,其中ProgressChanged
事件处理程序将是生产者,PowerShell管道线程中的事件循环将是消费者。通过.NET Framework 4.0中引入的支持,可以轻松实现:
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();
}
override void ProcessRecord(){
任务长时间运行操作;
使用(BlockingCollection队列=新建BlockingCollection()){
//将LongRunning操作卸载到不同的线程,以保持对PowerShell管道线程的控制
longRunningOperation=任务。运行(()=>{
试一试{
//将EventHandler替换为ProgressChanged类型
事件处理程序=
//实现为匿名方法以捕获队列局部变量
(对象发送方,ProgressChangeEventArgs e)=>{
ProgressRecord progress=新的ProgressRecord(activityId:1,activity:“移动数据”,statusDescription:“当前操作”);
progress.PercentComplete=e.ProgressPercentage;
//用于在PowerShell管道线程中处理的队列ProgressRecord
添加(进度);
}
LongRunningOperation op=新的LongRunningOperation();
op.ProgressChanged+=处理程序;
op.Execute();
op.ProgressChanged-=处理程序;
}最后{
queue.CompleteAdding();
}
});
//事件循环
对于(;;){
进度记录进度;
if(!queue.TryTake(out progress,Timeout.Infinite)){
打破
}
写进度(进度);
}
}
//从LongRunningOperation获取任何异常
longRunningOperation.GetAwaiter().GetResult();
}
您确定op.ProgressChanged
与op.Execute()
调用的?@PetSerAl-Whelp在同一线程中引发,这似乎是(a?)问题。没想到op.Execute()会产生一些新线程。知道如何解决这个问题吗?您的目标是什么PowerShell和.NET版本?如果您向事件注册lambda/delegate而不是实例方法,PowerShell 3、.NET 4.5是否会产生影响?