Why -- HOW -- are transactions processed after disposal?
c#, idisposable, transactionscope
Solution
This is self-inflicted pain. You violate a very basic rule for IDisposable, an object should only ever be disposed when it is no longer in use anywhere else. It is in use when your using statement calls Dispose(), you handed a reference to your object in the WtfTransactionScope constructor. You cannot dispose it until it is done with it, that necessarily means you have to dispose it after the using statement for the TransactionScope completes and the transaction got committed/rolled-back.
I'll let you fret about making it pretty, but an obvious way is:
using(var wtf = new WtfTransactionScope())
using(var scope = new TransactionScope())
{
wtf.Initialize();
scope.Complete();
}
The `Prepare completed` is merely an unhelpful debug statement. Just delete it.
Problem
I'm trying to work with some ambient transaction scopes (thanks, entity-framework), which I haven't really done before, and I'm seeing some ... odd behavior that I'm trying to understand. I'm trying to enlist in the current transaction scope and do some work after it completes successfully. My enlistment participant implements `IDisposable` due to some resources it holds. I've got a simple example that exhibits the strange behavior. For this class, ``` class WtfTransactionScope : IDisposable, IEnlistmentNotification { public WtfTransactionScope() { if(Transaction.Current == null) return; Transaction.Current.EnlistVolatile(this, EnlistmentOptions.None); } void IEnlistmentNotification.Commit(Enlistment enlistment) { enlistment.Done(); Console.WriteLine("Committed"); } void IEnlistmentNotification.InDoubt(Enlistment enlistment) { enlistment.Done(); Console.WriteLine("InDoubt"); } void IEnlistmentNotification.Prepare( PreparingEnlistment preparingEnlistment) { Console.WriteLine("Prepare called"); preparingEnlistment.Prepared(); Console.WriteLine("Prepare completed"); } void IEnlistmentNotification.Rollback(Enlistment enlistment) { enlistment.Done(); Console.WriteLine("Rolled back"); } public void Dispose() { Console.WriteLine("Disposed"); } } ``` when used as illustrated here ``` using(var scope = new TransactionScope()) using(new WtfTransactionScope()) { scope.Complete(); } ``` the console output demonstrates the wtf-ness: Disposed Prepare called Committed Prepare completed wut. I'm getting disposed before the transaction completes. This... kind of negates the benefits of hanging with the transaction scope. I was hoping that I'd be informed once the transaction completes successfully (or not) so I could do some work. I was unfortunately assuming that this would happen after `scope.Complete()` and before I get disposed as we move out of the `using` scope. This apparently is not the case. Of course, I could hack it. But I've got other issues which essentially prevent me from doing this. I'll have to scrap and do something else in this eventuality. Am I doing something wrong here? Or is this expected behavior? Can something be done differently to prevent this from happening??