The actual work should be performed in another method. Prepare and Commit are there to implement a 2-phase commit mechanism.
The pattern is as follows:
using(var transaction = new TransactionScope())
{
var rc1 = new ResourceManager();
rc1.DoWork();
var rc2 = new ResourceManager();
rc2.DoWork();
transaction.Complete();
}
In this example the DoWork should execute the action.
When exiting the transaction scope, the Prepare method of both resource managers will be called.
If they both called enlistment.Prepared();
then the Commit methods of both managers will be called. That commit should never fail!
For example, when working with files, DoWork should rename the file to indicate you are processing it, and then read and process the file. If either action fails, it should throw an exception causing the Rollback to be called. Rollback should rename the file back to its original name. Prepare could rename the file to indicate it should be deleted and check whether it is allowed to delete the file. If either action fails, it should throw an exception. Commit would then actually delete the file. This will not fail because we already checked the security, but even if it does, it should not throw an exception.
You could actually delete the file in the Prepare method and call enlistment.Done();
. This would indicate that the call to Commit is not needed anymore. But the problem with that is that after you deleted the file, the other resource manager could throw an exception in its Prepare. Because you indicated you were Done, your rollback method will not be called. And even if is was called, there would be no way for you to recover your action...
I hope this explains things a bit...