using System.Threading.Tasks;
private static async Task Main()
var uowDirect = new UnitOfWork(false);
await uowDirect.CompleteAsync();
Console.WriteLine("Fake transaction for UnitOfWork direct: " + uowDirect.FakeTransaction.Value);
UnitOfWork? uowECRun = new UnitOfWork(true);
Console.WriteLine("Fake transaction for UnitOfWork EC.Run(): " + uowECRun.FakeTransaction.Value);
await uowECRun.CompleteAsync();
Console.WriteLine("Fake transaction for UnitOfWork EC.Run(): " + uowECRun.FakeTransaction.Value);
public class UnitOfWork : IAsyncDisposable
private ExecutionContext executionContext = null!;
public readonly AsyncLocal<string> FakeTransaction = new();
private void UpdateExecutionContext() => this.executionContext = ExecutionContext.Capture()!;
public UnitOfWork(bool useCapturedExecutionContext)
if (useCapturedExecutionContext)
ExecutionContext.Run(ExecutionContext.Capture()!, init, null);
this.FakeTransaction.Value = "Created";
this.UpdateExecutionContext();
public async Task CompleteAsync()
ExecutionContext.Restore(this.executionContext);
if (this.FakeTransaction.Value != "Created")
throw new InvalidOperationException($"Expected 'Created', got: '{this.FakeTransaction.Value}'");
this.FakeTransaction.Value = "Did some work";
this.UpdateExecutionContext();
public async ValueTask DisposeAsync()
ExecutionContext.Restore(this.executionContext);
if (this.FakeTransaction.Value != "Did some work")
throw new InvalidOperationException($"Expected 'Did some work', got: '{this.FakeTransaction.Value}'");
this.FakeTransaction.Value = "Committed";
this.UpdateExecutionContext();