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 public TransactionScope (Transaction transactionToUse,
106 TransactionScopeAsyncFlowOption asyncFlowOption)
108 throw new NotImplementedException ();
111 public TransactionScope (Transaction transactionToUse,
112 TimeSpan scopeTimeout,
113 TransactionScopeAsyncFlowOption asyncFlowOption)
115 throw new NotImplementedException ();
118 public TransactionScope (TransactionScopeOption scopeOption,
119 TransactionOptions transactionOptions,
120 TransactionScopeAsyncFlowOption asyncFlowOption)
122 throw new NotImplementedException ();
125 void Initialize (TransactionScopeOption scopeOption,
126 Transaction tx, TransactionOptions options,
127 DTCOption interop, TimeSpan timeout, TransactionScopeAsyncFlowOption asyncFlow)
132 asyncFlowEnabled = asyncFlow == TransactionScopeAsyncFlowOption.Enabled;
134 if (timeout < TimeSpan.Zero)
135 throw new ArgumentOutOfRangeException ("timeout");
137 this.timeout = timeout;
139 oldTransaction = Transaction.CurrentInternal;
141 Transaction.CurrentInternal = transaction = InitTransaction (tx, scopeOption);
142 if (transaction != null)
143 transaction.InitScope (this);
144 if (parentScope != null)
145 parentScope.nested ++;
148 Transaction InitTransaction (Transaction tx, TransactionScopeOption scopeOption)
153 if (scopeOption == TransactionScopeOption.Suppress) {
154 if (Transaction.CurrentInternal != null)
155 parentScope = Transaction.CurrentInternal.Scope;
159 if (scopeOption == TransactionScopeOption.Required) {
160 if (Transaction.CurrentInternal == null) {
162 return new Transaction ();
165 parentScope = Transaction.CurrentInternal.Scope;
166 return Transaction.CurrentInternal;
170 if (Transaction.CurrentInternal != null)
171 parentScope = Transaction.CurrentInternal.Scope;
173 return new Transaction ();
176 public void Complete ()
179 throw new InvalidOperationException ("The current TransactionScope is already complete. You should dispose the TransactionScope.");
184 internal bool IsComplete {
185 get { return completed; }
188 internal TimeSpan Timeout
190 get { return timeout; }
193 public void Dispose ()
200 if (parentScope != null)
201 parentScope.nested --;
204 transaction.Rollback ();
205 throw new InvalidOperationException ("TransactionScope nested incorrectly");
208 if (Transaction.CurrentInternal != transaction && !asyncFlowEnabled) {
209 if (transaction != null)
210 transaction.Rollback ();
211 if (Transaction.CurrentInternal != null)
212 Transaction.CurrentInternal.Rollback ();
214 throw new InvalidOperationException ("Transaction.Current has changed inside of the TransactionScope");
217 if (asyncFlowEnabled) {
218 if (oldTransaction != null)
219 oldTransaction.Scope = parentScope;
221 var variedTransaction = Transaction.CurrentInternal;
223 if (transaction == null && variedTransaction == null)
224 /* scope was not in a transaction, (Suppress) */
227 variedTransaction.Scope = parentScope;
228 Transaction.CurrentInternal = oldTransaction;
230 transaction.Scope = null;
233 transaction.Rollback ();
234 variedTransaction.Rollback();
239 /* Non-root scope has completed+ended */
242 variedTransaction.CommitInternal();
243 transaction.CommitInternal();
245 if (Transaction.CurrentInternal == oldTransaction && oldTransaction != null)
246 oldTransaction.Scope = parentScope;
248 Transaction.CurrentInternal = oldTransaction;
250 if (transaction == null)
251 /* scope was not in a transaction, (Suppress) */
254 transaction.Scope = null;
258 transaction.Rollback();
263 /* Non-root scope has completed+ended */
266 transaction.CommitInternal();