CompensableActivity.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 / CompensableActivity.cs / 1305376 / CompensableActivity.cs

                            //---------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------
namespace System.Activities.Statements
{ 
    using System.Activities.Validation;
    using System.Collections.Generic; 
    using System.Collections.ObjectModel; 
    using System.ComponentModel;
    using System.Runtime; 
    using System.Runtime.Collections;
    using System.Windows.Markup;
    using System.Linq;
 
    [ContentProperty("Body")]
    public sealed class CompensableActivity : NativeActivity 
    { 
        static Constraint noCompensableActivityInSecondaryRoot = CompensableActivity.NoCompensableActivityInSecondaryRoot();
 
        Collection variables;

        CompensationParticipant compensationParticipant;
 
        // workflowCompensationBehavior field is used to store the singleton WokflowCompensationBehavior activity which needs to be scheduled once.
        // We currenly don't have runtime support to store both activity's name and activity. Using this field as a work around. 
        WorkflowCompensationBehavior workflowCompensationBehavior; 

        Variable currentCompensationId; 
        Variable currentCompensationToken;

        // This id will be passed to secondary root.
        Variable compensationId; 

        public CompensableActivity() 
            : base() 
        {
            this.currentCompensationToken = new Variable(); 
            this.currentCompensationId = new Variable();
            this.compensationId = new Variable();
        }
 
        public Collection Variables
        { 
            get 
            {
                if (this.variables == null) 
                {
                    this.variables = new ValidatingCollection
                    {
                        // disallow null values 
                        OnAddValidationCallback = item =>
                        { 
                            if (item == null) 
                            {
                                throw FxTrace.Exception.ArgumentNull("item"); 
                            }
                        }
                    };
                } 
                return this.variables;
            } 
        } 

        [DefaultValue(null)] 
        [DependsOn("Variables")]
        public Activity Body
        {
            get; 
            set;
        } 
 
        [DefaultValue(null)]
        [DependsOn("Body")] 
        public Activity CancellationHandler
        {
            get;
            set; 
        }
 
        [DefaultValue(null)] 
        [DependsOn("CancellationHandler")]
        public Activity CompensationHandler 
        {
            get;
            set;
        } 

        [DefaultValue(null)] 
        [DependsOn("CompensationHandler")] 
        public Activity ConfirmationHandler
        { 
            get;
            set;
        }
 
        protected override bool CanInduceIdle
        { 
            get 
            {
                return true; 
            }
        }

        // Internal properties. 
        CompensationParticipant CompensationParticipant
        { 
            get 
            {
                if (this.compensationParticipant == null) 
                {
                    this.compensationParticipant = new CompensationParticipant(this.compensationId);

                    if (CompensationHandler != null) 
                    {
                        this.compensationParticipant.CompensationHandler = CompensationHandler; 
                    } 

                    if (ConfirmationHandler != null) 
                    {
                        this.compensationParticipant.ConfirmationHandler = ConfirmationHandler;
                    }
 
                    if (CancellationHandler != null)
                    { 
                        this.compensationParticipant.CancellationHandler = CancellationHandler; 
                    }
                } 

                return this.compensationParticipant;
            }
 
            set
            { 
                this.compensationParticipant = value; 
            }
        } 

        protected override void CacheMetadata(NativeActivityMetadata metadata)
        {
            metadata.SetVariablesCollection(this.Variables); 

            metadata.SetImplementationVariablesCollection( 
                new Collection 
                {
                    this.currentCompensationId, 
                    this.currentCompensationToken,

                    // Add the variables which are only used by the secondary root
                    this.compensationId 
                });
 
            if (this.Body != null) 
            {
                metadata.SetChildrenCollection(new Collection { this.Body }); 
            }

            // Declare the handlers as public children.
            if (this.CompensationHandler != null) 
            {
                metadata.AddImportedChild(this.CompensationHandler); 
            } 

            if (this.ConfirmationHandler != null) 
            {
                metadata.AddImportedChild(this.ConfirmationHandler);
            }
 
            if (this.CancellationHandler != null)
            { 
                metadata.AddImportedChild(this.CancellationHandler); 
            }
 
            Collection implementationChildren = new Collection();

            if (!this.IsSingletonActivityDeclared(CompensationActivityStrings.WorkflowImplicitCompensationBehavior))
            { 
                this.workflowCompensationBehavior = new WorkflowCompensationBehavior();
 
                this.DeclareSingletonActivity(CompensationActivityStrings.WorkflowImplicitCompensationBehavior); 

                implementationChildren.Add(this.workflowCompensationBehavior); 

                metadata.AddDefaultExtensionProvider(CreateCompensationExtension);
            }
 
            // Clear the cached handler values as workflow definition could be updated.
            CompensationParticipant = null; 
            implementationChildren.Add(CompensationParticipant); 

            metadata.SetImplementationChildrenCollection(implementationChildren); 
        }

        CompensationExtension CreateCompensationExtension()
        { 
            Fx.Assert(this.workflowCompensationBehavior != null, "workflowCompensationBehavior should be assigned in CacheMetadata.");
 
            CompensationExtension compensationExtension = new CompensationExtension(); 
            compensationExtension.WorkflowCompensationBehavior = this.workflowCompensationBehavior;
 
            return compensationExtension;
        }

        internal override IList InternalGetConstraints() 
        {
            return new List(1) { noCompensableActivityInSecondaryRoot }; 
        } 

        static Constraint NoCompensableActivityInSecondaryRoot() 
        {
            DelegateInArgument validationContext = new DelegateInArgument { Name = "validationContext" };
            DelegateInArgument element = new DelegateInArgument { Name = "element" };
            Variable assertFlag = new Variable { Name = "assertFlag", Default = true }; 
            Variable> elements = new Variable>() { Name = "elements" };
            Variable index = new Variable() { Name = "index" }; 
 
            return new Constraint
            { 
                Body = new ActivityAction
                {
                    Argument1 = element,
                    Argument2 = validationContext, 
                    Handler = new Sequence
                    { 
                        Variables = 
                        {
                            assertFlag, 
                            elements,
                            index
                        },
                        Activities = 
                        {
                            new Assign> 
                            { 
                                To = elements,
                                Value = new GetParentChain 
                                {
                                    ValidationContext = validationContext,
                                },
                            }, 
                            new While(env => (assertFlag.Get(env) != false) && index.Get(env) < elements.Get(env).Count())
                            { 
                                Body = new Sequence 
                                {
                                    Activities = 
                                    {
                                        new If(env => (elements.Get(env).ElementAt(index.Get(env))).GetType() == typeof(CompensationParticipant))
                                        {
                                            Then = new Assign 
                                            {
                                                To = assertFlag, 
                                                Value = false 
                                            },
                                        }, 
                                        new Assign
                                        {
                                            To = index,
                                            Value = new InArgument(env => index.Get(env) + 1) 
                                        },
                                    } 
                                } 
                            },
                            new AssertValidation 
                            {
                                Assertion = new InArgument(assertFlag),
                                Message = new InArgument(SR.NoCAInSecondaryRoot)
                            } 
                        }
                    } 
                } 
            };
        } 

        protected override void Execute(NativeActivityContext context)
        {
            CompensationExtension compensationExtension = context.GetExtension(); 
            Fx.Assert(compensationExtension != null, "CompensationExtension must be valid");
 
            if (compensationExtension.IsWorkflowCompensationBehaviorScheduled) 
            {
                ScheduleBody(context, compensationExtension); 
            }
            else
            {
                compensationExtension.SetupWorkflowCompensationBehavior(context, new BookmarkCallback(OnWorkflowCompensationBehaviorScheduled)); 
            }
        } 
 
        protected override void Cancel(NativeActivityContext context)
        { 
            context.CancelChildren();
        }

        void OnWorkflowCompensationBehaviorScheduled(NativeActivityContext context, Bookmark bookmark, object value) 
        {
            CompensationExtension compensationExtension = context.GetExtension(); 
            Fx.Assert(compensationExtension != null, "CompensationExtension must be valid"); 

            ScheduleBody(context, compensationExtension); 
        }

        void ScheduleBody(NativeActivityContext context, CompensationExtension compensationExtension)
        { 
            Fx.Assert(compensationExtension != null, "CompensationExtension must be valid");
 
            CompensationToken parentToken = null; 
            long parentCompensationId = CompensationToken.RootCompensationId;
 
            parentToken = (CompensationToken)context.Properties.Find(CompensationToken.PropertyName);

            if (parentToken != null)
            { 
                if (compensationExtension.Get(parentToken.CompensationId).IsTokenValidInSecondaryRoot)
                { 
                      throw FxTrace.Exception.AsError(new InvalidOperationException(SR.NoCAInSecondaryRoot)); 
                }
 
                parentCompensationId = parentToken.CompensationId;
            }

            CompensationTokenData tokenData = new CompensationTokenData(compensationExtension.GetNextId(), parentCompensationId) 
                {
                    CompensationState = CompensationState.Active, 
                    DisplayName = this.DisplayName, 
                };
            CompensationToken token = new CompensationToken(tokenData); 

            context.Properties.Add(CompensationToken.PropertyName, token);

            this.currentCompensationId.Set(context, token.CompensationId); 
            this.currentCompensationToken.Set(context, token);
 
            compensationExtension.Add(token.CompensationId, tokenData); 

            if(TD.CompensationStateIsEnabled()) 
            {
                TD.CompensationState(tokenData.DisplayName, tokenData.CompensationState.ToString());
            }
 
            if (this.Body != null)
            { 
                context.ScheduleActivity(this.Body, new CompletionCallback(OnBodyExecutionComplete)); 
            }
            else 
            {
                //empty body case. Assume the body has completed successfully
                tokenData.CompensationState = CompensationState.Completed;
                if(TD.CompensationStateIsEnabled()) 
                {
                    TD.CompensationState(tokenData.DisplayName, tokenData.CompensationState.ToString()); 
                } 

                ScheduleSecondaryRoot(context, compensationExtension, tokenData); 
            }
        }

        void OnBodyExecutionComplete(NativeActivityContext context, ActivityInstance completedInstance) 
        {
            CompensationExtension compensationExtension = context.GetExtension(); 
            Fx.Assert(compensationExtension != null, "CompensationExtension must be valid"); 

            CompensationTokenData token = compensationExtension.Get(this.currentCompensationId.Get(context)); 
            Fx.Assert(token != null, "CompensationTokenData must be valid");

            if (completedInstance.State == ActivityInstanceState.Closed)
            { 
                token.CompensationState = CompensationState.Completed;
                if(TD.CompensationStateIsEnabled()) 
                { 
                    TD.CompensationState(token.DisplayName, token.CompensationState.ToString());
                } 

                if (context.IsCancellationRequested)
                {
                    token.CompensationState = CompensationState.Compensating; 
                }
            } 
            else if (completedInstance.State == ActivityInstanceState.Canceled || completedInstance.State == ActivityInstanceState.Faulted) 
            {
                // we check for faulted as well for one odd case where an exception can be thrown from the body activity itself. 
                token.CompensationState = CompensationState.Canceling;
            }
            else
            { 
                Fx.Assert(false, "completedInstance in unexpected state");
            } 
 
            ScheduleSecondaryRoot(context, compensationExtension, token);
        } 

        void ScheduleSecondaryRoot(NativeActivityContext context, CompensationExtension compensationExtension, CompensationTokenData token)
        {
            if (token.ParentCompensationId != CompensationToken.RootCompensationId) 
            {
                CompensationTokenData parentToken = compensationExtension.Get(token.ParentCompensationId); 
                Fx.Assert(parentToken != null, "parentToken must be valid"); 

                parentToken.ExecutionTracker.Add(token); 
            }
            else
            {
                CompensationTokenData parentToken = compensationExtension.Get(CompensationToken.RootCompensationId); 
                Fx.Assert(parentToken != null, "parentToken must be valid");
 
                parentToken.ExecutionTracker.Add(token); 
            }
 
            // If we are going to Cancel, don't set the out arg...
            if (Result != null && token.CompensationState == CompensationState.Completed)
            {
                Result.Set(context, this.currentCompensationToken.Get(context)); 
            }
 
            Fx.Assert(token.BookmarkTable[CompensationBookmarkName.OnSecondaryRootScheduled] == null, "Bookmark should not be already initialized in the bookmark table."); 
            token.BookmarkTable[CompensationBookmarkName.OnSecondaryRootScheduled] = context.CreateBookmark(new BookmarkCallback(OnSecondaryRootScheduled));
 
            this.compensationId.Set(context, token.CompensationId);

            context.ScheduleSecondaryRoot(CompensationParticipant, context.Environment);
        } 

        void OnSecondaryRootScheduled(NativeActivityContext context, Bookmark bookmark, object value) 
        { 
            CompensationExtension compensationExtension = context.GetExtension();
            Fx.Assert(compensationExtension != null, "CompensationExtension must be valid"); 

            long compensationId = (long)value;

            CompensationTokenData compensationToken = compensationExtension.Get(compensationId); 
            Fx.Assert(compensationToken != null, "CompensationTokenData must be valid");
 
            if (compensationToken.CompensationState == CompensationState.Canceling) 
            {
                Fx.Assert(compensationToken.BookmarkTable[CompensationBookmarkName.Canceled] == null, "Bookmark should not be already initialized in the bookmark table."); 
                compensationToken.BookmarkTable[CompensationBookmarkName.Canceled] = context.CreateBookmark(new BookmarkCallback(OnCanceledOrCompensated));

                compensationExtension.NotifyMessage(context, compensationToken.CompensationId, CompensationBookmarkName.OnCancellation);
            } 
            else if (compensationToken.CompensationState == CompensationState.Compensating)
            { 
                Fx.Assert(compensationToken.BookmarkTable[CompensationBookmarkName.Compensated] == null, "Bookmark should not be already initialized in the bookmark table."); 
                compensationToken.BookmarkTable[CompensationBookmarkName.Compensated] = context.CreateBookmark(new BookmarkCallback(OnCanceledOrCompensated));
 
                compensationExtension.NotifyMessage(context, compensationToken.CompensationId, CompensationBookmarkName.OnCompensation);
            }
        }
 
        void OnCanceledOrCompensated(NativeActivityContext context, Bookmark bookmark, object value)
        { 
            CompensationExtension compensationExtension = context.GetExtension(); 
            Fx.Assert(compensationExtension != null, "CompensationExtension must be valid");
 
            long compensationId = (long)value;

            CompensationTokenData compensationToken = compensationExtension.Get(compensationId);
            Fx.Assert(compensationToken != null, "CompensationTokenData must be valid"); 

            switch(compensationToken.CompensationState) 
            { 
                case CompensationState.Canceling:
                    compensationToken.CompensationState = CompensationState.Canceled; 
                    break;
                case CompensationState.Compensating:
                    compensationToken.CompensationState = CompensationState.Compensated;
                    break; 
                default:
                    break; 
            } 

            if(TD.CompensationStateIsEnabled()) 
            {
                TD.CompensationState(compensationToken.DisplayName, compensationToken.CompensationState.ToString());
            }
 
            AppCompletionCleanup(context, compensationExtension, compensationToken);
 
            // Mark the activity as canceled. 
            context.MarkCanceled();
        } 

        void AppCompletionCleanup(NativeActivityContext context, CompensationExtension compensationExtension, CompensationTokenData compensationToken)
        {
            Fx.Assert(compensationToken != null, "CompensationTokenData must be valid"); 

            // Remove the token from the parent! 
            if (compensationToken.ParentCompensationId != CompensationToken.RootCompensationId) 
            {
                CompensationTokenData parentToken = compensationExtension.Get(compensationToken.ParentCompensationId); 
                Fx.Assert(parentToken != null, "parentToken must be valid");

                parentToken.ExecutionTracker.Remove(compensationToken);
            } 
            else
            { 
                // remove from workflow root... 
                CompensationTokenData parentToken = compensationExtension.Get(CompensationToken.RootCompensationId);
                Fx.Assert(parentToken != null, "parentToken must be valid"); 

                parentToken.ExecutionTracker.Remove(compensationToken);
            }
 
            compensationToken.RemoveBookmark(context, CompensationBookmarkName.Canceled);
            compensationToken.RemoveBookmark(context, CompensationBookmarkName.Compensated); 
 
            // Remove the token from the extension...
            compensationExtension.Remove(compensationToken.CompensationId); 
        }
    }
}

// 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