Created
July 9, 2017 18:43
-
-
Save devlead/a5cb537a7b3dd4d78047bc043d695df1 to your computer and use it in GitHub Desktop.
Sample of using async await in a cake script using a AsyncHelper class to work with all async scenarios, currently needs "--Experimental" flag or to use the Cake.CoreCLR runner as a newer version of Roslyn is required for async to be recognized. Example invocation: cake .\AsyncHelper.cake -Experimental
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
#load "AsyncHelper.cake" | |
#r "System.Net.Http" | |
using System.Net.Http; | |
using System.Net.Http.Headers; | |
string url = "https://icanhazdadjoke.com/"; | |
var result = AsyncHelpers.RunSync( | |
async ()=> { | |
using(var client = new HttpClient()) | |
{ | |
client.DefaultRequestHeaders | |
.Accept | |
.Add(new MediaTypeWithQualityHeaderValue("text/plain")); | |
using(var r = await client.GetAsync(new Uri(url))) | |
{ | |
string result = await r.Content.ReadAsStringAsync(); | |
return result; | |
} | |
} | |
} | |
); | |
Information(result); |
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.Generic; | |
using System.Threading; | |
using System.Threading.Tasks; | |
public static class AsyncHelpers | |
{ | |
/// <summary> | |
/// Execute's an async Task<T> method which has a void return value synchronously | |
/// </summary> | |
/// <param name="task">Task<T> method to execute</param> | |
public static void RunSync(Func<Task> task) | |
{ | |
var oldContext = SynchronizationContext.Current; | |
var synch = new ExclusiveSynchronizationContext(); | |
SynchronizationContext.SetSynchronizationContext(synch); | |
synch.Post(async _ => | |
{ | |
try | |
{ | |
await task(); | |
} | |
catch (Exception e) | |
{ | |
synch.InnerException = e; | |
throw; | |
} | |
finally | |
{ | |
synch.EndMessageLoop(); | |
} | |
}, null); | |
synch.BeginMessageLoop(); | |
SynchronizationContext.SetSynchronizationContext(oldContext); | |
} | |
/// <summary> | |
/// Execute's an async Task<T> method which has a T return type synchronously | |
/// </summary> | |
/// <typeparam name="T">Return Type</typeparam> | |
/// <param name="task">Task<T> method to execute</param> | |
/// <returns></returns> | |
public static T RunSync<T>(Func<Task<T>> task) | |
{ | |
var oldContext = SynchronizationContext.Current; | |
var synch = new ExclusiveSynchronizationContext(); | |
SynchronizationContext.SetSynchronizationContext(synch); | |
T ret = default(T); | |
synch.Post(async _ => | |
{ | |
try | |
{ | |
ret = await task(); | |
} | |
catch (Exception e) | |
{ | |
synch.InnerException = e; | |
throw; | |
} | |
finally | |
{ | |
synch.EndMessageLoop(); | |
} | |
}, null); | |
synch.BeginMessageLoop(); | |
SynchronizationContext.SetSynchronizationContext(oldContext); | |
return ret; | |
} | |
private class ExclusiveSynchronizationContext : SynchronizationContext | |
{ | |
private bool done; | |
public Exception InnerException { get; set; } | |
readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false); | |
readonly Queue<Tuple<SendOrPostCallback, object>> items = | |
new Queue<Tuple<SendOrPostCallback, object>>(); | |
public override void Send(SendOrPostCallback d, object state) | |
{ | |
throw new NotSupportedException("We cannot send to our same thread"); | |
} | |
public override void Post(SendOrPostCallback d, object state) | |
{ | |
lock (items) | |
{ | |
items.Enqueue(Tuple.Create(d, state)); | |
} | |
workItemsWaiting.Set(); | |
} | |
public void EndMessageLoop() | |
{ | |
Post(_ => done = true, null); | |
} | |
public void BeginMessageLoop() | |
{ | |
while (!done) | |
{ | |
Tuple<SendOrPostCallback, object> task = null; | |
lock (items) | |
{ | |
if (items.Count > 0) | |
{ | |
task = items.Dequeue(); | |
} | |
} | |
if (task != null) | |
{ | |
task.Item1(task.Item2); | |
if (InnerException != null) // the method threw an exeption | |
{ | |
throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException); | |
} | |
} | |
else | |
{ | |
workItemsWaiting.WaitOne(); | |
} | |
} | |
} | |
public override SynchronizationContext CreateCopy() | |
{ | |
return this; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment