Add async support for ProductAdapters #527
Replies: 3 comments
-
Hey @benmurphycb Yea, unfortunately Umbraco Commerce's API's are mostly all synchronous so don't have async alternatives. It's actually something we've been discussing internally recently as I think it's probably about time we tackle this once v14 is out the door. It's just discussions at the moment though so we don't have a timeframe for this yet. It's pretty ugly and not ideal, but here is the code for an AsyncHelper we use internally at the moment to be able to run an async method inside a sync method. Maybe it could be of use to you for the time being. internal static class AsyncHelper
{
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;
}
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);
}
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 exception
{
throw new AggregateException("AsyncHelper.RunSync method threw an exception.", InnerException);
}
}
else
{
workItemsWaiting.WaitOne();
}
}
}
public override SynchronizationContext CreateCopy()
=> this;
}
} |
Beta Was this translation helpful? Give feedback.
-
Hey Matt, cheers for the update and I will keep an eye on the release notes for updates. |
Beta Was this translation helpful? Give feedback.
-
Umbraco Commerce v15 is now fully async |
Beta Was this translation helpful? Give feedback.
-
Hello, I am working with Umbraco Commerce and need to implement a custom
ProductAdapter
.Inside the custom product adapter I need to call some async code and have come across the age old issue - the
GetProductSnapshot(...)
method that I need to override is not async.Currently I am faced with trying to work around this and call the async code in a synchronous way.
I was wondering if there is a to get around this and make the method async? Or if there is a plan to provide a
ProductAdapterBase
with async methods to override?Beta Was this translation helpful? Give feedback.
All reactions