5 // Atsushi Enomoto <atsushi@ximian.com>
6 // Ankit Jain <JAnkit@novell.com>
13 using DTCOption = System.Transactions.EnterpriseServicesInteropOption;
15 namespace System.Transactions
17 public sealed class TransactionScope : IDisposable
19 static TransactionOptions defaultOptions =
20 new TransactionOptions (0, TransactionManager.DefaultTimeout);
22 Transaction transaction;
23 Transaction oldTransaction;
24 TransactionScope parentScope;
27 /* Num of non-disposed nested scopes */
34 bool asyncFlowEnabled;
36 public TransactionScope ()
37 : this (TransactionScopeOption.Required,
38 TransactionManager.DefaultTimeout)
42 public TransactionScope(TransactionScopeAsyncFlowOption asyncFlow)
43 : this(TransactionScopeOption.Required,
44 TransactionManager.DefaultTimeout, asyncFlow)
48 public TransactionScope (Transaction transaction)
49 : this (transaction, TransactionManager.DefaultTimeout)
53 public TransactionScope (Transaction transaction,
55 : this (transaction, timeout, DTCOption.None)
59 [MonoTODO ("EnterpriseServicesInteropOption not supported.")]
60 public TransactionScope (Transaction transaction,
61 TimeSpan timeout, DTCOption opt)
63 Initialize (TransactionScopeOption.Required,
64 transaction, defaultOptions, opt, timeout, TransactionScopeAsyncFlowOption.Suppress);
67 public TransactionScope (TransactionScopeOption option)
68 : this (option, TransactionManager.DefaultTimeout)
72 public TransactionScope(TransactionScopeOption option, TransactionScopeAsyncFlowOption asyncFlow)
73 : this(option, TransactionManager.DefaultTimeout, asyncFlow)
77 public TransactionScope (TransactionScopeOption option,
78 TimeSpan timeout, TransactionScopeAsyncFlowOption asyncFlow)
80 Initialize (option, null, defaultOptions,
81 DTCOption.None, timeout, asyncFlow);
84 public TransactionScope (TransactionScopeOption scopeOption,
85 TransactionOptions options)
86 : this (scopeOption, options, DTCOption.None)
90 [MonoTODO ("EnterpriseServicesInteropOption not supported")]
91 public TransactionScope (TransactionScopeOption scopeOption,
92 TransactionOptions options,
95 Initialize (scopeOption, null, options, opt,
96 TransactionManager.DefaultTimeout, TransactionScopeAsyncFlowOption.Suppress);
99 void Initialize (TransactionScopeOption scopeOption,
100 Transaction tx, TransactionOptions options,
101 DTCOption interop, TimeSpan timeout, TransactionScopeAsyncFlowOption asyncFlow)
106 asyncFlowEnabled = asyncFlow == TransactionScopeAsyncFlowOption.Enabled;
108 if (timeout < TimeSpan.Zero)
109 throw new ArgumentOutOfRangeException ("timeout");
111 this.timeout = timeout;
113 oldTransaction = Transaction.CurrentInternal;
115 Transaction.CurrentInternal = transaction = InitTransaction (tx, scopeOption);
116 if (transaction != null)
117 transaction.InitScope (this);
118 if (parentScope != null)
119 parentScope.nested ++;
122 Transaction InitTransaction (Transaction tx, TransactionScopeOption scopeOption)
127 if (scopeOption == TransactionScopeOption.Suppress) {
128 if (Transaction.CurrentInternal != null)
129 parentScope = Transaction.CurrentInternal.Scope;
133 if (scopeOption == TransactionScopeOption.Required) {
134 if (Transaction.CurrentInternal == null) {
136 return new Transaction ();
139 parentScope = Transaction.CurrentInternal.Scope;
140 return Transaction.CurrentInternal;
144 if (Transaction.CurrentInternal != null)
145 parentScope = Transaction.CurrentInternal.Scope;
147 return new Transaction ();
150 public void Complete ()
153 throw new InvalidOperationException ("The current TransactionScope is already complete. You should dispose the TransactionScope.");
158 internal bool IsComplete {
159 get { return completed; }
162 internal TimeSpan Timeout
164 get { return timeout; }
167 public void Dispose ()
174 if (parentScope != null)
175 parentScope.nested --;
178 transaction.Rollback ();
179 throw new InvalidOperationException ("TransactionScope nested incorrectly");
182 if (Transaction.CurrentInternal != transaction && !asyncFlowEnabled) {
183 if (transaction != null)
184 transaction.Rollback ();
185 if (Transaction.CurrentInternal != null)
186 Transaction.CurrentInternal.Rollback ();
188 throw new InvalidOperationException ("Transaction.Current has changed inside of the TransactionScope");
191 if (asyncFlowEnabled) {
192 if (oldTransaction != null)
193 oldTransaction.Scope = parentScope;
195 var variedTransaction = Transaction.CurrentInternal;
197 if (transaction == null && variedTransaction == null)
198 /* scope was not in a transaction, (Suppress) */
201 variedTransaction.Scope = parentScope;
202 Transaction.CurrentInternal = oldTransaction;
204 transaction.Scope = null;
207 transaction.Rollback ();
208 variedTransaction.Rollback();
213 /* Non-root scope has completed+ended */
216 variedTransaction.CommitInternal();
217 transaction.CommitInternal();
219 if (Transaction.CurrentInternal == oldTransaction && oldTransaction != null)
220 oldTransaction.Scope = parentScope;
222 Transaction.CurrentInternal = oldTransaction;
224 if (transaction == null)
225 /* scope was not in a transaction, (Suppress) */
228 transaction.Scope = null;
232 transaction.Rollback();
237 /* Non-root scope has completed+ended */
240 transaction.CommitInternal();