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,
74 : this (option, timeout, TransactionScopeAsyncFlowOption.Suppress)
78 public TransactionScope(TransactionScopeOption option, TransactionScopeAsyncFlowOption asyncFlow)
79 : this(option, TransactionManager.DefaultTimeout, asyncFlow)
83 public TransactionScope (TransactionScopeOption option,
84 TimeSpan timeout, TransactionScopeAsyncFlowOption asyncFlow)
86 Initialize (option, null, defaultOptions,
87 DTCOption.None, timeout, asyncFlow);
90 public TransactionScope (TransactionScopeOption scopeOption,
91 TransactionOptions options)
92 : this (scopeOption, options, DTCOption.None)
96 [MonoTODO ("EnterpriseServicesInteropOption not supported")]
97 public TransactionScope (TransactionScopeOption scopeOption,
98 TransactionOptions options,
101 Initialize (scopeOption, null, options, opt,
102 TransactionManager.DefaultTimeout, TransactionScopeAsyncFlowOption.Suppress);
105 void Initialize (TransactionScopeOption scopeOption,
106 Transaction tx, TransactionOptions options,
107 DTCOption interop, TimeSpan timeout, TransactionScopeAsyncFlowOption asyncFlow)
112 asyncFlowEnabled = asyncFlow == TransactionScopeAsyncFlowOption.Enabled;
114 if (timeout < TimeSpan.Zero)
115 throw new ArgumentOutOfRangeException ("timeout");
117 this.timeout = timeout;
119 oldTransaction = Transaction.CurrentInternal;
121 Transaction.CurrentInternal = transaction = InitTransaction (tx, scopeOption);
122 if (transaction != null)
123 transaction.InitScope (this);
124 if (parentScope != null)
125 parentScope.nested ++;
128 Transaction InitTransaction (Transaction tx, TransactionScopeOption scopeOption)
133 if (scopeOption == TransactionScopeOption.Suppress) {
134 if (Transaction.CurrentInternal != null)
135 parentScope = Transaction.CurrentInternal.Scope;
139 if (scopeOption == TransactionScopeOption.Required) {
140 if (Transaction.CurrentInternal == null) {
142 return new Transaction ();
145 parentScope = Transaction.CurrentInternal.Scope;
146 return Transaction.CurrentInternal;
150 if (Transaction.CurrentInternal != null)
151 parentScope = Transaction.CurrentInternal.Scope;
153 return new Transaction ();
156 public void Complete ()
159 throw new InvalidOperationException ("The current TransactionScope is already complete. You should dispose the TransactionScope.");
164 internal bool IsComplete {
165 get { return completed; }
168 internal TimeSpan Timeout
170 get { return timeout; }
173 public void Dispose ()
180 if (parentScope != null)
181 parentScope.nested --;
184 transaction.Rollback ();
185 throw new InvalidOperationException ("TransactionScope nested incorrectly");
188 if (Transaction.CurrentInternal != transaction && !asyncFlowEnabled) {
189 if (transaction != null)
190 transaction.Rollback ();
191 if (Transaction.CurrentInternal != null)
192 Transaction.CurrentInternal.Rollback ();
194 throw new InvalidOperationException ("Transaction.Current has changed inside of the TransactionScope");
197 if (asyncFlowEnabled) {
198 if (oldTransaction != null)
199 oldTransaction.Scope = parentScope;
201 var variedTransaction = Transaction.CurrentInternal;
203 if (transaction == null && variedTransaction == null)
204 /* scope was not in a transaction, (Suppress) */
207 variedTransaction.Scope = parentScope;
208 Transaction.CurrentInternal = oldTransaction;
210 transaction.Scope = null;
213 transaction.Rollback ();
214 variedTransaction.Rollback();
219 /* Non-root scope has completed+ended */
222 variedTransaction.CommitInternal();
223 transaction.CommitInternal();
225 if (Transaction.CurrentInternal == oldTransaction && oldTransaction != null)
226 oldTransaction.Scope = parentScope;
228 Transaction.CurrentInternal = oldTransaction;
230 if (transaction == null)
231 /* scope was not in a transaction, (Suppress) */
234 transaction.Scope = null;
238 transaction.Rollback();
243 /* Non-root scope has completed+ended */
246 transaction.CommitInternal();