TransactionScope.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / System.Activities / System / Activities / Statements / TransactionScope.cs / 1305376 / TransactionScope.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------

namespace System.Activities.Statements 
{
    using System; 
    using System.Activities; 
    using System.Activities.Validation;
    using System.Collections.Generic; 
    using System.ComponentModel;
    using System.Runtime;
    using System.Transactions;
    using System.Windows.Markup; 
    using System.Activities.Expressions;
    using System.Collections.ObjectModel; 
 
    [ContentProperty("Body")]
    public sealed class TransactionScope : NativeActivity 
    {
        const IsolationLevel defaultIsolationLevel = default(IsolationLevel);

        InArgument timeout; 
        bool isTimeoutSetExplicitly;
        Variable runtimeTransactionHandle; 
        bool abortInstanceOnTransactionFailure; 
        bool abortInstanceFlagWasExplicitlySet;
        Delay nestedScopeTimeoutWorkflow; 
        Variable delayWasScheduled;
        Variable nestedScopeTimeout;
        Variable nestedScopeTimeoutActivityInstance;
        static string runtimeTransactionHandlePropertyName = typeof(RuntimeTransactionHandle).FullName; 
        const string AbortInstanceOnTransactionFailurePropertyName = "AbortInstanceOnTransactionFailure";
        const string IsolationLevelPropertyName = "IsolationLevel"; 
        const string BodyPropertyName = "Body"; 

        public TransactionScope() 
            : base()
        {
            this.timeout = new InArgument(TimeSpan.FromMinutes(1));
            this.runtimeTransactionHandle = new Variable(); 
            this.abortInstanceOnTransactionFailure = true;
            this.nestedScopeTimeout = new Variable(); 
            this.delayWasScheduled = new Variable(); 
            this.nestedScopeTimeoutActivityInstance = new Variable();
 
            base.Constraints.Add(ProcessParentChainConstraints());
            base.Constraints.Add(ProcessChildSubtreeConstraints());
        }
 
        [DefaultValue(null)]
        public Activity Body 
        { 
            get;
            set; 
        }

        [DefaultValue(true)]
        public bool AbortInstanceOnTransactionFailure 
        {
            get 
            { 
                return this.abortInstanceOnTransactionFailure;
            } 
            set
            {
                this.abortInstanceOnTransactionFailure = value;
                this.abortInstanceFlagWasExplicitlySet = true; 
            }
        } 
 
        public IsolationLevel IsolationLevel
        { 
            get;
            set;
        }
 
        public InArgument Timeout
        { 
            get 
            {
                return this.timeout; 
            }

            set
            { 
                this.timeout = value;
                this.isTimeoutSetExplicitly = true; 
            } 
        }
 
        Delay NestedScopeTimeoutWorkflow
        {
            get
            { 
                if (this.nestedScopeTimeoutWorkflow == null)
                { 
                    this.nestedScopeTimeoutWorkflow = new Delay 
                    {
                        Duration = new InArgument(this.nestedScopeTimeout) 
                    };

                }
                return this.nestedScopeTimeoutWorkflow; 
            }
        } 
 
        protected override bool CanInduceIdle
        { 
            get
            {
                return true;
            } 
        }
 
        [EditorBrowsable(EditorBrowsableState.Never)] 
        public bool ShouldSerializeIsolationLevel()
        { 
            return this.IsolationLevel != defaultIsolationLevel;
        }

        [EditorBrowsable(EditorBrowsableState.Never)] 
        public bool ShouldSerializeTimeout()
        { 
            return this.isTimeoutSetExplicitly; 
        }
 
        protected override void CacheMetadata(NativeActivityMetadata metadata)
        {
            RuntimeArgument timeoutArgument = new RuntimeArgument("Timeout", typeof(TimeSpan), ArgumentDirection.In,false);
            metadata.Bind(this.Timeout, timeoutArgument); 
            metadata.SetArgumentsCollection(new Collection { timeoutArgument });
            metadata.AddImplementationChild(this.NestedScopeTimeoutWorkflow); 
 
            if (this.Body != null)
            { 
                metadata.AddChild(this.Body);
            }

            metadata.AddImplementationVariable(this.runtimeTransactionHandle); 
            metadata.AddImplementationVariable(this.nestedScopeTimeout);
            metadata.AddImplementationVariable(this.delayWasScheduled); 
            metadata.AddImplementationVariable(this.nestedScopeTimeoutActivityInstance); 
        }
 
        Constraint ProcessParentChainConstraints()
        {
            DelegateInArgument element = new DelegateInArgument { Name = "element" };
            DelegateInArgument validationContext = new DelegateInArgument { Name = "validationContext" }; 
            DelegateInArgument parent = new DelegateInArgument { Name = "parent" };
 
            return new Constraint 
            {
                Body = new ActivityAction 
                {
                    Argument1 = element,
                    Argument2 = validationContext,
                    Handler = new Sequence 
                    {
                        Activities = 
                        { 
                            new ForEach
                            { 
                                Values = new GetParentChain
                                {
                                    ValidationContext = validationContext,
                                }, 
                                Body = new ActivityAction
                                { 
                                    Argument = parent, 
                                    Handler = new Sequence
                                    { 
                                        Activities =
                                        {
                                            new If()
                                            { 
                                                Condition = new Equal
                                                { 
                                                    Left = new ObtainType 
                                                    {
                                                        Input = parent, 
                                                    },
                                                    Right = new InArgument(context => typeof(TransactionScope))
                                                },
                                                Then = new Sequence 
                                                {
                                                    Activities = 
                                                    { 
                                                        new AssertValidation
                                                        { 
                                                            IsWarning = true,
                                                            Assertion = new AbortInstanceFlagValidator
                                                            {
                                                                ParentActivity = parent, 
                                                                TransactionScope = new InArgument(context => element.Get(context))
                                                            }, 
                                                            Message = new InArgument(SR.AbortInstanceOnTransactionFailureDoesNotMatch), 
                                                            PropertyName = AbortInstanceOnTransactionFailurePropertyName
                                                        }, 
                                                        new AssertValidation
                                                        {
                                                            Assertion = new IsolationLevelValidator
                                                            { 
                                                                ParentActivity = parent,
                                                                CurrentIsolationLevel = new InArgument(context => element.Get(context).IsolationLevel) 
                                                            }, 
                                                            Message = new InArgument(SR.IsolationLevelValidation),
                                                            PropertyName = IsolationLevelPropertyName 
                                                        }

                                                    }
                                                } 

                                            } 
                                        } 
                                    }
                                } 
                            }
                        }
                    }
                } 
            };
        } 
 
        Constraint ProcessChildSubtreeConstraints()
        { 
            DelegateInArgument element = new DelegateInArgument { Name = "element" };
            DelegateInArgument validationContext = new DelegateInArgument { Name = "validationContext" };
            DelegateInArgument child = new DelegateInArgument { Name = "child" };
            Variable nestedCompensableActivity = new Variable(); 

            return new Constraint 
            { 
                Body = new ActivityAction
                { 
                    Argument1 = element,
                    Argument2 = validationContext,
                    Handler = new Sequence
                    { 
                        Variables = { nestedCompensableActivity },
                        Activities = 
                        { 
                            new ForEach
                            { 
                                Values = new GetChildSubtree
                                {
                                    ValidationContext = validationContext,
                                }, 
                                Body = new ActivityAction
                                { 
                                    Argument = child, 
                                    Handler = new Sequence
                                    { 
                                        Activities =
                                        {
                                            new If()
                                            { 
                                                Condition = new Equal()
                                                { 
                                                     Left = new ObtainType 
                                                     {
                                                          Input = new InArgument(child) 
                                                     },
                                                     Right = new InArgument(context => typeof(CompensableActivity))
                                                },
                                                Then = new Assign 
                                                {
                                                    To = new OutArgument(nestedCompensableActivity), 
                                                    Value = new InArgument(true) 
                                                }
                                            } 
                                        }
                                    }
                                }
                            }, 
                            new AssertValidation()
                            { 
                                 Assertion = new InArgument(new Not { Operand = new VariableValue { Variable = nestedCompensableActivity }}), 
                                 Message = new InArgument(SR.CompensableActivityInsideTransactionScopeActivity),
                                 PropertyName = BodyPropertyName 
                            }
                        }
                    }
                } 
            };
        } 
 
        protected override void Execute(NativeActivityContext context)
        { 
            RuntimeTransactionHandle transactionHandle = this.runtimeTransactionHandle.Get(context);
            Fx.Assert(transactionHandle != null, "RuntimeTransactionHandle is null");

            RuntimeTransactionHandle foundHandle = context.Properties.Find(runtimeTransactionHandlePropertyName) as RuntimeTransactionHandle; 
            if (foundHandle == null)
            { 
                //Note, once the property is registered, we cannot change the state of this flag 
                transactionHandle.AbortInstanceOnTransactionFailure = this.AbortInstanceOnTransactionFailure;
                context.Properties.Add(transactionHandle.ExecutionPropertyName, transactionHandle); 
            }
            else
            {
                //nested case 
                //foundHandle.IsRuntimeOwnedTransaction will be true only in the Invoke case within an ambient Sys.Tx transaction.
                //If this TSA is nested inside the ambient transaction from Invoke, then the AbortInstanceFlag is always false since the RTH corresponding to the ambient 
                //transaction has this flag as false. In this case, we ignore if this TSA has this flag explicitly set to true. 
                if(!foundHandle.IsRuntimeOwnedTransaction && this.abortInstanceFlagWasExplicitlySet && (foundHandle.AbortInstanceOnTransactionFailure != this.AbortInstanceOnTransactionFailure))
                { 
                    throw FxTrace.Exception.AsError(new InvalidOperationException(SR.AbortInstanceOnTransactionFailureDoesNotMatch));
                }

                if (foundHandle.SuppressTransaction) 
                {
                    throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CannotNestTransactionScopeWhenAmbientHandleIsSuppressed(this.DisplayName))); 
                } 
                transactionHandle = foundHandle;
            } 

            Transaction transaction = transactionHandle.GetCurrentTransaction(context);
            //Check if there is already a transaction (Requires Semantics)
            if (transaction == null) 
            {
                //If not, request one.. 
                transactionHandle.RequestTransactionContext(context, OnContextAcquired, null); 
            }
            else 
            {
                //Most likely, you are inside a nested TSA
                if (transaction.IsolationLevel != this.IsolationLevel)
                { 
                    throw FxTrace.Exception.AsError(new InvalidOperationException(SR.IsolationLevelValidation));
                } 
 
                //Check if the nested TSA had a timeout specified explicitly
                if (this.isTimeoutSetExplicitly) 
                {
                    TimeSpan timeout = this.Timeout.Get(context);
                    this.delayWasScheduled.Set(context, true);
                    this.nestedScopeTimeout.Set(context, timeout); 

                    this.nestedScopeTimeoutActivityInstance.Set(context, context.ScheduleActivity(this.NestedScopeTimeoutWorkflow, new CompletionCallback(OnDelayCompletion))); 
                } 

                //execute the Body under the current runtime transaction 
                ScheduleBody(context);
            }
        }
 
        void OnContextAcquired(NativeActivityTransactionContext context, object state)
        { 
            Fx.Assert(context != null, "ActivityTransactionContext was null"); 

            TimeSpan transactionTimeout = this.Timeout.Get(context); 
            TransactionOptions transactionOptions = new TransactionOptions()
            {
                 IsolationLevel = this.IsolationLevel,
                 Timeout = transactionTimeout 
            };
 
            context.SetRuntimeTransaction(new CommittableTransaction(transactionOptions)); 

            ScheduleBody(context); 
        }

        void ScheduleBody(NativeActivityContext context)
        { 
            if (this.Body != null)
            { 
                context.ScheduleActivity(this.Body,new CompletionCallback(OnCompletion)); 
            }
        } 

        void OnCompletion(NativeActivityContext context, ActivityInstance instance)
        {
            RuntimeTransactionHandle transactionHandle = this.runtimeTransactionHandle.Get(context); 
            Fx.Assert(transactionHandle != null, "RuntimeTransactionHandle is null");
 
            if (this.delayWasScheduled.Get(context)) 
            {
                transactionHandle.CompleteTransaction(context, new BookmarkCallback(OnTransactionComplete)); 
            }
            else
            {
                transactionHandle.CompleteTransaction(context); 
            }
        } 
 
        void OnDelayCompletion(NativeActivityContext context, ActivityInstance instance)
        { 
            if (instance.State == ActivityInstanceState.Closed)
            {
                RuntimeTransactionHandle handle = context.Properties.Find(runtimeTransactionHandlePropertyName) as RuntimeTransactionHandle;
                Fx.Assert(handle != null, "Internal error.. If we are here, there ought to be an ambient transaction handle"); 
                handle.GetCurrentTransaction(context).Rollback();
            } 
        } 

        void OnTransactionComplete(NativeActivityContext context, Bookmark bookmark, object state) 
        {
            Fx.Assert(this.delayWasScheduled.Get(context), "Internal error..Delay should have been scheduled if we are here");
            ActivityInstance delayActivityInstance = this.nestedScopeTimeoutActivityInstance.Get(context);
            if (delayActivityInstance != null) 
            {
                context.CancelChild(delayActivityInstance); 
            } 
        }
 
        //
        class ObtainType : CodeActivity
        {
            public ObtainType() 
            {
            } 
 
            public InArgument Input
            { 
                get;
                set;
            }
 
            protected override Type Execute(CodeActivityContext context)
            { 
                return this.Input.Get(context).GetType(); 
            }
        } 

        class IsolationLevelValidator : CodeActivity
        {
            public InArgument ParentActivity 
            {
                get; 
                set; 
            }
 
            public InArgument CurrentIsolationLevel
            {
                get;
                set; 
            }
 
            protected override bool Execute(CodeActivityContext context) 
            {
                Activity parent = this.ParentActivity.Get(context); 

                if (parent != null)
                {
                    TransactionScope transactionScope = parent as TransactionScope; 
                    Fx.Assert(transactionScope != null, "ParentActivity was not of expected type");
 
                    if (transactionScope.IsolationLevel != this.CurrentIsolationLevel.Get(context)) 
                    {
                        return false; 
                    }
                    else
                    {
                        return true; 
                    }
                } 
                else 
                {
                    return true; 
                }
            }
        }
 
        class AbortInstanceFlagValidator : CodeActivity
        { 
            public InArgument ParentActivity 
            {
                get; 
                set;
            }

            public InArgument TransactionScope 
            {
                get; 
                set; 
            }
 
            protected override bool Execute(CodeActivityContext context)
            {
                Activity parent = this.ParentActivity.Get(context);
 
                if (parent != null)
                { 
                    TransactionScope parentTransactionScope = parent as TransactionScope; 
                    Fx.Assert(parentTransactionScope != null, "ParentActivity was not of expected type");
                    TransactionScope currentTransactionScope = this.TransactionScope.Get(context); 

                    if (parentTransactionScope.AbortInstanceOnTransactionFailure != currentTransactionScope.AbortInstanceOnTransactionFailure)
                    {
                        //If the Inner TSA was default and still different from outer, we dont flag validation warning. See design spec for all variations 
                        if (!currentTransactionScope.abortInstanceFlagWasExplicitlySet)
                        { 
                            return true; 
                        }
                        else 
                        {
                            return false;
                        }
                    } 
                    else
                    { 
                        return true; 
                    }
                } 
                else
                {
                    return true;
                } 
            }
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK