Files
linux-packaging-mono/mcs/class/System.Transactions/System.Transactions/TransactionScope.cs
Xamarin Public Jenkins (auto-signing) 966bba02bb Imported Upstream version 5.2.0.175
Former-commit-id: bb0468d0f257ff100aa895eb5fe583fb5dfbf900
2017-06-07 13:16:24 +00:00

275 lines
6.8 KiB
C#

//
// TransactionScope.cs
//
// Author:
// Atsushi Enomoto <atsushi@ximian.com>
// Ankit Jain <JAnkit@novell.com>
//
// (C)2005 Novell Inc,
// (C)2006 Novell Inc,
//
using DTCOption = System.Transactions.EnterpriseServicesInteropOption;
namespace System.Transactions
{
public sealed class TransactionScope : IDisposable
{
static TransactionOptions defaultOptions =
new TransactionOptions (0, TransactionManager.DefaultTimeout);
Transaction transaction;
Transaction oldTransaction;
TransactionScope parentScope;
TimeSpan timeout;
/* Num of non-disposed nested scopes */
int nested;
bool disposed;
bool completed;
bool isRoot;
bool asyncFlowEnabled;
public TransactionScope ()
: this (TransactionScopeOption.Required,
TransactionManager.DefaultTimeout)
{
}
public TransactionScope(TransactionScopeAsyncFlowOption asyncFlowOption)
: this(TransactionScopeOption.Required,
TransactionManager.DefaultTimeout, asyncFlowOption)
{
}
public TransactionScope (Transaction transactionToUse)
: this (transactionToUse, TransactionManager.DefaultTimeout)
{
}
public TransactionScope (Transaction transactionToUse,
TimeSpan scopeTimeout)
: this (transactionToUse, scopeTimeout, DTCOption.None)
{
}
[MonoTODO ("EnterpriseServicesInteropOption not supported.")]
public TransactionScope (Transaction transactionToUse,
TimeSpan scopeTimeout, DTCOption interopOption)
{
Initialize (TransactionScopeOption.Required,
transactionToUse, defaultOptions, interopOption, scopeTimeout, TransactionScopeAsyncFlowOption.Suppress);
}
public TransactionScope (TransactionScopeOption scopeOption)
: this (scopeOption, TransactionManager.DefaultTimeout)
{
}
public TransactionScope (TransactionScopeOption scopeOption,
TimeSpan scopeTimeout)
: this (scopeOption, scopeTimeout, TransactionScopeAsyncFlowOption.Suppress)
{
}
public TransactionScope(TransactionScopeOption option, TransactionScopeAsyncFlowOption asyncFlow)
: this(option, TransactionManager.DefaultTimeout, asyncFlow)
{
}
public TransactionScope (TransactionScopeOption scopeOption,
TimeSpan scopeTimeout, TransactionScopeAsyncFlowOption asyncFlow)
{
Initialize (scopeOption, null, defaultOptions,
DTCOption.None, scopeTimeout, asyncFlow);
}
public TransactionScope (TransactionScopeOption scopeOption,
TransactionOptions transactionOptions)
: this (scopeOption, transactionOptions, DTCOption.None)
{
}
[MonoTODO ("EnterpriseServicesInteropOption not supported")]
public TransactionScope (TransactionScopeOption scopeOption,
TransactionOptions transactionOptions,
DTCOption interopOption)
{
Initialize (scopeOption, null, transactionOptions, interopOption,
TransactionManager.DefaultTimeout, TransactionScopeAsyncFlowOption.Suppress);
}
public TransactionScope (Transaction transactionToUse,
TransactionScopeAsyncFlowOption asyncFlowOption)
{
throw new NotImplementedException ();
}
public TransactionScope (Transaction transactionToUse,
TimeSpan scopeTimeout,
TransactionScopeAsyncFlowOption asyncFlowOption)
{
throw new NotImplementedException ();
}
public TransactionScope (TransactionScopeOption scopeOption,
TransactionOptions transactionOptions,
TransactionScopeAsyncFlowOption asyncFlowOption)
{
throw new NotImplementedException ();
}
void Initialize (TransactionScopeOption scopeOption,
Transaction tx, TransactionOptions options,
DTCOption interop, TimeSpan scopeTimeout, TransactionScopeAsyncFlowOption asyncFlow)
{
completed = false;
isRoot = false;
nested = 0;
asyncFlowEnabled = asyncFlow == TransactionScopeAsyncFlowOption.Enabled;
if (scopeTimeout < TimeSpan.Zero)
throw new ArgumentOutOfRangeException ("scopeTimeout");
this.timeout = scopeTimeout;
oldTransaction = Transaction.CurrentInternal;
Transaction.CurrentInternal = transaction = InitTransaction (tx, scopeOption);
if (transaction != null)
transaction.InitScope (this);
if (parentScope != null)
parentScope.nested ++;
}
Transaction InitTransaction (Transaction tx, TransactionScopeOption scopeOption)
{
if (tx != null)
return tx;
if (scopeOption == TransactionScopeOption.Suppress) {
if (Transaction.CurrentInternal != null)
parentScope = Transaction.CurrentInternal.Scope;
return null;
}
if (scopeOption == TransactionScopeOption.Required) {
if (Transaction.CurrentInternal == null) {
isRoot = true;
return new Transaction ();
}
parentScope = Transaction.CurrentInternal.Scope;
return Transaction.CurrentInternal;
}
/* RequiresNew */
if (Transaction.CurrentInternal != null)
parentScope = Transaction.CurrentInternal.Scope;
isRoot = true;
return new Transaction ();
}
public void Complete ()
{
if (completed)
throw new InvalidOperationException ("The current TransactionScope is already complete. You should dispose the TransactionScope.");
completed = true;
}
internal bool IsComplete {
get { return completed; }
}
internal TimeSpan Timeout
{
get { return timeout; }
}
public void Dispose ()
{
if (disposed)
return;
disposed = true;
if (parentScope != null)
parentScope.nested --;
if (nested > 0) {
transaction.Rollback ();
throw new InvalidOperationException ("TransactionScope nested incorrectly");
}
if (Transaction.CurrentInternal != transaction && !asyncFlowEnabled) {
if (transaction != null)
transaction.Rollback ();
if (Transaction.CurrentInternal != null)
Transaction.CurrentInternal.Rollback ();
throw new InvalidOperationException ("Transaction.Current has changed inside of the TransactionScope");
}
if (asyncFlowEnabled) {
if (oldTransaction != null)
oldTransaction.Scope = parentScope;
var variedTransaction = Transaction.CurrentInternal;
if (transaction == null && variedTransaction == null)
/* scope was not in a transaction, (Suppress) */
return;
variedTransaction.Scope = parentScope;
Transaction.CurrentInternal = oldTransaction;
transaction.Scope = null;
if (!IsComplete) {
transaction.Rollback ();
variedTransaction.Rollback();
return;
}
if (!isRoot)
/* Non-root scope has completed+ended */
return;
variedTransaction.CommitInternal();
transaction.CommitInternal();
} else {
if (Transaction.CurrentInternal == oldTransaction && oldTransaction != null)
oldTransaction.Scope = parentScope;
Transaction.CurrentInternal = oldTransaction;
if (transaction == null)
/* scope was not in a transaction, (Suppress) */
return;
transaction.Scope = null;
if (!IsComplete)
{
transaction.Rollback();
return;
}
if (!isRoot)
/* Non-root scope has completed+ended */
return;
transaction.CommitInternal();
}
}
}
}