public void Prepared() { if (State != TransactionSignalState.Ready) { ThrowInvalidAsyncResult("PrepareAsyncCompletion should only be called once per PrepareTransactionalCall."); } State = TransactionSignalState.Prepared; }
protected virtual void Dispose(bool disposing) { if (disposing && !_disposed) { _disposed = true; if (State == TransactionSignalState.Ready) { State = TransactionSignalState.Abandoned; } else if (State == TransactionSignalState.Prepared) { State = TransactionSignalState.Completed; } else { ThrowInvalidAsyncResult("PrepareTransactionalCall should only be called in a using. Dispose called multiple times."); } try { Fx.CompleteTransactionScope(ref _transactionScope); } catch (Exception exception) { if (Fx.IsFatal(exception)) { throw; } // Complete and Dispose are not expected to throw. If they do it can mess up the AsyncResult state machine. throw Fx.Exception.AsError(new InvalidOperationException(CommonResources.AsyncTransactionException)); } // This will release the callback to run, or tell us that we need to defer the callback to Check/SyncContinue. // // It's possible to avoid this Interlocked when CompletedSynchronously is true, but we have no way of knowing that // from here, and adding a way would add complexity to the AsyncResult transactional calling pattern. This // unnecessary Interlocked only happens when: PrepareTransactionalCall is called with a non-null transaction, // PrepareAsyncCompletion is reached, and the operation completes synchronously or with an exception. if (State == TransactionSignalState.Completed && Unlock(out IAsyncResult result)) { if (_parent._deferredTransactionalResult != null) { ThrowInvalidAsyncResult(_parent._deferredTransactionalResult); } _parent._deferredTransactionalResult = result; } } }