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

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

namespace System.Activities 
{
    using System; 
    using System.Activities.Runtime; 
    using System.Activities.Tracking;
    using System.Collections; 
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization; 
    using System.Runtime;
    using System.Runtime.Serialization; 
 
    [DataContract(Name = XD.ActivityInstance.Name, Namespace = XD.Runtime.Namespace)]
    [Fx.Tag.XamlVisible(false)] 
    public sealed class ActivityInstance : ActivityInstanceMap.IActivityReference
    {
        Activity activity;
 
        ChildList childList;
        ReadOnlyCollection childCache; 
 
        CompletionBookmark completionBookmark;
 
        ActivityInstanceMap instanceMap;
        ActivityInstance parent;

        string ownerName; 

        [DataMember(EmitDefaultValue = false)] 
        int busyCount; 
        [DataMember(EmitDefaultValue = false)]
        ExtendedData extendedData; 

        // most activities will have a symbol (either variable or argument, so optimize for that case)
        [DataMember(EmitDefaultValue = false)]
        bool noSymbols; 

        [DataMember(EmitDefaultValue = false)] 
        ActivityInstanceState state; 
        [DataMember(EmitDefaultValue = false)]
        bool isCancellationRequested; 
        [DataMember(EmitDefaultValue = false)]
        bool performingDefaultCancelation;
        [DataMember(EmitDefaultValue = false)]
        Substate substate; 

        [DataMember(EmitDefaultValue = false)] 
        long id; 

        [DataMember(EmitDefaultValue = false)] 
        bool initializationIncomplete;

        // This is serialized through the SerializedEnvironment property
        LocationEnvironment environment; 

        ExecutionPropertyManager propertyManager; 
 
        internal ActivityInstance(Activity activity)
        { 
            this.activity = activity;
            this.state = ActivityInstanceState.Executing;
            this.substate = Substate.Created;
        } 

        public Activity Activity 
        { 
            get
            { 
                return this.activity;
            }

            internal set 
            {
                Fx.Assert(value != null || this.state == ActivityInstanceState.Closed, ""); 
                this.activity = value; 
            }
        } 

        Activity ActivityInstanceMap.IActivityReference.Activity
        {
            get 
            {
                return this.Activity; 
            } 
        }
 
        [DataMember(EmitDefaultValue = false)]
        LocationEnvironment SerializedEnvironment
        {
            get 
            {
                if (this.IsCompleted) 
                { 
                    return null;
                } 
                else
                {
                    return this.environment;
                } 
            }
            set 
            { 
                Fx.Assert(value != null, "We should never get null here.");
 
                this.environment = value;
            }
        }
 
        internal LocationEnvironment Environment
        { 
            get 
            {
                Fx.Assert(this.environment != null, "There should always be an environment"); 
                return this.environment;
            }
        }
 
        internal ActivityInstanceMap InstanceMap
        { 
            get 
            {
                return this.instanceMap; 
            }
        }

        public bool IsCompleted 
        {
            get 
            { 
                return ActivityUtilities.IsCompletedState(this.State);
            } 
        }

        public ActivityInstanceState State
        { 
            get
            { 
                return this.state; 
            }
        } 

        internal bool IsCancellationRequested
        {
            get 
            {
                return this.isCancellationRequested; 
            } 
            set
            { 
                // This is set at the time of scheduling the cancelation work item

                Fx.Assert(!this.isCancellationRequested, "We should not set this if we have already requested cancel.");
                Fx.Assert(value != false, "We should only set this to true."); 

                this.isCancellationRequested = value; 
            } 
        }
 
        internal bool IsPerformingDefaultCancelation
        {
            get
            { 
                return this.performingDefaultCancelation;
            } 
        } 

        public string Id 
        {
            get
            {
                return this.id.ToString(CultureInfo.InvariantCulture); 
            }
        } 
 
        internal bool IsEnvironmentOwner
        { 
            get
            {
                return !this.noSymbols;
            } 
        }
 
        internal bool HasNotExecuted 
        {
            get 
            {
                return (this.substate & Substate.PreExecuting) != 0;
            }
        } 

        internal bool HasPendingWork 
        { 
            get
            { 
                if (this.HasChildren)
                {
                    return true;
                } 

                // check if we have pending bookmarks or outstanding OperationControlContexts/WorkItems 
                if (this.busyCount > 0) 
                {
                    return true; 
                }

                return false;
            } 
        }
 
        internal bool OnlyHasOutstandingBookmarks 
        {
            get 
            {
                // If our whole busy count is because of blocking bookmarks then
                // we should return true
                return !this.HasChildren && this.extendedData != null && (this.extendedData.BlockingBookmarkCount == this.busyCount); 
            }
        } 
 
        internal ActivityInstance Parent
        { 
            get
            {
                return this.parent;
            } 
        }
 
        internal bool WaitingForTransactionContext 
        {
            get 
            {
                if (this.extendedData == null)
                {
                    return false; 
                }
                else 
                { 
                    return this.extendedData.WaitingForTransactionContext;
                } 
            }
            set
            {
                EnsureExtendedData(); 

                this.extendedData.WaitingForTransactionContext = value; 
            } 
        }
 
        [DataMember(EmitDefaultValue = false)]
        internal CompletionBookmark CompletionBookmark
        {
            get 
            {
                return this.completionBookmark; 
            } 

            set 
            {
                this.completionBookmark = value;
            }
        } 

        internal FaultBookmark FaultBookmark 
        { 
            get
            { 
                if (this.extendedData == null)
                {
                    return null;
                } 

                return this.extendedData.FaultBookmark; 
            } 

            set 
            {
                Fx.Assert(value != null || (this.extendedData == null || this.extendedData.FaultBookmark == null), "cannot go from non-null to null");
                if (value != null)
                { 
                    EnsureExtendedData();
                    this.extendedData.FaultBookmark = value; 
                } 
            }
        } 

        internal bool HasChildren
        {
            get 
            {
                return (this.childList != null && this.childList.Count > 0); 
            } 
        }
 
        internal ExecutionPropertyManager PropertyManager
        {
            get
            { 
                return this.propertyManager;
            } 
            set 
            {
                this.propertyManager = value; 
            }
        }

        internal WorkflowDataContext DataContext 
        {
            get 
            { 
                if (this.extendedData != null)
                { 
                    return this.extendedData.DataContext;
                }
                return null;
            } 
            set
            { 
                EnsureExtendedData(); 
                this.extendedData.DataContext = value;
            } 
        }

        internal bool HasActivityReferences
        { 
            get
            { 
                return this.extendedData != null && this.extendedData.HasActivityReferences; 
            }
        } 

        [DataMember(Name = XD.ActivityInstance.PropertyManager, EmitDefaultValue = false)]
        [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode, Justification = "Called from Serialization")]
        ExecutionPropertyManager SerializedPropertyManager 
        {
            get 
            { 
                if (this.propertyManager == null || !this.propertyManager.ShouldSerialize(this))
                { 
                    return null;
                }
                else
                { 
                    return this.propertyManager;
                } 
            } 
            set
            { 
                Fx.Assert(value != null, "We don't emit the default value so this should never be null.");
                this.propertyManager = value;
            }
        } 

        [DataMember(Name = XD.ActivityInstance.Children, EmitDefaultValue = false)] 
        ChildList SerializedChildren 
        {
            get 
            {
                if (this.HasChildren)
                {
                    this.childList.Compress(); 
                    return this.childList;
                } 
 
                return null;
            } 

            set
            {
                Fx.Assert(value != null, "value from Serialization should not be null"); 
                this.childList = value;
            } 
        } 

        [DataMember(Name = XD.ActivityInstance.Owner, EmitDefaultValue = false)] 
        string OwnerName
        {
            get
            { 
                if (this.ownerName == null)
                { 
                    this.ownerName = this.Activity.GetType().Name; 
                }
                return this.ownerName; 
            }
            set
            {
                Fx.Assert(value != null, "value from Serialization should not be null"); 
                this.ownerName = value;
            } 
        } 

        internal static ActivityInstance CreateCompletedInstance(Activity activity) 
        {
            ActivityInstance instance = new ActivityInstance(activity);
            instance.state = ActivityInstanceState.Closed;
 
            return instance;
        } 
 
        internal static ActivityInstance CreateCanceledInstance(Activity activity)
        { 
            ActivityInstance instance = new ActivityInstance(activity);
            instance.state = ActivityInstanceState.Canceled;

            return instance; 
        }
 
        internal ReadOnlyCollection GetChildren() 
        {
            if (!this.HasChildren) 
            {
                return ChildList.Empty;
            }
 
            if (this.childCache == null)
            { 
                this.childCache = this.childList.AsReadOnly(); 
            }
            return this.childCache; 
        }

        internal HybridCollection GetRawChildren()
        { 
            return this.childList;
        } 
 
        void EnsureExtendedData()
        { 
            if (this.extendedData == null)
            {
                this.extendedData = new ExtendedData();
            } 
        }
 
        // Busy Count includes the following: 
        //   1. Active OperationControlContexts.
        //   2. Active work items. 
        //   3. Blocking bookmarks.
        internal void IncrementBusyCount()
        {
            this.busyCount++; 
        }
 
        internal void DecrementBusyCount() 
        {
            Fx.Assert(this.busyCount > 0, "something went wrong with our bookkeeping"); 
            this.busyCount--;
        }

        internal void DecrementBusyCount(int amount) 
        {
            Fx.Assert(this.busyCount >= amount, "something went wrong with our bookkeeping"); 
            this.busyCount -= amount; 
        }
 
        internal void AddActivityReference(ActivityInstanceReference reference)
        {
            EnsureExtendedData();
            this.extendedData.AddActivityReference(reference); 
        }
 
        internal void AddBookmark(Bookmark bookmark, BookmarkOptions options) 
        {
            bool affectsBusyCount = false; 

            if (!BookmarkOptionsHelper.IsNonBlocking(options))
            {
                IncrementBusyCount(); 
                affectsBusyCount = true;
            } 
 
            EnsureExtendedData();
            this.extendedData.AddBookmark(bookmark, affectsBusyCount); 
        }

        internal void RemoveBookmark(Bookmark bookmark, BookmarkOptions options)
        { 
            bool affectsBusyCount = false;
 
            if (!BookmarkOptionsHelper.IsNonBlocking(options)) 
            {
                DecrementBusyCount(); 
                affectsBusyCount = true;
            }

            Fx.Assert(this.extendedData != null, "something went wrong with our bookkeeping"); 
            this.extendedData.RemoveBookmark(bookmark, affectsBusyCount);
        } 
 
        internal void RemoveAllBookmarks(BookmarkScopeManager bookmarkScopeManager, BookmarkManager bookmarkManager)
        { 
            if (this.extendedData != null)
            {
                this.extendedData.PurgeBookmarks(bookmarkScopeManager, bookmarkManager, this);
            } 
        }
 
        internal void SetInitializationIncomplete() 
        {
            this.initializationIncomplete = true; 
        }

        internal void MarkCanceled()
        { 
            Fx.Assert(this.substate == Substate.Executing || this.substate == Substate.Canceling, "called from an unexpected state");
            this.substate = Substate.Canceling; 
        } 

        void MarkExecuted() 
        {
            this.substate = Substate.Executing;
        }
 
        internal void MarkAsComplete(BookmarkScopeManager bookmarkScopeManager, BookmarkManager bookmarkManager)
        { 
            if (this.extendedData != null) 
            {
                this.extendedData.PurgeBookmarks(bookmarkScopeManager, bookmarkManager, this); 

                if (this.extendedData.DataContext != null)
                {
                    this.extendedData.DataContext.Dispose(); 
                }
            } 
 
            if (this.instanceMap != null)
            { 
                this.instanceMap.RemoveEntry(this);

                if (this.HasActivityReferences)
                { 
                    this.extendedData.PurgeActivityReferences(this.instanceMap);
                } 
            } 

            if (this.Parent != null) 
            {
                this.Parent.RemoveChild(this);
            }
        } 

        internal void Abort(ActivityExecutor executor, BookmarkManager bookmarkManager, Exception terminationReason, bool isTerminate) 
        { 
            // This is a gentle abort where we try to keep the runtime in a
            // usable state. 
            AbortEnumerator abortEnumerator = new AbortEnumerator(this);

            while (abortEnumerator.MoveNext())
            { 
                ActivityInstance currentInstance = abortEnumerator.Current;
 
                if (!currentInstance.HasNotExecuted) 
                {
                    currentInstance.Activity.InternalAbort(currentInstance, executor, terminationReason); 
                    executor.DebugActivityCompleted(this);
                }

                if (currentInstance.PropertyManager != null) 
                {
                    currentInstance.PropertyManager.UnregisterProperties(currentInstance, currentInstance.Activity.MemberOf, true); 
                } 

                executor.TerminateSpecialExecutionBlocks(currentInstance, terminationReason); 

                executor.CancelPendingOperation(currentInstance);

                executor.HandleRootCompletion(currentInstance); 

                currentInstance.MarkAsComplete(executor.RawBookmarkScopeManager, bookmarkManager); 
 
                currentInstance.state = ActivityInstanceState.Faulted;
 
                currentInstance.FinalizeState(executor, false, !isTerminate);
            }
        }
 
        internal void BaseCancel(NativeActivityContext context)
        { 
            // Default cancelation logic starts here, but is also performed in 
            // UpdateState and through special completion work items
 
            Fx.Assert(this.IsCancellationRequested, "This should be marked to true at this point.");

            this.performingDefaultCancelation = true;
 
            CancelChildren(context);
        } 
 
        internal void CancelChildren(NativeActivityContext context)
        { 
            if (this.HasChildren)
            {
                foreach (ActivityInstance child in this.GetChildren())
                { 
                    context.CancelChild(child);
                } 
            } 
        }
 
        internal void Cancel(ActivityExecutor executor, BookmarkManager bookmarkManager)
        {
            this.Activity.InternalCancel(this, executor, bookmarkManager);
        } 

        internal void Execute(ActivityExecutor executor, BookmarkManager bookmarkManager) 
        { 
            if (this.initializationIncomplete)
            { 
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.InitializationIncomplete));
            }

            MarkExecuted(); 
            this.Activity.InternalExecute(this, executor, bookmarkManager);
        } 
 
        internal void AddChild(ActivityInstance item)
        { 
            if (this.childList == null)
            {
                this.childList = new ChildList();
            } 

            this.childList.Add(item); 
            this.childCache = null; 
        }
 
        internal void RemoveChild(ActivityInstance item)
        {
            Fx.Assert(this.childList != null, "");
            this.childList.Remove(item, true); 
            this.childCache = null;
        } 
 
        // called by ActivityUtilities tree-walk
        internal void AppendChildren(ActivityUtilities.TreeProcessingList nextInstanceList, ref Queue> instancesRemaining) 
        {
            Fx.Assert(this.HasChildren, "AppendChildren is tuned to only be called when HasChildren is true");
            this.childList.AppendChildren(nextInstanceList, ref instancesRemaining);
        } 

        // called after deserialization of the workflow instance 
        internal void FixupInstance(ActivityInstance parent, ActivityInstanceMap instanceMap, ActivityExecutor executor) 
        {
            if (this.IsCompleted) 
            {
                // We hang onto the root instance even after is it complete.  We skip the fixups
                // for a completed root.
                Fx.Assert(parent == null, "This should only happen to root instances."); 

                return; 
            } 

            if (this.Activity == null) 
            {
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.ActivityInstanceFixupFailed));
            }
 
            this.parent = parent;
            this.instanceMap = instanceMap; 
 
            if (this.PropertyManager != null)
            { 
                this.PropertyManager.OnDeserialized(this, parent, this.Activity.MemberOf, executor);
            }
            else if (this.parent != null)
            { 
                // The current property manager is null here
                this.PropertyManager = this.parent.PropertyManager; 
            } 
            else
            { 
                this.PropertyManager = executor.RootPropertyManager;
            }

            if (!this.noSymbols) 
            {
                this.environment.OnDeserialized(executor, this); 
            } 
        }
 
        internal bool TryFixupChildren(ActivityInstanceMap instanceMap, ActivityExecutor executor)
        {
            if (!this.HasChildren)
            { 
                return false;
            } 
 
            this.childList.FixupList(this, instanceMap, executor);
            return true; 
        }

        internal void FillInstanceMap(ActivityInstanceMap instanceMap)
        { 
            if (this.IsCompleted)
            { 
                // We don't bother adding completed roots to the map 
                return;
            } 

            Fx.Assert(this.instanceMap == null, "We should never call this unless the current map is null.");
            Fx.Assert(this.Parent == null, "Can only generate a map from a root instance.");
 
            this.instanceMap = instanceMap;
            ActivityUtilities.ProcessActivityInstanceTree(this, null, new Func(GenerateInstanceMapCallback)); 
        } 

        bool GenerateInstanceMapCallback(ActivityInstance instance, ActivityExecutor executor) 
        {
            this.instanceMap.AddEntry(instance);
            instance.instanceMap = this.instanceMap;
 
            if (instance.HasActivityReferences)
            { 
                instance.extendedData.FillInstanceMap(instance.instanceMap); 
            }
 
            return true;
        }

        internal bool Initialize(ActivityInstance parent, ActivityInstanceMap instanceMap, LocationEnvironment parentEnvironment, long instanceId, ActivityExecutor executor) 
        {
            return this.Initialize(parent, instanceMap, parentEnvironment, instanceId, executor, 0); 
        } 

        internal bool Initialize(ActivityInstance parent, ActivityInstanceMap instanceMap, LocationEnvironment parentEnvironment, long instanceId, ActivityExecutor executor, int delegateParameterCount) 
        {
            this.parent = parent;
            this.instanceMap = instanceMap;
            this.id = instanceId; 

            if (this.instanceMap != null) 
            { 
                this.instanceMap.AddEntry(this);
            } 

            // propagate necessary information from our parent
            if (this.parent != null)
            { 
                if (this.parent.PropertyManager != null)
                { 
                    this.PropertyManager = this.parent.PropertyManager; 
                }
 
                if (parentEnvironment == null)
                {
                    parentEnvironment = this.parent.Environment;
                } 
            }
 
            int symbolCount = this.Activity.SymbolCount + delegateParameterCount; 

            if (symbolCount == 0) 
            {
                if (parentEnvironment == null)
                {
                    // We create an environment for a root activity that otherwise would not have one 
                    // to simplify environment management.
                    this.environment = new LocationEnvironment(executor, this.Activity); 
                } 
                else
                { 
                    this.noSymbols = true;
                    this.environment = parentEnvironment;
                }
 
                // We don't set Initialized here since the tracking/tracing would be too early
                return false; 
            } 
            else
            { 
                this.environment = new LocationEnvironment(executor, this.Activity, parentEnvironment, symbolCount);
                this.substate = Substate.ResolvingArguments;
                return true;
            } 
        }
 
        // return true if arguments were resolved synchronously 
        internal bool ResolveArguments(ActivityExecutor executor, IDictionary argumentValueOverrides, Location resultLocation, int startIndex = 0)
        { 
            Fx.Assert(!this.noSymbols, "Can only resolve arguments if we created an environment");
            Fx.Assert(this.substate == Substate.ResolvingArguments, "Invalid sub-state machine");

            bool completedSynchronously = true; 

            if (this.Activity.SkipArgumentResolution) 
            { 
                // We still need to resolve the result argument
                Fx.Assert(this.Activity is ActivityWithResult, "SkipArgumentResolution is currently only used by ActivityWithResult subclasses"); 
                Fx.Assert(argumentValueOverrides == null, "We shouldn't have any overrides.");
                Fx.Assert(((ActivityWithResult)this.Activity).ResultRuntimeArgument != null, "We should have a result argument");

                ActivityContext resolutionContext = executor.GetResolutionContext(this); 

                try 
                { 
                    RuntimeArgument argument = ((ActivityWithResult)this.Activity).ResultRuntimeArgument;
 
                    if (!argument.TryPopulateValue(this.environment, this, resolutionContext, null, resultLocation, false))
                    {
                        completedSynchronously = false;
 
                        Location location = this.environment.GetSpecificLocation(argument.Id);
                        executor.ScheduleExpression(argument.BoundArgument.Expression, this, resolutionContext.Environment, location.CreateReference(true)); 
                    } 
                }
                finally 
                {
                    resolutionContext.Dispose();
                }
            } 
            else
            { 
                IList runtimeArguments = this.Activity.RuntimeArguments; 

                int argumentCount = runtimeArguments.Count; 

                if (argumentCount > 0)
                {
                    ActivityContext resolutionContext = executor.GetResolutionContext(this); 
                    try
                    { 
                        for (int i = startIndex; i < argumentCount; i++) 
                        {
                            RuntimeArgument argument = runtimeArguments[i]; 

                            object overrideValue = null;
                            if (argumentValueOverrides != null)
                            { 
                                argumentValueOverrides.TryGetValue(argument.Name, out overrideValue);
                            } 
 
                            if (!argument.TryPopulateValue(this.environment, this, resolutionContext, overrideValue, resultLocation, false))
                            { 
                                completedSynchronously = false;

                                //1. Check if there are more arguments to process
                                int nextArgumentIndex = i + 1; 
                                if (nextArgumentIndex < runtimeArguments.Count)
                                { 
                                    // 2. Add a workitem to resume argument resolution when 
                                    // work related to 3 below either completes or it hits an async point.
                                    ResolveNextArgumentWorkItem workItem = executor.ResolveNextArgumentWorkItemPool.Acquire(); 
                                    workItem.Initialize(this, nextArgumentIndex, argumentValueOverrides, resultLocation);

                                    executor.ScheduleItem(workItem);
                                } 

                                // 3. Schedule the argument expression. 
                                Location location = this.environment.GetSpecificLocation(argument.Id); 
                                executor.ScheduleExpression(argument.BoundArgument.Expression, this, resolutionContext.Environment, location.CreateReference(true));
 
                                break;
                            }
                        }
                    } 
                    finally
                    { 
                        resolutionContext.Dispose(); 
                    }
                } 
            }

            if (completedSynchronously && startIndex == 0)
            { 
                // We only move our state machine forward if this
                // is the first call to ResolveArguments (startIndex 
                // == 0).  Otherwise, a call to UpdateState will 
                // cause the substate switch (as well as a call to
                // CollapseTemporaryResolutionLocations). 
                this.substate = Substate.ResolvingVariables;
            }

            return completedSynchronously; 
        }
 
 
        internal bool ResolveVariables(ActivityExecutor executor)
        { 
            Fx.Assert(!this.noSymbols, "can only resolve variables if we created an environment");
            Fx.Assert(this.substate == Substate.ResolvingVariables, "invalid sub-state machine");

            this.substate = Substate.ResolvingVariables; 
            bool completedSynchronously = true;
 
            IList implementationVariables = this.Activity.ImplementationVariables; 
            IList runtimeVariables = this.Activity.RuntimeVariables;
 
            int implementationVariableCount = implementationVariables.Count;
            int runtimeVariableCount = runtimeVariables.Count;

            if (implementationVariableCount > 0 || runtimeVariableCount > 0) 
            {
                ActivityContext resolutionContext = executor.GetResolutionContext(this); 
                try 
                {
                    for (int i = 0; i < implementationVariableCount; i++) 
                    {
                        Variable variable = implementationVariables[i];

                        resolutionContext.Activity = variable.Default; 
                        if (!variable.TryPopulateLocation(executor, resolutionContext))
                        { 
                            // Incomplete initialization detection logic relies on the fact that we 
                            // don't specify a completion callback.  If this changes we need to modify
                            // callers of SetInitializationIncomplete(). 
                            Fx.Assert(variable.Default != null, "If we've gone async we must have a default");
                            Location variableLocation = this.environment.GetSpecificLocation(variable.Id);
                            executor.ScheduleExpression(variable.Default, this, this.environment, variableLocation.CreateReference(true));
                            completedSynchronously = false; 
                        }
                    } 
 
                    for (int i = 0; i < runtimeVariableCount; i++)
                    { 
                        Variable variable = runtimeVariables[i];

                        resolutionContext.Activity = variable.Default;
                        if (!variable.TryPopulateLocation(executor, resolutionContext)) 
                        {
                            // Incomplete initialization detection logic relies on the fact that we 
                            // don't specify a completion callback.  If this changes we need to modify 
                            // callers of SetInitializationIncomplete().
                            Fx.Assert(variable.Default != null, "initial value expression can't be null if we're going async"); 
                            Location variableLocation = this.environment.GetSpecificLocation(variable.Id);
                            executor.ScheduleExpression(variable.Default, this, this.environment, variableLocation.CreateReference(true));
                            completedSynchronously = false;
                        } 
                    }
                } 
                finally 
                {
                    resolutionContext.Dispose(); 
                }
            }

            return completedSynchronously; 
        }
 
        void ActivityInstanceMap.IActivityReference.Load(Activity activity, ActivityInstanceMap instanceMap) 
        {
            if (activity.GetType().Name != this.OwnerName) 
            {
                throw FxTrace.Exception.AsError(
                    new ValidationException(SR.ActivityTypeMismatch(activity.DisplayName, this.OwnerName)));
            } 

            this.Activity = activity; 
        } 

        // Returns true if the activity completed 
        internal bool UpdateState(ActivityExecutor executor)
        {
            bool activityCompleted = false;
 
            if (this.HasNotExecuted)
            { 
                if (this.IsCancellationRequested) // need to cancel any in-flight resolutions and bail 
                {
                    if (this.HasChildren) 
                    {
                        foreach (ActivityInstance child in this.GetChildren())
                        {
                            Fx.Assert(child.State == ActivityInstanceState.Executing, "should only have children if they're still executing"); 
                            executor.CancelActivity(child);
                        } 
                    } 
                    else
                    { 
                        SetCanceled();
                        activityCompleted = true;
                    }
                } 
                else if (!this.HasPendingWork)
                { 
                    bool scheduleBody = false; 

                    if (this.substate == Substate.ResolvingArguments) 
                    {
                        // if we've had asynchronous resolution of Locations (Out/InOut Arguments), resolve them now
                        this.Environment.CollapseTemporaryResolutionLocations();
 
                        this.substate = Substate.ResolvingVariables;
                        scheduleBody = ResolveVariables(executor); 
                    } 
                    else if (this.substate == Substate.ResolvingVariables)
                    { 
                        scheduleBody = true;
                    }

                    if (scheduleBody) 
                    {
                        executor.ScheduleBody(this, false, null, null); 
                    } 
                }
 
                Fx.Assert(this.HasPendingWork || activityCompleted, "should have scheduled work pending if we're not complete");
            }
            else if (!this.HasPendingWork)
            { 
                if (!executor.IsCompletingTransaction(this))
                { 
                    activityCompleted = true; 
                    if (this.substate == Substate.Canceling)
                    { 
                        SetCanceled();
                    }
                    else
                    { 
                        SetClosed();
                    } 
                } 
            }
            else if (this.performingDefaultCancelation) 
            {
                if (this.OnlyHasOutstandingBookmarks)
                {
                    RemoveAllBookmarks(executor.RawBookmarkScopeManager, executor.RawBookmarkManager); 
                    MarkCanceled();
 
                    Fx.Assert(!this.HasPendingWork, "Shouldn't have pending work here."); 

                    SetCanceled(); 
                    activityCompleted = true;
                }
            }
 
            return activityCompleted;
        } 
 
        void TryCancelParent()
        { 
            if (this.parent != null && this.parent.IsPerformingDefaultCancelation)
            {
                this.parent.MarkCanceled();
            } 
        }
 
        internal void SetInitializedSubstate(ActivityExecutor executor) 
        {
            Fx.Assert(this.substate != Substate.Initialized, "SetInitializedSubstate called when substate is already Initialized."); 
            this.substate = Substate.Initialized;
            if (executor.ShouldTrackActivityStateRecordsExecutingState)
            {
                if (executor.ShouldTrackActivity(this.Activity.DisplayName)) 
                {
                    executor.AddTrackingRecord(new ActivityStateRecord(executor.WorkflowInstanceId, this, this.state)); 
                } 
            }
 
            if (this.Activity.RuntimeArguments.Count > 0 && TD.InArgumentBoundIsEnabled())
            {
                for (int i = 0; i < this.Activity.RuntimeArguments.Count; i++)
                { 
                    RuntimeArgument argument = this.Activity.RuntimeArguments[i];
 
                    if (ArgumentDirectionHelper.IsIn(argument.Direction)) 
                    {
                        Location location; 
                        if (this.environment.TryGetLocation(argument.Id, this.Activity, out location))
                        {
                            string argumentValue = null;
 
                            if (location.Value == null)
                            { 
                                argumentValue = ""; 
                            }
                            else 
                            {
                                argumentValue = "'" + location.Value.ToString() + "'";
                            }
 
                            TD.InArgumentBound(argument.Name, this.Activity.GetType().ToString(), this.Activity.DisplayName, this.Id, argumentValue);
                        } 
                    } 
                }
            } 
        }

        internal void FinalizeState(ActivityExecutor executor, bool faultActivity)
        { 
            FinalizeState(executor, faultActivity, false);
        } 
 
        internal void FinalizeState(ActivityExecutor executor, bool faultActivity, bool skipTracking)
        { 
            if (faultActivity)
            {
                TryCancelParent();
 
                // We can override previous completion states with this
                this.state = ActivityInstanceState.Faulted; 
            } 

            Fx.Assert(this.state != ActivityInstanceState.Executing, "We must be in a completed state at this point."); 

            if (this.state == ActivityInstanceState.Closed)
            {
                if (executor.ShouldTrackActivityStateRecordsClosedState && !skipTracking) 
                {
                    if (executor.ShouldTrackActivity(this.Activity.DisplayName)) 
                    { 
                        executor.AddTrackingRecord(new ActivityStateRecord(executor.WorkflowInstanceId, this, this.state));
                    } 
                }
            }
            else
            { 
                if (executor.ShouldTrackActivityStateRecords && !skipTracking)
                { 
                    executor.AddTrackingRecord(new ActivityStateRecord(executor.WorkflowInstanceId, this, this.state)); 
                }
            } 

            if (TD.ActivityCompletedIsEnabled())
            {
                TD.ActivityCompleted(this.Activity.GetType().ToString(), this.Activity.DisplayName, this.Id, this.State.ToString()); 
            }
 
        } 

        void SetCanceled() 
        {
            Fx.Assert(!this.IsCompleted, "Should not be completed if we are changing the state.");

            TryCancelParent(); 

            this.state = ActivityInstanceState.Canceled; 
        } 

        void SetClosed() 
        {
            Fx.Assert(!this.IsCompleted, "Should not be completed if we are changing the state.");

            this.state = ActivityInstanceState.Closed; 
        }
 
        enum Substate : byte 
        {
            Executing = 0, // choose the most common persist-time state for the default 
            PreExecuting = 0x80, // used for all states prior to "core execution"
            Created = 1 | Substate.PreExecuting,
            ResolvingArguments = 2 | Substate.PreExecuting,
            // ResolvedArguments = 2, 
            ResolvingVariables = 3 | Substate.PreExecuting,
            // ResolvedVariables = 3, 
            Initialized = 4 | Substate.PreExecuting, 
            Canceling = 5,
        } 

        // data necessary to support non-mainline usage of instances (i.e. creating bookmarks, using transactions)
        [DataContract]
        class ExtendedData 
        {
            BookmarkList bookmarks; 
            ActivityReferenceList activityReferences; 

            public ExtendedData() 
            {
            }

            [DataMember(Name = XD.ActivityInstance.BlockingBookmarkCount, EmitDefaultValue = false)] 
            public int BlockingBookmarkCount
            { 
                get; 
                private set;
            } 

            [DataMember(Name = XD.ActivityInstance.WaitingForTransactionContext, EmitDefaultValue = false)]
            public bool WaitingForTransactionContext
            { 
                get;
                set; 
            } 

            [DataMember(Name = XD.ActivityInstance.FaultBookmark, EmitDefaultValue = false)] 
            public FaultBookmark FaultBookmark
            {
                get;
                set; 
            }
 
            public WorkflowDataContext DataContext 
            {
                get; 
                set;
            }

            [DataMember(Name = XD.ActivityInstance.Bookmarks, EmitDefaultValue = false)] 
            [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode, Justification = "Called from Serialization")]
            BookmarkList Bookmarks 
            { 
                get
                { 
                    if (this.bookmarks == null || this.bookmarks.Count == 0)
                    {
                        return null;
                    } 
                    else
                    { 
                        return this.bookmarks; 
                    }
                } 
                set
                {
                    Fx.Assert(value != null, "We don't emit the default value so this should never be null.");
                    this.bookmarks = value; 
                }
            } 
 
            [DataMember(Name = XD.ActivityInstance.ActivityReferences, EmitDefaultValue = false)]
            [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode, Justification = "Called from Serialization")] 
            ActivityReferenceList ActivityReferences
            {
                get
                { 
                    if (this.activityReferences == null || this.activityReferences.Count == 0)
                    { 
                        return null; 
                    }
                    else 
                    {
                        return this.activityReferences;
                    }
                } 
                set
                { 
                    Fx.Assert(value != null && value.Count > 0, "We shouldn't emit the default value or empty lists"); 
                    this.activityReferences = value;
                } 
            }

            public bool HasActivityReferences
            { 
                get
                { 
                    return this.activityReferences != null && this.activityReferences.Count > 0; 
                }
            } 

            public void AddBookmark(Bookmark bookmark, bool affectsBusyCount)
            {
                if (this.bookmarks == null) 
                {
                    this.bookmarks = new BookmarkList(); 
                } 

                if (affectsBusyCount) 
                {
                    this.BlockingBookmarkCount = this.BlockingBookmarkCount + 1;
                }
 
                this.bookmarks.Add(bookmark);
            } 
 
            public void RemoveBookmark(Bookmark bookmark, bool affectsBusyCount)
            { 
                Fx.Assert(this.bookmarks != null, "The bookmark list should have been initialized if we are trying to remove one.");

                if (affectsBusyCount)
                { 
                    Fx.Assert(this.BlockingBookmarkCount > 0, "We should never decrement below zero.");
 
                    this.BlockingBookmarkCount = this.BlockingBookmarkCount - 1; 
                }
 
                this.bookmarks.Remove(bookmark);
            }

            public void PurgeBookmarks(BookmarkScopeManager bookmarkScopeManager, BookmarkManager bookmarkManager, ActivityInstance owningInstance) 
            {
                if (this.bookmarks != null) 
                { 
                    if (this.bookmarks.Count > 0)
                    { 
                        Bookmark singleBookmark;
                        IList multipleBookmarks;
                        this.bookmarks.TransferBookmarks(out singleBookmark, out multipleBookmarks);
                        this.bookmarks = null; 

                        if (bookmarkScopeManager != null) 
                        { 
                            bookmarkScopeManager.PurgeBookmarks(bookmarkManager, singleBookmark, multipleBookmarks);
                        } 
                        else
                        {
                            bookmarkManager.PurgeBookmarks(singleBookmark, multipleBookmarks);
                        } 

                        // Clean up the busy count 
                        owningInstance.DecrementBusyCount(this.BlockingBookmarkCount); 
                        this.BlockingBookmarkCount = 0;
                    } 
                }
            }

            public void AddActivityReference(ActivityInstanceReference reference) 
            {
                if (this.activityReferences == null) 
                { 
                    this.activityReferences = new ActivityReferenceList();
                } 

                this.activityReferences.Add(reference);
            }
 
            public void FillInstanceMap(ActivityInstanceMap instanceMap)
            { 
                Fx.Assert(this.HasActivityReferences, "Must have references to have called this."); 

                this.activityReferences.FillInstanceMap(instanceMap); 
            }

            public void PurgeActivityReferences(ActivityInstanceMap instanceMap)
            { 
                Fx.Assert(this.HasActivityReferences, "Must have references to have called this.");
 
                this.activityReferences.PurgeActivityReferences(instanceMap); 
            }
 
            [DataContract]
            class ActivityReferenceList : HybridCollection
            {
                public ActivityReferenceList() 
                    : base()
                { 
                } 

                public void FillInstanceMap(ActivityInstanceMap instanceMap) 
                {
                    Fx.Assert(this.Count > 0, "Should only call this when we have items");

                    if (this.SingleItem != null) 
                    {
                        instanceMap.AddEntry(this.SingleItem); 
                    } 
                    else
                    { 
                        for (int i = 0; i < this.MultipleItems.Count; i++)
                        {
                            ActivityInstanceReference reference = this.MultipleItems[i];
 
                            instanceMap.AddEntry(reference);
                        } 
                    } 
                }
 
                public void PurgeActivityReferences(ActivityInstanceMap instanceMap)
                {
                    Fx.Assert(this.Count > 0, "Should only call this when we have items");
 
                    if (this.SingleItem != null)
                    { 
                        instanceMap.RemoveEntry(this.SingleItem); 
                    }
                    else 
                    {
                        for (int i = 0; i < this.MultipleItems.Count; i++)
                        {
                            instanceMap.RemoveEntry(this.MultipleItems[i]); 
                        }
                    } 
                } 
            }
        } 

        [DataContract]
        class ChildList : HybridCollection
        { 
            static ReadOnlyCollection emptyChildren;
 
            public ChildList() 
                : base()
            { 
            }

            public static ReadOnlyCollection Empty
            { 
                get
                { 
                    if (emptyChildren == null) 
                    {
                        emptyChildren = new ReadOnlyCollection(new ActivityInstance[0]); 
                    }

                    return emptyChildren;
                } 
            }
 
            public void AppendChildren(ActivityUtilities.TreeProcessingList nextInstanceList, ref Queue> instancesRemaining) 
            {
                // This is only called if there is at least one item in the list. 

                if (base.SingleItem != null)
                {
                    nextInstanceList.Add(base.SingleItem); 
                }
                else if (nextInstanceList.Count == 0) 
                { 
                    nextInstanceList.Set(base.MultipleItems);
                } 
                else
                {
                    // Next instance list already has some stuff and we have multiple
                    // items.  Let's enqueue them for later processing. 

                    if (instancesRemaining == null) 
                    { 
                        instancesRemaining = new Queue>();
                    } 

                    instancesRemaining.Enqueue(base.MultipleItems);
                }
            } 

            public void FixupList(ActivityInstance parent, ActivityInstanceMap instanceMap, ActivityExecutor executor) 
            { 
                if (base.SingleItem != null)
                { 
                    base.SingleItem.FixupInstance(parent, instanceMap, executor);
                }
                else
                { 
                    for (int i = 0; i < base.MultipleItems.Count; i++)
                    { 
                        base.MultipleItems[i].FixupInstance(parent, instanceMap, executor); 
                    }
                } 
            }
        }

        // Does a depth first walk and uses some knowledge of 
        // the abort process to determine which child to visit next
        class AbortEnumerator : IEnumerator 
        { 
            ActivityInstance root;
            ActivityInstance current; 

            bool initialized;

            public AbortEnumerator(ActivityInstance root) 
            {
                this.root = root; 
            } 

            public ActivityInstance Current 
            {
                get
                {
                    return this.current; 
                }
            } 
 
            object IEnumerator.Current
            { 
                get
                {
                    return this.Current;
                } 
            }
 
            public bool MoveNext() 
            {
                if (!this.initialized) 
                {
                    this.current = root;

                    // We start by diving down the tree along the 
                    // "first child" path
                    while (this.current.HasChildren) 
                    { 
                        this.current = this.current.GetChildren()[0];
                    } 

                    this.initialized = true;

                    return true; 
                }
                else 
                { 
                    if (this.current == this.root)
                    { 
                        // We're done if we returned all the way to the root last time
                        return false;
                    }
                    else 
                    {
                        Fx.Assert(!this.current.Parent.GetChildren().Contains(this.current), "We should always have removed the current one from the parent's list by now."); 
 
                        this.current = this.current.Parent;
 
                        // Dive down the tree of remaining first children
                        while (this.current.HasChildren)
                        {
                            this.current = this.current.GetChildren()[0]; 
                        }
 
                        return true; 
                    }
                } 
            }

            public void Reset()
            { 
                this.current = null;
                this.initialized = false; 
            } 

            public void Dispose() 
            {
                // no op
            }
        } 
    }
} 

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