A base class that enables to use async/await (cf http://sunnyone41.blogspot.jp/2014/06/pscmdletasyncawait.html)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Concurrent; | |
using System.Management.Automation; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace AwaitablePSCmdlet | |
{ | |
public class AwaitablePSCmdlet : PSCmdlet | |
{ | |
private class PSSynchronizationContextItem | |
{ | |
public SendOrPostCallback Callback { get; private set; } | |
public object State { get; private set; } | |
public PSSynchronizationContextItem(SendOrPostCallback callback, object state) | |
{ | |
Callback = callback; | |
State = state; | |
} | |
} | |
private class PSSynchronizationContext : SynchronizationContext | |
{ | |
private readonly BlockingCollection<PSSynchronizationContextItem> queue = | |
new BlockingCollection<PSSynchronizationContextItem>(); | |
public override void Post(SendOrPostCallback d, object state) | |
{ | |
queue.Add(new PSSynchronizationContextItem(d, state)); | |
} | |
public void RunLoop() | |
{ | |
PSSynchronizationContextItem item; | |
while (queue.TryTake(out item, Timeout.Infinite)) | |
{ | |
if (item == null) | |
{ | |
break; | |
} | |
item.Callback(item.State); | |
} | |
} | |
public void Complete() | |
{ | |
// Null means break | |
queue.Add(null); | |
} | |
} | |
private void doWithSyncCtx(Func<Task> func) | |
{ | |
var prevCtx = SynchronizationContext.Current; | |
try | |
{ | |
SynchronizationContext.SetSynchronizationContext(psSyncCtx); | |
var task = func(); | |
task.ContinueWith(t => psSyncCtx.Complete(), TaskScheduler.Default); | |
psSyncCtx.RunLoop(); | |
task.GetAwaiter().GetResult(); | |
} | |
finally | |
{ | |
SynchronizationContext.SetSynchronizationContext(prevCtx); | |
} | |
} | |
private PSSynchronizationContext psSyncCtx = new PSSynchronizationContext(); | |
protected override void BeginProcessing() | |
{ | |
doWithSyncCtx(BeginProcessingAsync); | |
} | |
protected override void ProcessRecord() | |
{ | |
doWithSyncCtx(ProcessRecordAsync); | |
} | |
protected override void EndProcessing() | |
{ | |
doWithSyncCtx(EndProcessingAsync); | |
} | |
protected virtual Task ProcessRecordAsync() | |
{ | |
return Task.FromResult(true); | |
} | |
protected virtual Task BeginProcessingAsync() | |
{ | |
return Task.FromResult(true); | |
} | |
protected virtual Task EndProcessingAsync() | |
{ | |
return Task.FromResult(true); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment