/// <summary> /// Handles the parent transaction context's <see cref="StateChanged"/> event. /// </summary> /// <param name="sender">The object that raised the event.</param> /// <param name="e">The <see cref="TransactionContextStateChangedEventArgs"/> that contains the event data.</param> private void Parent_TransactionContextStateChanged(object sender, TransactionContextStateChangedEventArgs e) { if (sender == null) { throw new ArgumentNullException(nameof(sender)); } if (e == null) { throw new ArgumentNullException(nameof(e)); } if (((TransactionContext)sender).State == TransactionContextState.Exited) { Dispose(); } }
private static void OnTransactionContextStateChanged(object sender, TransactionContextStateChangedEventArgs e) { if (sender == null) { throw new ArgumentNullException(nameof(sender)); } if (e == null) { throw new ArgumentNullException(nameof(e)); } var context = (TransactionContext)sender; if (!context.IsController) { return; } if (e.NewState == TransactionContextState.Exited && (e.OldState == TransactionContextState.ToBeCommitted || e.OldState == TransactionContextState.ToBeRollbacked)) { ConcurrentDictionary <string, Lazy <Task <DataSession> > > sessionsByTransactionGroup; if (_pending.TryRemove(context, out sessionsByTransactionGroup)) { Task.Run( async() => { // In the face of error(s), we try to go on and rollback as many data sessions as we can // then we throw an AggregateException encapsulating all exceptions that occurred. // Data sessions committed before the first error will be left as is // and must be handled by the application using a compensating action for example var exceptions = new ConcurrentBag <Exception>(); var tasks = sessionsByTransactionGroup .Values .Where(ls => ls.IsValueCreated) .Select( async lazySession => { var session = await lazySession.Value.ConfigureAwait(false); try { if (exceptions.Count > 0 || e.OldState == TransactionContextState.ToBeRollbacked) { await session.Rollback(session).ConfigureAwait(false); } else if (e.OldState == TransactionContextState.ToBeCommitted) { await session.Commit(session).ConfigureAwait(false); } } catch (Exception ex) { exceptions.Add(ex); } finally { try { await session.End(session).ConfigureAwait(false); } catch (Exception ex) { exceptions.Add(ex); } } }); await Task.WhenAll(tasks).ConfigureAwait(false); if (exceptions.Count > 0) { throw new AggregateException(exceptions); } }); } } }
/// <summary> /// Handles the parent transaction context's <see cref="StateChanged"/> event. /// </summary> /// <param name="sender">The object that raised the event.</param> /// <param name="e">The <see cref="TransactionContextStateChangedEventArgs"/> that contains the event data.</param> private void Parent_TransactionContextStateChanged(object sender, TransactionContextStateChangedEventArgs e) { if (sender == null) throw new ArgumentNullException(nameof(sender)); if (e == null) throw new ArgumentNullException(nameof(e)); if (((TransactionContext) sender).State == TransactionContextState.Exited) Dispose(); }