c# - Volatile IEnlistmentNotification and TransactionScope.AsyncFlowEnabled = true -
apart .net 4.5.1 there new option on transactionscope enables use async flow. allows write following client code
using(var txt = new transactionscope(..., transactionscopeasyncflowoption.enabled) { await sender.sendasync(); }
so far good. when need implement volatile ienlistmentnotification i'm struggling that. let's imagine following scenario, assumption: underlying infrastructure async bottom top
public class messagesender : isendmessages { public async task sendasync(transportmessage message, sendoptions options) { await sender.sendasync(message); } }
so want achieve introduce volatile ienlistmentnotification this:
internal class sendresourcemanager : ienlistmentnotification { private readonly func<task> oncommit; public sendresourcemanager(func<task> oncommit) { this.oncommit = oncommit; } public void prepare(preparingenlistment preparingenlistment) { preparingenlistment.prepared(); } public void commit(enlistment enlistment) { await this.oncommit(); enlistment.done(); } public void rollback(enlistment enlistment) { enlistment.done(); } public void indoubt(enlistment enlistment) { enlistment.done(); } }
and new sender
public class messagesender : isendmessages { public async task sendasync(transportmessage message, sendoptions options) { // dirty: let's assume transaction.current never null transaction.current.enlistvolatile(new sendresourcemanager(async () => { await sender.sendasync(message) })); } }
note: of course code doesn't compile. require me declare commit method async void. aweful.
so question is: how can write enlistment can internally await asynchronous operation?
as long enlistvolatile
isn't heavy cpu bound time consuming operation, can create thin task
based wrapper on enlistvolatile
using task.fromresult
:
public static class transcationextensions { public static task enlistvolatileasync(this transaction transaction, ienlistmentnotification enlistmentnotification, enlistmentoptions enlistmentoptions) { return task.fromresult(transaction.enlistvolatile (enlistmentnotification, enlistmentoptions)); } }
and consume inside method:
public class messagesender : isendmessages { public task sendasync(transportmessage message, sendoptions options) { return transaction.current.enlistvolatileasync (new sendresourcemanager(async () => { await sender.sendasync(message) })); } }
which can awaited higher in callstack:
messagesender sender = new messagesender(); await sender.sendasync(message, options);
Comments
Post a Comment