e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
465 lines
19 KiB
C#
465 lines
19 KiB
C#
#pragma warning disable 1634, 1691
|
|
|
|
namespace System.Workflow.ComponentModel
|
|
{
|
|
#region Imports
|
|
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Workflow.ComponentModel.Design;
|
|
using System.Runtime.Serialization;
|
|
using System.IO;
|
|
using System.Runtime.Serialization.Formatters.Binary;
|
|
using System.Workflow.ComponentModel.Serialization;
|
|
#endregion
|
|
|
|
[Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")]
|
|
public sealed class ActivityExecutionContextManager
|
|
{
|
|
#region Data members and constructor
|
|
|
|
private ActivityExecutionContext ownerContext = null;
|
|
private List<ActivityExecutionContext> executionContexts = new List<ActivityExecutionContext>();
|
|
|
|
internal ActivityExecutionContextManager(ActivityExecutionContext ownerContext)
|
|
{
|
|
this.ownerContext = ownerContext;
|
|
|
|
// Populate the child collection.
|
|
IList<Activity> activeContexts = (IList<Activity>)this.ownerContext.Activity.ContextActivity.GetValue(Activity.ActiveExecutionContextsProperty);
|
|
if (activeContexts != null)
|
|
{
|
|
foreach (Activity activeContextActivity in activeContexts)
|
|
this.executionContexts.Add(new ActivityExecutionContext(activeContextActivity));
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public members
|
|
|
|
public ReadOnlyCollection<ActivityExecutionContext> ExecutionContexts
|
|
{
|
|
get
|
|
{
|
|
if (this.ownerContext == null)
|
|
#pragma warning suppress 56503
|
|
throw new ObjectDisposedException("ActivityExecutionContextManager");
|
|
|
|
return new ReadOnlyCollection<ActivityExecutionContext>(this.executionContexts);
|
|
}
|
|
}
|
|
|
|
public ActivityExecutionContext CreateExecutionContext(Activity activity)
|
|
{
|
|
if (this.ownerContext == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContextManager");
|
|
|
|
if (activity == null)
|
|
throw new ArgumentNullException("activity");
|
|
|
|
if (!this.ownerContext.IsValidChild(activity, true))
|
|
throw new ArgumentException(SR.GetString(SR.AEC_InvalidActivity), "activity");
|
|
|
|
Activity copiedActivity = activity.Clone();
|
|
((IDependencyObjectAccessor)copiedActivity).InitializeInstanceForRuntime(this.ownerContext.Activity.WorkflowCoreRuntime);
|
|
|
|
//Reset the cloned tree for execution.
|
|
Queue<Activity> activityQueue = new Queue<Activity>();
|
|
activityQueue.Enqueue(copiedActivity);
|
|
|
|
while (activityQueue.Count != 0)
|
|
{
|
|
Activity clonedActivity = activityQueue.Dequeue();
|
|
if (clonedActivity.ExecutionStatus != ActivityExecutionStatus.Initialized)
|
|
{
|
|
clonedActivity.ResetAllKnownDependencyProperties();
|
|
CompositeActivity compositeActivity = clonedActivity as CompositeActivity;
|
|
|
|
if (compositeActivity != null)
|
|
{
|
|
for (int i = 0; i < compositeActivity.EnabledActivities.Count; ++i)
|
|
{
|
|
activityQueue.Enqueue(compositeActivity.EnabledActivities[i]);
|
|
}
|
|
|
|
ISupportAlternateFlow alternateFlow = compositeActivity as ISupportAlternateFlow;
|
|
|
|
if (alternateFlow != null)
|
|
{
|
|
for (int i = 0; i < alternateFlow.AlternateFlowActivities.Count; ++i)
|
|
{
|
|
activityQueue.Enqueue(alternateFlow.AlternateFlowActivities[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// get active context activities and add it to this one
|
|
IList<Activity> activeContexts = (IList<Activity>)this.ownerContext.Activity.ContextActivity.GetValue(Activity.ActiveExecutionContextsProperty);
|
|
if (activeContexts == null)
|
|
{
|
|
activeContexts = new List<Activity>();
|
|
this.ownerContext.Activity.ContextActivity.SetValue(Activity.ActiveExecutionContextsProperty, activeContexts);
|
|
}
|
|
activeContexts.Add(copiedActivity);
|
|
|
|
// prepare the copied activity as a context activity
|
|
ActivityExecutionContextInfo contextInfo = new ActivityExecutionContextInfo(activity.QualifiedName, this.ownerContext.WorkflowCoreRuntime.GetNewContextActivityId(), Guid.NewGuid(), this.ownerContext.ContextId);
|
|
copiedActivity.SetValue(Activity.ActivityExecutionContextInfoProperty, contextInfo);
|
|
copiedActivity.SetValue(Activity.ActivityContextGuidProperty, contextInfo.ContextGuid);
|
|
ActivityExecutionContext newExecutionContext = null;
|
|
try
|
|
{
|
|
// inform workflow runtime
|
|
this.ownerContext.Activity.WorkflowCoreRuntime.RegisterContextActivity(copiedActivity);
|
|
|
|
// return the new context
|
|
newExecutionContext = new ActivityExecutionContext(copiedActivity);
|
|
this.executionContexts.Add(newExecutionContext);
|
|
newExecutionContext.InitializeActivity(newExecutionContext.Activity);
|
|
return newExecutionContext;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
if (newExecutionContext != null)
|
|
{
|
|
this.CompleteExecutionContext(newExecutionContext);
|
|
}
|
|
else
|
|
{
|
|
activeContexts.Remove(copiedActivity);
|
|
}
|
|
throw;
|
|
}
|
|
}
|
|
|
|
public void CompleteExecutionContext(ActivityExecutionContext childContext)
|
|
{
|
|
if (this.ownerContext == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContextManager");
|
|
|
|
CompleteExecutionContext(childContext, false);
|
|
}
|
|
|
|
public void CompleteExecutionContext(ActivityExecutionContext childContext, bool forcePersist)
|
|
{
|
|
if (this.ownerContext == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContextManager");
|
|
|
|
if (childContext == null)
|
|
throw new ArgumentNullException("childContext");
|
|
|
|
if (childContext.Activity == null)
|
|
throw new ArgumentException("childContext", SR.GetString(SR.Error_MissingActivityProperty));
|
|
|
|
if (childContext.Activity.ContextActivity == null)
|
|
throw new ArgumentException("childContext", SR.GetString(SR.Error_MissingContextActivityProperty));
|
|
|
|
if (!this.executionContexts.Contains(childContext))
|
|
throw new ArgumentException();
|
|
|
|
if (childContext.Activity.ContextActivity.ExecutionStatus != ActivityExecutionStatus.Closed && childContext.Activity.ContextActivity.ExecutionStatus != ActivityExecutionStatus.Initialized)
|
|
throw new InvalidOperationException(SR.GetString(System.Globalization.CultureInfo.CurrentCulture, SR.Error_CannotCompleteContext));
|
|
|
|
// make sure that this is in the active contexts collections
|
|
ActivityExecutionContextInfo childContextInfo = childContext.Activity.ContextActivity.GetValue(Activity.ActivityExecutionContextInfoProperty) as ActivityExecutionContextInfo;
|
|
IList<Activity> activeContexts = (IList<Activity>)this.ownerContext.Activity.ContextActivity.GetValue(Activity.ActiveExecutionContextsProperty);
|
|
if (activeContexts == null || !activeContexts.Contains(childContext.Activity.ContextActivity))
|
|
throw new ArgumentException();
|
|
|
|
// add it to completed contexts collection
|
|
bool needsCompensation = childContext.Activity.NeedsCompensation;
|
|
if (needsCompensation || forcePersist)
|
|
{
|
|
// add it to completed contexts
|
|
List<ActivityExecutionContextInfo> completedContexts = this.ownerContext.Activity.ContextActivity.GetValue(Activity.CompletedExecutionContextsProperty) as List<ActivityExecutionContextInfo>;
|
|
if (completedContexts == null)
|
|
{
|
|
completedContexts = new List<ActivityExecutionContextInfo>();
|
|
this.ownerContext.Activity.ContextActivity.SetValue(Activity.CompletedExecutionContextsProperty, completedContexts);
|
|
}
|
|
|
|
if (needsCompensation)
|
|
childContextInfo.Flags = PersistFlags.NeedsCompensation;
|
|
if (forcePersist)
|
|
childContextInfo.Flags |= PersistFlags.ForcePersist;
|
|
|
|
childContextInfo.SetCompletedOrderId(this.ownerContext.Activity.IncrementCompletedOrderId());
|
|
completedContexts.Add(childContextInfo);
|
|
|
|
// ask runtime to save the context activity
|
|
this.ownerContext.Activity.WorkflowCoreRuntime.SaveContextActivity(childContext.Activity);
|
|
}
|
|
|
|
// remove it from active contexts
|
|
activeContexts.Remove(childContext.Activity.ContextActivity);
|
|
this.executionContexts.Remove(childContext);
|
|
|
|
//Case for those context which has compensatable child context, when those context
|
|
//are completed at the end of Compensation chain we need to uninitialize the context
|
|
//activity associated to them.
|
|
if (childContext.Activity.ContextActivity.CanUninitializeNow && childContext.Activity.ContextActivity.ExecutionResult != ActivityExecutionResult.Uninitialized)
|
|
{
|
|
childContext.Activity.ContextActivity.Uninitialize(this.ownerContext.Activity.RootActivity.WorkflowCoreRuntime);
|
|
childContext.Activity.ContextActivity.SetValue(Activity.ExecutionResultProperty, ActivityExecutionResult.Uninitialized);
|
|
}
|
|
|
|
// unregister it from runtime
|
|
this.ownerContext.Activity.WorkflowCoreRuntime.UnregisterContextActivity(childContext.Activity);
|
|
|
|
if (!(needsCompensation || forcePersist))
|
|
{
|
|
childContext.Activity.Dispose();
|
|
}
|
|
}
|
|
|
|
public ActivityExecutionContext GetExecutionContext(Activity activity)
|
|
{
|
|
if (this.ownerContext == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContextManager");
|
|
|
|
if (activity == null)
|
|
throw new ArgumentNullException("activity");
|
|
|
|
ActivityExecutionContextInfo contextInfo = activity.GetValue(Activity.ActivityExecutionContextInfoProperty) as ActivityExecutionContextInfo;
|
|
|
|
// Returns the first context for an activity with the same qualified name.
|
|
foreach (ActivityExecutionContext context in ExecutionContexts)
|
|
{
|
|
if (contextInfo == null) //Template being passed.
|
|
{
|
|
if (context.Activity.ContextActivity.QualifiedName == activity.QualifiedName)
|
|
return context;
|
|
}
|
|
else //Context Sensitive Activity
|
|
{
|
|
if (context.ContextGuid.Equals(contextInfo.ContextGuid))
|
|
return context;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public IEnumerable<Guid> PersistedExecutionContexts
|
|
{
|
|
get
|
|
{
|
|
if (this.ownerContext == null)
|
|
#pragma warning suppress 56503
|
|
throw new ObjectDisposedException("ActivityExecutionContextManager");
|
|
|
|
List<ActivityExecutionContextInfo> completedContexts = this.ownerContext.Activity.ContextActivity.GetValue(Activity.CompletedExecutionContextsProperty) as List<ActivityExecutionContextInfo>;
|
|
completedContexts = (completedContexts == null) ? new List<ActivityExecutionContextInfo>() : completedContexts;
|
|
|
|
List<Guid> persistedContexts = new List<Guid>();
|
|
foreach (ActivityExecutionContextInfo contextInfo in completedContexts)
|
|
if ((contextInfo.Flags & PersistFlags.ForcePersist) != 0)
|
|
persistedContexts.Add(contextInfo.ContextGuid);
|
|
|
|
return persistedContexts;
|
|
}
|
|
}
|
|
|
|
public ActivityExecutionContext GetPersistedExecutionContext(Guid contextGuid)
|
|
{
|
|
if (this.ownerContext == null)
|
|
throw new ObjectDisposedException("ActivityExecutionContextManager");
|
|
|
|
// Check if child execution context exists.
|
|
IList<ActivityExecutionContextInfo> completedContexts = this.ownerContext.Activity.ContextActivity.GetValue(Activity.CompletedExecutionContextsProperty) as IList<ActivityExecutionContextInfo>;
|
|
if (completedContexts == null)
|
|
throw new ArgumentException();
|
|
|
|
ActivityExecutionContextInfo contextInfo = null;
|
|
foreach (ActivityExecutionContextInfo completedContextInfo in completedContexts)
|
|
{
|
|
if (completedContextInfo.ContextGuid == contextGuid && ((completedContextInfo.Flags & PersistFlags.ForcePersist) != 0))
|
|
{
|
|
contextInfo = completedContextInfo;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (contextInfo == null)
|
|
throw new ArgumentException();
|
|
|
|
// The caller would have to close the AEC with forcepersist the next time
|
|
// around.
|
|
contextInfo.Flags &= ~PersistFlags.ForcePersist;
|
|
return DiscardPersistedExecutionContext(contextInfo);
|
|
}
|
|
|
|
#endregion
|
|
|
|
internal void Dispose()
|
|
{
|
|
if (this.ownerContext != null)
|
|
{
|
|
foreach (ActivityExecutionContext executionContext in this.ExecutionContexts)
|
|
((IDisposable)executionContext).Dispose();
|
|
this.ownerContext = null;
|
|
}
|
|
}
|
|
|
|
#region Internal members
|
|
|
|
internal ReadOnlyCollection<ActivityExecutionContextInfo> CompletedExecutionContexts
|
|
{
|
|
get
|
|
{
|
|
List<ActivityExecutionContextInfo> completedContexts = this.ownerContext.Activity.ContextActivity.GetValue(Activity.CompletedExecutionContextsProperty) as List<ActivityExecutionContextInfo>;
|
|
completedContexts = (completedContexts == null) ? new List<ActivityExecutionContextInfo>() : completedContexts;
|
|
return completedContexts.AsReadOnly();
|
|
}
|
|
}
|
|
|
|
internal ActivityExecutionContext DiscardPersistedExecutionContext(ActivityExecutionContextInfo contextInfo)
|
|
{
|
|
if (contextInfo == null)
|
|
throw new ArgumentNullException("contextInfo");
|
|
|
|
// check if child execution context
|
|
IList<ActivityExecutionContextInfo> completedContexts = this.ownerContext.Activity.ContextActivity.GetValue(Activity.CompletedExecutionContextsProperty) as IList<ActivityExecutionContextInfo>;
|
|
if (completedContexts == null || !completedContexts.Contains(contextInfo))
|
|
throw new ArgumentException();
|
|
|
|
// revoke from persistence service
|
|
Activity revokedActivity = this.ownerContext.WorkflowCoreRuntime.LoadContextActivity(contextInfo, this.ownerContext.Activity.ContextActivity.GetActivityByName(contextInfo.ActivityQualifiedName));
|
|
((IDependencyObjectAccessor)revokedActivity).InitializeInstanceForRuntime(this.ownerContext.Activity.WorkflowCoreRuntime);
|
|
|
|
// add it back to active contexts
|
|
IList<Activity> activeContexts = (IList<Activity>)this.ownerContext.Activity.ContextActivity.GetValue(Activity.ActiveExecutionContextsProperty);
|
|
if (activeContexts == null)
|
|
{
|
|
activeContexts = new List<Activity>();
|
|
this.ownerContext.Activity.ContextActivity.SetValue(Activity.ActiveExecutionContextsProperty, activeContexts);
|
|
}
|
|
activeContexts.Add(revokedActivity);
|
|
|
|
// inform workflow runtime
|
|
this.ownerContext.Activity.WorkflowCoreRuntime.RegisterContextActivity(revokedActivity);
|
|
|
|
// return the new context
|
|
ActivityExecutionContext revokedContext = new ActivityExecutionContext(revokedActivity);
|
|
this.executionContexts.Add(revokedContext);
|
|
System.Workflow.Runtime.WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 0, "Revoking context {0}:{1}", revokedContext.ContextId, revokedContext.Activity.ContextActivity.QualifiedName);
|
|
|
|
// remove it from completed contexts
|
|
completedContexts.Remove(contextInfo);
|
|
return revokedContext;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
#region Class ActivityExecutionContextInfo
|
|
|
|
[Serializable]
|
|
[Flags]
|
|
internal enum PersistFlags : byte
|
|
{
|
|
NeedsCompensation = 1,
|
|
ForcePersist = 2
|
|
}
|
|
|
|
[Serializable]
|
|
internal sealed class ActivityExecutionContextInfo
|
|
{
|
|
private string qualifiedID = string.Empty;
|
|
private int contextId = -1;
|
|
private Guid contextGuid = Guid.Empty; //
|
|
private int parentContextId = -1;
|
|
private int completedOrderId = -1;
|
|
private PersistFlags flags = 0;
|
|
|
|
internal ActivityExecutionContextInfo(string qualifiedName, int contextId, Guid contextGuid, int parentContextId)
|
|
{
|
|
this.qualifiedID = qualifiedName;
|
|
this.contextId = contextId;
|
|
this.contextGuid = contextGuid;
|
|
this.parentContextId = parentContextId;
|
|
}
|
|
|
|
internal int ContextId
|
|
{
|
|
get
|
|
{
|
|
return this.contextId;
|
|
}
|
|
}
|
|
|
|
public Guid ContextGuid
|
|
{
|
|
get
|
|
{
|
|
return this.contextGuid;
|
|
}
|
|
}
|
|
|
|
public string ActivityQualifiedName
|
|
{
|
|
get
|
|
{
|
|
return this.qualifiedID;
|
|
}
|
|
}
|
|
|
|
public int CompletedOrderId
|
|
{
|
|
get
|
|
{
|
|
return this.completedOrderId;
|
|
}
|
|
}
|
|
|
|
internal int ParentContextId
|
|
{
|
|
get
|
|
{
|
|
return this.parentContextId;
|
|
}
|
|
}
|
|
|
|
internal void SetCompletedOrderId(int completedOrderId)
|
|
{
|
|
this.completedOrderId = completedOrderId;
|
|
}
|
|
|
|
internal PersistFlags Flags
|
|
{
|
|
get
|
|
{
|
|
return this.flags;
|
|
}
|
|
|
|
set
|
|
{
|
|
this.flags = value;
|
|
}
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return contextGuid.GetHashCode();
|
|
}
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
ActivityExecutionContextInfo otherContextInfo = obj as ActivityExecutionContextInfo;
|
|
|
|
if (otherContextInfo != null)
|
|
{
|
|
return this.ContextGuid.Equals(otherContextInfo.ContextGuid);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|