Beispiel #1
0
        /// <summary>
        /// Create a Task based on Begin/End IAsyncResult pattern.
        /// </summary>
        /// <param name="transaction">The transaction (optional) to use.  If not null a TransactionScope will be used when calling the begin Func.</param>
        /// <param name="begin"></param>
        /// <param name="end"></param>
        /// <param name="state">
        /// This parameter helps reduce allocations by passing state to the Funcs. e.g.:
        ///  await TaskHelpers.CreateTask(
        ///      (c, s) => ((Transaction)s).BeginCommit(c, s),
        ///      (a) => ((Transaction)a.AsyncState).EndCommit(a),
        ///      transaction);
        /// </param>
        public static Task CreateTransactionalTask(Transaction transaction, Func <AsyncCallback, object, IAsyncResult> begin, Action <IAsyncResult> end, object state = null)
        {
            Task             retval;
            TransactionScope scope = null;

            try
            {
                scope  = Fx.CreateTransactionScope(transaction);
                retval = Task.Factory.FromAsync(begin, end, state);
                Fx.CompleteTransactionScope(ref scope);
            }
            catch (Exception ex)
            {
                if (Fx.IsFatal(ex))
                {
                    throw;
                }

                if (scope != null)
                {
                    scope.Dispose();
                }

                var completionSource = new TaskCompletionSource <object>(state);
                completionSource.SetException(ex);
                retval = completionSource.Task;
            }

            return(retval);
        }
            protected virtual void Dispose(bool disposing)
            {
                if (disposing && !this.disposed)
                {
                    this.disposed = true;

                    if (this.State == TransactionSignalState.Ready)
                    {
                        this.State = TransactionSignalState.Abandoned;
                    }
                    else if (this.State == TransactionSignalState.Prepared)
                    {
                        this.State = TransactionSignalState.Completed;
                    }
                    else
                    {
                        AsyncResult.ThrowInvalidAsyncResult("PrepareTransactionalCall should only be called in a using. Dispose called multiple times.");
                    }

                    try
                    {
                        Fx.CompleteTransactionScope(ref this.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.
                    IAsyncResult result;
                    if (this.State == TransactionSignalState.Completed && Unlock(out result))
                    {
                        if (this.parent.deferredTransactionalResult != null)
                        {
                            AsyncResult.ThrowInvalidAsyncResult(this.parent.deferredTransactionalResult);
                        }
                        this.parent.deferredTransactionalResult = result;
                    }
                }
            }