e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
765 lines
31 KiB
C#
765 lines
31 KiB
C#
#pragma warning disable 1634, 1691
|
|
|
|
namespace System.Workflow.ComponentModel
|
|
{
|
|
#region Imports
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Collections;
|
|
using System.Runtime.Serialization;
|
|
using System.Security.Permissions;
|
|
using System.Diagnostics;
|
|
using System.Workflow.ComponentModel.Design;
|
|
|
|
#endregion
|
|
|
|
[Serializable]
|
|
[Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")]
|
|
public class QueueEventArgs : EventArgs
|
|
{
|
|
IComparable queueName;
|
|
|
|
internal QueueEventArgs(IComparable queueName)
|
|
{
|
|
this.queueName = queueName;
|
|
}
|
|
|
|
public IComparable QueueName
|
|
{
|
|
get
|
|
{
|
|
return this.queueName;
|
|
}
|
|
}
|
|
}
|
|
|
|
[Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")]
|
|
public sealed class ActivityExecutionContext : IServiceProvider, IDisposable
|
|
{
|
|
#region Data members
|
|
|
|
// dependency props
|
|
public static readonly DependencyProperty CurrentExceptionProperty = DependencyProperty.RegisterAttached("CurrentException", typeof(Exception), typeof(ActivityExecutionContext), new PropertyMetadata(null, DependencyPropertyOptions.Default, null, EnforceExceptionSemantics, true));
|
|
internal static readonly DependencyProperty GrantedLocksProperty = DependencyProperty.RegisterAttached("GrantedLocks", typeof(Dictionary<string, GrantedLock>), typeof(ActivityExecutionContext));
|
|
internal static readonly DependencyProperty CachedGrantedLocksProperty = DependencyProperty.RegisterAttached("CachedGrantedLocks", typeof(Dictionary<string, GrantedLock>), typeof(ActivityExecutionContext), new PropertyMetadata(DependencyPropertyOptions.NonSerialized));
|
|
internal static readonly DependencyProperty LockAcquiredCallbackProperty = DependencyProperty.RegisterAttached("LockAcquiredCallback", typeof(ActivityExecutorDelegateInfo<EventArgs>), typeof(ActivityExecutionContext));
|
|
|
|
private Activity currentActivity = null;
|
|
private ActivityExecutionContextManager contextManager = null;
|
|
private IStartWorkflow startWorkflowService = null;
|
|
private bool allowSignalsOnCurrentActivity = false;
|
|
|
|
private static Type schedulerServiceType = Type.GetType("System.Workflow.Runtime.Hosting.WorkflowSchedulerService, " + AssemblyRef.RuntimeAssemblyRef);
|
|
private static Type persistenceServiceType = Type.GetType("System.Workflow.Runtime.Hosting.WorkflowPersistenceService, " + AssemblyRef.RuntimeAssemblyRef);
|
|
private static Type trackingServiceType = Type.GetType("System.Workflow.Runtime.Tracking.TrackingService, " + AssemblyRef.RuntimeAssemblyRef);
|
|
private static Type transactionServiceType = Type.GetType("System.Workflow.Runtime.Hosting.WorkflowCommitWorkBatchService, " + AssemblyRef.RuntimeAssemblyRef);
|
|
private static Type loaderServiceType = Type.GetType("System.Workflow.Runtime.Hosting.WorkflowLoaderService, " + AssemblyRef.RuntimeAssemblyRef);
|
|
|
|
#endregion
|
|
|
|
#region Members
|
|
|
|
internal ActivityExecutionContext(Activity activity)
|
|
{
|
|
this.currentActivity = activity;
|
|
}
|
|
internal ActivityExecutionContext(Activity activity, bool allowSignalsOnCurrentActivity)
|
|
: this(activity)
|
|
{
|
|
// ExecuteActivity/FaultActivity on root activity will be called by the ScheduleExecutor
|
|
// we don't want to do child check in that case, so this flag is just to avoid those checks
|
|
this.allowSignalsOnCurrentActivity = allowSignalsOnCurrentActivity;
|
|
}
|
|
|
|
public Activity Activity
|
|
{
|
|
get
|
|
{
|
|
if (this.currentActivity == null)
|
|
#pragma warning suppress 56503
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
return this.currentActivity;
|
|
}
|
|
}
|
|
|
|
public ActivityExecutionContextManager ExecutionContextManager
|
|
{
|
|
get
|
|
{
|
|
if (this.currentActivity == null)
|
|
#pragma warning suppress 56503
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
if (this.contextManager == null)
|
|
this.contextManager = new ActivityExecutionContextManager(this);
|
|
|
|
return this.contextManager;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region StartWorkflow
|
|
internal sealed class StartWorkflow : IStartWorkflow
|
|
{
|
|
private ActivityExecutionContext executionContext = null;
|
|
internal StartWorkflow(ActivityExecutionContext executionContext)
|
|
{
|
|
this.executionContext = executionContext;
|
|
}
|
|
Guid IStartWorkflow.StartWorkflow(Type workflowType, Dictionary<string, object> namedArgumentValues)
|
|
{
|
|
return this.executionContext.WorkflowCoreRuntime.StartWorkflow(workflowType, namedArgumentValues);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region IServiceProvider methods
|
|
|
|
public T GetService<T>()
|
|
{
|
|
return (T)this.GetService(typeof(T));
|
|
}
|
|
|
|
public Object GetService(Type serviceType)
|
|
{
|
|
if (this.currentActivity == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
if (serviceType == typeof(IStartWorkflow))
|
|
{
|
|
if (this.startWorkflowService == null)
|
|
this.startWorkflowService = new StartWorkflow(this);
|
|
|
|
return this.startWorkflowService;
|
|
}
|
|
else
|
|
{
|
|
if (schedulerServiceType != null && schedulerServiceType.IsAssignableFrom(serviceType))
|
|
return null;
|
|
|
|
if (persistenceServiceType != null && persistenceServiceType.IsAssignableFrom(serviceType))
|
|
return null;
|
|
|
|
if (trackingServiceType != null && trackingServiceType.IsAssignableFrom(serviceType))
|
|
return null;
|
|
|
|
if (transactionServiceType != null && transactionServiceType.IsAssignableFrom(serviceType))
|
|
return null;
|
|
|
|
if (loaderServiceType != null && loaderServiceType.IsAssignableFrom(serviceType))
|
|
return null;
|
|
}
|
|
|
|
return this.currentActivity.WorkflowCoreRuntime.GetService(this.currentActivity, serviceType);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Context Information
|
|
|
|
public Guid ContextGuid
|
|
{
|
|
get
|
|
{
|
|
if (this.currentActivity == null)
|
|
#pragma warning suppress 56503
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
return this.currentActivity.ContextActivity.ContextGuid;
|
|
}
|
|
}
|
|
internal int ContextId
|
|
{
|
|
get
|
|
{
|
|
if (this.currentActivity == null)
|
|
#pragma warning suppress 56503
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
return this.currentActivity.ContextActivity.ContextId;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Activity Execution Signals
|
|
|
|
internal void InitializeActivity(Activity activity)
|
|
{
|
|
if (this.currentActivity == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
if (activity == null)
|
|
throw new ArgumentNullException("activity");
|
|
|
|
if (!IsValidChild(activity, false))
|
|
throw new ArgumentException(SR.GetString(SR.AEC_InvalidActivity), "activity");
|
|
|
|
if (activity.ExecutionStatus != ActivityExecutionStatus.Initialized)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_InvalidInitializingState));
|
|
|
|
using (ActivityExecutionContext executionContext = new ActivityExecutionContext(activity))
|
|
{
|
|
using (this.currentActivity.WorkflowCoreRuntime.SetCurrentActivity(activity))
|
|
activity.Initialize(executionContext);
|
|
}
|
|
}
|
|
public void ExecuteActivity(Activity activity)
|
|
{
|
|
if (this.currentActivity == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
if (activity == null)
|
|
throw new ArgumentNullException("activity");
|
|
|
|
// if this activity is not executing, canceling, faulting OR compensating
|
|
// then it can not execute a child.
|
|
if (!this.allowSignalsOnCurrentActivity &&
|
|
(
|
|
this.currentActivity.WorkflowCoreRuntime.CurrentActivity.ExecutionStatus == ActivityExecutionStatus.Initialized ||
|
|
this.currentActivity.WorkflowCoreRuntime.CurrentActivity.ExecutionStatus == ActivityExecutionStatus.Closed
|
|
)
|
|
)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_InvalidStateToExecuteChild));
|
|
|
|
if (!IsValidChild(activity, false))
|
|
throw new ArgumentException(SR.GetString(SR.AEC_InvalidActivity), "activity");
|
|
|
|
if (activity.ExecutionStatus != ActivityExecutionStatus.Initialized)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_InvalidExecutionState));
|
|
|
|
try
|
|
{
|
|
activity.SetStatus(ActivityExecutionStatus.Executing, false);
|
|
}
|
|
finally
|
|
{
|
|
Debug.Assert(activity.ExecutionStatus == ActivityExecutionStatus.Executing);
|
|
this.currentActivity.WorkflowCoreRuntime.ScheduleItem(new ActivityExecutorOperation(activity, ActivityOperationType.Execute, this.ContextId), IsInAtomicTransaction(activity), false, false);
|
|
}
|
|
}
|
|
public void CancelActivity(Activity activity)
|
|
{
|
|
if (this.currentActivity == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
if (activity == null)
|
|
throw new ArgumentNullException("activity");
|
|
|
|
// if this activity is not executing, canceling, faulting OR compensating
|
|
// then it can not cancel a child.
|
|
if (!this.allowSignalsOnCurrentActivity &&
|
|
(
|
|
this.currentActivity.WorkflowCoreRuntime.CurrentActivity.ExecutionStatus == ActivityExecutionStatus.Initialized ||
|
|
this.currentActivity.WorkflowCoreRuntime.CurrentActivity.ExecutionStatus == ActivityExecutionStatus.Closed
|
|
)
|
|
)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_InvalidStateToExecuteChild));
|
|
|
|
if (!IsValidChild(activity, false))
|
|
throw new ArgumentException(SR.GetString(SR.AEC_InvalidActivity), "activity");
|
|
|
|
if (activity.ExecutionStatus != ActivityExecutionStatus.Executing)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_InvalidCancelingState));
|
|
|
|
try
|
|
{
|
|
activity.SetStatus(ActivityExecutionStatus.Canceling, false);
|
|
}
|
|
finally
|
|
{
|
|
this.currentActivity.WorkflowCoreRuntime.ScheduleItem(new ActivityExecutorOperation(activity, ActivityOperationType.Cancel, this.ContextId), IsInAtomicTransaction(activity), false, false);
|
|
}
|
|
}
|
|
internal void CompensateActivity(Activity activity)
|
|
{
|
|
if (this.currentActivity == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
if (activity == null)
|
|
throw new ArgumentNullException("activity");
|
|
|
|
if (!IsValidNestedChild(activity))
|
|
throw new ArgumentException(SR.GetString(SR.AEC_InvalidNestedActivity), "activity");
|
|
|
|
if (activity.ExecutionStatus != ActivityExecutionStatus.Closed)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_InvalidCompensatingState));
|
|
|
|
try
|
|
{
|
|
activity.SetStatus(ActivityExecutionStatus.Compensating, false);
|
|
}
|
|
finally
|
|
{
|
|
this.currentActivity.WorkflowCoreRuntime.ScheduleItem(new ActivityExecutorOperation(activity, ActivityOperationType.Compensate, this.ContextId), IsInAtomicTransaction(activity), false, false);
|
|
}
|
|
}
|
|
internal void FaultActivity(Exception e)
|
|
{
|
|
if (this.currentActivity == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
// the current activity might have closed, in that case, we would like to give the exception to parent
|
|
if (this.currentActivity.ExecutionStatus == ActivityExecutionStatus.Closed)
|
|
{
|
|
if (this.currentActivity.Parent == null)
|
|
{
|
|
// this could have happened if the root activity closed, but
|
|
// then it threw an exception
|
|
this.currentActivity.WorkflowCoreRuntime.TerminateInstance(e);
|
|
}
|
|
else
|
|
{
|
|
this.currentActivity.WorkflowCoreRuntime.RaiseException(e, this.currentActivity.Parent, string.Empty);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
this.currentActivity.SetValueCommon(CurrentExceptionProperty, e, CurrentExceptionProperty.DefaultMetadata, false);
|
|
this.currentActivity.SetStatus(ActivityExecutionStatus.Faulting, false);
|
|
}
|
|
finally
|
|
{
|
|
this.currentActivity.WorkflowCoreRuntime.ScheduleItem(new ActivityExecutorOperation(this.currentActivity, ActivityOperationType.HandleFault, this.ContextId, e), IsInAtomicTransaction(this.currentActivity), false, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void CloseActivity()
|
|
{
|
|
if (this.currentActivity == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
switch (this.currentActivity.ExecutionStatus)
|
|
{
|
|
case ActivityExecutionStatus.Executing:
|
|
this.currentActivity.MarkCompleted();
|
|
break;
|
|
case ActivityExecutionStatus.Canceling:
|
|
this.currentActivity.MarkCanceled();
|
|
break;
|
|
case ActivityExecutionStatus.Compensating:
|
|
this.currentActivity.MarkCompensated();
|
|
break;
|
|
case ActivityExecutionStatus.Faulting:
|
|
this.currentActivity.MarkFaulted();
|
|
break;
|
|
case ActivityExecutionStatus.Closed:
|
|
break;
|
|
default:
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_InvalidClosingState));
|
|
}
|
|
}
|
|
|
|
internal void Invoke<T>(EventHandler<T> handler, T e) where T : EventArgs
|
|
{
|
|
if (this.currentActivity == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
// let the activity handle it
|
|
this.currentActivity.Invoke(handler, e);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Tracking Method
|
|
|
|
// user tracking
|
|
public void TrackData(object userData)
|
|
{
|
|
if (this.currentActivity == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
if (null == userData)
|
|
throw new ArgumentNullException("userData");
|
|
|
|
this.currentActivity.WorkflowCoreRuntime.Track(null, userData);
|
|
}
|
|
|
|
// user tracking
|
|
public void TrackData(string userDataKey, object userData)
|
|
{
|
|
if (this.currentActivity == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
if (null == userData)
|
|
throw new ArgumentNullException("userData");
|
|
|
|
this.currentActivity.WorkflowCoreRuntime.Track(userDataKey, userData);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Locking methods
|
|
|
|
internal bool AcquireLocks(IActivityEventListener<EventArgs> locksAcquiredCallback)
|
|
{
|
|
if (this.currentActivity == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
this.Activity.SetValue(LockAcquiredCallbackProperty, new ActivityExecutorDelegateInfo<EventArgs>(true, locksAcquiredCallback, this.Activity.ContextActivity));
|
|
return AcquireLocks(this.Activity);
|
|
}
|
|
|
|
private bool AcquireLocks(Activity activity)
|
|
{
|
|
// If this activity doesn't have any handles, we have nothing to do.
|
|
ICollection<string> handles = GetAllSynchronizationHandles(activity);
|
|
if (handles == null || handles.Count == 0)
|
|
return true;
|
|
|
|
Activity parent = activity.Parent;
|
|
while (parent != null)
|
|
{
|
|
if (parent.SupportsSynchronization || parent.Parent == null)
|
|
{
|
|
Dictionary<string, GrantedLock> grantedLocks = (Dictionary<string, GrantedLock>)parent.GetValue(GrantedLocksProperty);
|
|
if (grantedLocks == null)
|
|
{
|
|
grantedLocks = new Dictionary<string, GrantedLock>();
|
|
parent.SetValue(GrantedLocksProperty, grantedLocks);
|
|
}
|
|
foreach (string handle in handles)
|
|
{
|
|
bool acquiredLocks = true;
|
|
if (!grantedLocks.ContainsKey(handle))
|
|
{
|
|
grantedLocks[handle] = new GrantedLock(activity);
|
|
}
|
|
else if (grantedLocks[handle].Holder != activity)
|
|
{
|
|
grantedLocks[handle].WaitList.Add(activity);
|
|
acquiredLocks = false;
|
|
}
|
|
if (!acquiredLocks)
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// If we reach a parent which has at least one handle, then we do not need to
|
|
// go any further as the parent would already have acquired all our locks for
|
|
// itself. Note that we still need to acquire our locks in the same parent if
|
|
// the parent ProvidesSychronization, hence, this if check is *not* after
|
|
// "parent = parent.Parent"!
|
|
ICollection<string> synchronizationHandlesOnParent = (ICollection<string>)parent.GetValue(Activity.SynchronizationHandlesProperty);
|
|
if (synchronizationHandlesOnParent != null && synchronizationHandlesOnParent.Count != 0)
|
|
break;
|
|
|
|
parent = parent.Parent;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
internal void ReleaseLocks(bool transactional)
|
|
{
|
|
if (this.currentActivity == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
|
|
// remove the callback.
|
|
this.Activity.RemoveProperty(LockAcquiredCallbackProperty);
|
|
|
|
// The assumption is that lock contentions will be few. Hence, we optimize serialization
|
|
// size over performance, for ex. do not persist the list of locks that have already been
|
|
// granted.
|
|
ICollection<string> handles = GetAllSynchronizationHandles(this.Activity);
|
|
if (handles == null || handles.Count == 0)
|
|
return;
|
|
|
|
List<Activity> waitingActivities = new List<Activity>();
|
|
Activity parent = Activity.Parent;
|
|
while (parent != null)
|
|
{
|
|
if (parent.SupportsSynchronization || parent.Parent == null)
|
|
{
|
|
Dictionary<string, GrantedLock> grantedLocks = (Dictionary<string, GrantedLock>)parent.GetValue(GrantedLocksProperty);
|
|
|
|
// if its an transactional release of locks, then release it and then keep it
|
|
// cached, so that in case of rollback, we can reacuire locks
|
|
if (transactional)
|
|
{
|
|
Dictionary<string, GrantedLock> cachedGrantedLocks = new Dictionary<string, GrantedLock>();
|
|
|
|
if (grantedLocks != null)
|
|
foreach (KeyValuePair<string, GrantedLock> grantedLockEntry in grantedLocks)
|
|
cachedGrantedLocks.Add(grantedLockEntry.Key, (GrantedLock)grantedLockEntry.Value.Clone());
|
|
|
|
parent.SetValue(CachedGrantedLocksProperty, cachedGrantedLocks);
|
|
}
|
|
|
|
if (grantedLocks != null)
|
|
{
|
|
foreach (string handle in handles)
|
|
{
|
|
if (!grantedLocks.ContainsKey(handle))
|
|
{
|
|
continue;
|
|
}
|
|
else if (grantedLocks[handle].WaitList.Count == 0)
|
|
{
|
|
grantedLocks.Remove(handle);
|
|
}
|
|
else if (grantedLocks[handle].Holder != this.Activity)
|
|
{
|
|
grantedLocks[handle].WaitList.Remove(this.Activity);
|
|
}
|
|
else
|
|
{
|
|
// Grant the lock to the next waiting activity.
|
|
Activity waitingActivity = grantedLocks[handle].WaitList[0];
|
|
grantedLocks[handle].WaitList.RemoveAt(0);
|
|
grantedLocks[handle].Holder = waitingActivity;
|
|
if (!waitingActivities.Contains(waitingActivity))
|
|
waitingActivities.Add(waitingActivity);
|
|
}
|
|
}
|
|
if (grantedLocks.Count == 0)
|
|
parent.RemoveProperty(GrantedLocksProperty);
|
|
}
|
|
}
|
|
|
|
// If we reach a parent which has at least one handle, then we do not need to
|
|
// go any further as the parent would already have acquired all our locks for
|
|
// itself. Note that we still need to acquire our locks in the same parent if
|
|
// the parent ProvidesSychronization, hence, this if check is *not* after
|
|
// "parent = parent.Parent"!
|
|
ICollection<string> synchronizationHandlesOnParent = (ICollection<string>)parent.GetValue(Activity.SynchronizationHandlesProperty);
|
|
if (synchronizationHandlesOnParent != null && synchronizationHandlesOnParent.Count != 0)
|
|
break;
|
|
|
|
parent = parent.Parent;
|
|
}
|
|
|
|
// Try and acquire locks for all the waiting activities.
|
|
foreach (Activity waitingActivity in waitingActivities)
|
|
{
|
|
if (AcquireLocks(waitingActivity))
|
|
{
|
|
ActivityExecutorDelegateInfo<EventArgs> waitingActivityCallback = (ActivityExecutorDelegateInfo<EventArgs>)waitingActivity.GetValue(LockAcquiredCallbackProperty);
|
|
waitingActivityCallback.InvokeDelegate(this.Activity.ContextActivity, EventArgs.Empty, false, transactional);
|
|
}
|
|
}
|
|
}
|
|
|
|
private ICollection<string> GetAllSynchronizationHandles(Activity activity)
|
|
{
|
|
// If the activity doesn't have any handles, do not look at child activities.
|
|
ICollection<string> handleCollection = (ICollection<string>)activity.GetValue(Activity.SynchronizationHandlesProperty);
|
|
if (handleCollection == null || handleCollection.Count == 0)
|
|
return handleCollection;
|
|
|
|
List<string> handles = new List<string>(handleCollection);
|
|
// Collect all child locks and normalize the list.
|
|
if (activity is CompositeActivity)
|
|
{
|
|
Walker walker = new Walker();
|
|
walker.FoundActivity += delegate(Walker w, WalkerEventArgs e)
|
|
{
|
|
if (e.CurrentActivity == activity)
|
|
return;
|
|
|
|
ICollection<string> handlesOnChild = (ICollection<string>)e.CurrentActivity.GetValue(Activity.SynchronizationHandlesProperty);
|
|
if (handlesOnChild != null)
|
|
handles.AddRange(handlesOnChild);
|
|
};
|
|
walker.Walk(activity);
|
|
}
|
|
|
|
// normalize handles
|
|
handles.Sort();
|
|
for (int i = 1; i < handles.Count; i++)
|
|
{
|
|
if (handles[i] == handles[i - 1])
|
|
handles.RemoveAt(--i);
|
|
}
|
|
handles.TrimExcess();
|
|
|
|
// return
|
|
return handles;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Instance Operation Methods
|
|
|
|
internal void SuspendWorkflowInstance(string suspendDescription)
|
|
{
|
|
if (this.currentActivity == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
this.currentActivity.WorkflowCoreRuntime.SuspendInstance(suspendDescription);
|
|
}
|
|
internal void TerminateWorkflowInstance(Exception e)
|
|
{
|
|
if (this.currentActivity == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
if (e == null)
|
|
throw new ArgumentNullException("e");
|
|
|
|
this.currentActivity.WorkflowCoreRuntime.TerminateInstance(e);
|
|
}
|
|
internal void CheckpointInstanceState()
|
|
{
|
|
if (this.currentActivity == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
this.currentActivity.WorkflowCoreRuntime.CheckpointInstanceState(this.currentActivity);
|
|
}
|
|
internal void RequestRevertToCheckpointState(EventHandler<EventArgs> handler, EventArgs data, bool suspendOnRevert, string suspendOnRevertInfo)
|
|
{
|
|
if (this.currentActivity == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
this.currentActivity.WorkflowCoreRuntime.RequestRevertToCheckpointState(this.currentActivity, handler, data, suspendOnRevert, suspendOnRevertInfo);
|
|
}
|
|
internal void DisposeCheckpointState()
|
|
{
|
|
if (this.currentActivity == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
this.currentActivity.WorkflowCoreRuntime.DisposeCheckpointState();
|
|
}
|
|
#endregion
|
|
|
|
#region Helper Methods
|
|
|
|
internal bool IsValidChild(Activity activity, bool allowContextVariance)
|
|
{
|
|
if (this.currentActivity == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
if (activity == this.currentActivity.WorkflowCoreRuntime.CurrentActivity && this.allowSignalsOnCurrentActivity)
|
|
return true;
|
|
|
|
if (activity.Enabled && activity.Parent == this.currentActivity.WorkflowCoreRuntime.CurrentActivity && (allowContextVariance || activity.Equals(this.Activity.GetActivityByName(activity.QualifiedName, true))))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
internal bool IsValidNestedChild(Activity activity)
|
|
{
|
|
if (this.currentActivity == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
if (activity == this.currentActivity)
|
|
return true;
|
|
|
|
Activity parentActivity = activity;
|
|
while (parentActivity != null && parentActivity.Enabled && parentActivity.Parent != this.currentActivity.ContextActivity)
|
|
parentActivity = parentActivity.Parent;
|
|
|
|
return (parentActivity != null && parentActivity.Enabled);
|
|
}
|
|
internal IWorkflowCoreRuntime WorkflowCoreRuntime
|
|
{
|
|
get
|
|
{
|
|
if (this.currentActivity == null)
|
|
#pragma warning suppress 56503
|
|
throw new ObjectDisposedException("ActivityExecutionContext");
|
|
|
|
return this.GetService<IWorkflowCoreRuntime>();
|
|
}
|
|
}
|
|
internal static bool IsInAtomicTransaction(Activity activity)
|
|
{
|
|
bool isInAtomicTransaction = false;
|
|
while (activity != null)
|
|
{
|
|
if (activity == activity.WorkflowCoreRuntime.CurrentAtomicActivity)
|
|
{
|
|
isInAtomicTransaction = true;
|
|
break;
|
|
}
|
|
activity = activity.Parent;
|
|
}
|
|
return isInAtomicTransaction;
|
|
}
|
|
#endregion
|
|
|
|
#region CurrentExceptionProperty Guard
|
|
static void EnforceExceptionSemantics(DependencyObject d, object value)
|
|
{
|
|
Activity activity = d as Activity;
|
|
|
|
if (activity == null)
|
|
throw new ArgumentException(SR.GetString(System.Globalization.CultureInfo.CurrentCulture, SR.Error_DOIsNotAnActivity));
|
|
|
|
if (value != null)
|
|
throw new InvalidOperationException(SR.GetString(System.Globalization.CultureInfo.CurrentCulture, SR.Error_PropertyCanBeOnlyCleared));
|
|
|
|
d.SetValueCommon(CurrentExceptionProperty, null, CurrentExceptionProperty.DefaultMetadata, false);
|
|
}
|
|
#endregion
|
|
|
|
#region IDisposable Members
|
|
|
|
void IDisposable.Dispose()
|
|
{
|
|
if (this.currentActivity != null)
|
|
{
|
|
if (this.contextManager != null)
|
|
{
|
|
this.contextManager.Dispose();
|
|
this.contextManager = null;
|
|
}
|
|
this.currentActivity = null;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
#region Class GrantedLock
|
|
|
|
[Serializable]
|
|
internal class GrantedLock : ICloneable
|
|
{
|
|
private Activity holder;
|
|
private List<Activity> waitList;
|
|
|
|
public GrantedLock(Activity holder)
|
|
{
|
|
this.holder = holder;
|
|
this.waitList = new List<Activity>();
|
|
}
|
|
public Activity Holder
|
|
{
|
|
get
|
|
{
|
|
return this.holder;
|
|
}
|
|
set
|
|
{
|
|
this.holder = value;
|
|
}
|
|
}
|
|
public IList<Activity> WaitList
|
|
{
|
|
get
|
|
{
|
|
return this.waitList;
|
|
}
|
|
}
|
|
|
|
#region ICloneable Members
|
|
|
|
public object Clone()
|
|
{
|
|
GrantedLock clonedGrantedLock = new GrantedLock(this.holder);
|
|
clonedGrantedLock.waitList.InsertRange(0, this.waitList);
|
|
return clonedGrantedLock;
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
}
|