You've already forked linux-packaging-mono
Rewrite with hard-coded offsets into the PE file format to discern if a binary is PE32 or PE32+, and then to determine if it contains a "CLR Data Directory" entry that looks valid. Tested with PE32 and PE32+ compiled Mono binaries, PE32 and PE32+ native binaries, and a random assortment of garbage files. Former-commit-id: 9e7ac86ec84f653a2f79b87183efd5b0ebda001b
2482 lines
108 KiB
C#
2482 lines
108 KiB
C#
#pragma warning disable 1634, 1691
|
|
|
|
namespace System.Workflow.ComponentModel
|
|
{
|
|
#region Imports
|
|
|
|
using System;
|
|
using System.CodeDom;
|
|
using System.CodeDom.Compiler;
|
|
using System.Xml;
|
|
using System.Text;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Collections;
|
|
using System.Runtime.Serialization;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.ComponentModel.Design;
|
|
using System.ComponentModel.Design.Serialization;
|
|
using System.Drawing.Design;
|
|
using System.Workflow.ComponentModel.Design;
|
|
using System.Workflow.ComponentModel.Compiler;
|
|
using System.Resources;
|
|
using System.Globalization;
|
|
using System.Diagnostics;
|
|
using System.Collections.Specialized;
|
|
using System.Collections.ObjectModel;
|
|
using System.Runtime.Serialization.Formatters.Binary;
|
|
using System.Workflow.ComponentModel.Serialization;
|
|
|
|
#endregion
|
|
|
|
#region Classes ActivityResolveEventArgs and WorkflowChangeActionsResolveEventArgs
|
|
|
|
internal delegate Activity ActivityResolveEventHandler(object sender, ActivityResolveEventArgs e);
|
|
internal delegate ArrayList WorkflowChangeActionsResolveEventHandler(object sender, WorkflowChangeActionsResolveEventArgs e);
|
|
|
|
internal sealed class ActivityResolveEventArgs : EventArgs
|
|
{
|
|
private Type activityType = null;
|
|
private string activityDefinition = null;
|
|
private string rulesDefinition = null;
|
|
private bool createNew = false;
|
|
private bool initForRuntime = true;
|
|
private IServiceProvider serviceProvider = null;
|
|
|
|
internal ActivityResolveEventArgs(Type activityType, string workflowMarkup, string rulesMarkup, bool createNew, bool initForRuntime, IServiceProvider serviceProvider)
|
|
{
|
|
if (!(string.IsNullOrEmpty(workflowMarkup) ^ activityType == null))
|
|
throw new ArgumentException(SR.GetString(SR.Error_WrongParamForActivityResolveEventArgs));
|
|
|
|
this.activityType = activityType;
|
|
this.activityDefinition = workflowMarkup;
|
|
this.rulesDefinition = rulesMarkup;
|
|
this.createNew = createNew;
|
|
this.initForRuntime = initForRuntime;
|
|
this.serviceProvider = serviceProvider;
|
|
}
|
|
|
|
public Type Type
|
|
{
|
|
get
|
|
{
|
|
return this.activityType;
|
|
}
|
|
}
|
|
public string WorkflowMarkup
|
|
{
|
|
get
|
|
{
|
|
return this.activityDefinition;
|
|
}
|
|
}
|
|
public string RulesMarkup
|
|
{
|
|
get
|
|
{
|
|
return this.rulesDefinition;
|
|
}
|
|
}
|
|
public bool CreateNewDefinition
|
|
{
|
|
get
|
|
{
|
|
return this.createNew;
|
|
}
|
|
}
|
|
public bool InitializeForRuntime
|
|
{
|
|
get
|
|
{
|
|
return this.initForRuntime;
|
|
}
|
|
}
|
|
public IServiceProvider ServiceProvider
|
|
{
|
|
get
|
|
{
|
|
return this.serviceProvider;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal sealed class WorkflowChangeActionsResolveEventArgs : EventArgs
|
|
{
|
|
private string workflowChangesMarkup;
|
|
|
|
public WorkflowChangeActionsResolveEventArgs(string workflowChangesMarkup)
|
|
{
|
|
this.workflowChangesMarkup = workflowChangesMarkup;
|
|
}
|
|
|
|
public string WorkflowChangesMarkup
|
|
{
|
|
get
|
|
{
|
|
return this.workflowChangesMarkup;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Class Activity
|
|
|
|
|
|
[ActivityCodeGenerator(typeof(ActivityCodeGenerator))]
|
|
[ActivityValidator(typeof(ActivityValidator))]
|
|
[System.Drawing.ToolboxBitmap(typeof(Activity), "Design.Resources.Activity.png")]
|
|
[ToolboxItemFilter("Microsoft.Workflow.VSDesigner", ToolboxItemFilterType.Require)]
|
|
[ToolboxItemFilter("System.Workflow.ComponentModel.Design.ActivitySet", ToolboxItemFilterType.Allow)]
|
|
[DesignerSerializer(typeof(ActivityMarkupSerializer), typeof(WorkflowMarkupSerializer))]
|
|
[DesignerSerializer(typeof(ActivityCodeDomSerializer), typeof(CodeDomSerializer))]
|
|
[DesignerSerializer(typeof(ActivityTypeCodeDomSerializer), typeof(TypeCodeDomSerializer))]
|
|
[DesignerCategory("Component")]
|
|
[ActivityExecutor(typeof(ActivityExecutor<Activity>))]
|
|
[Designer(typeof(ActivityDesigner), typeof(IDesigner))]
|
|
[Designer(typeof(ActivityDesigner), typeof(IRootDesigner))]
|
|
[ToolboxItem(typeof(ActivityToolboxItem))]
|
|
[RuntimeNameProperty("Name")]
|
|
[Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")]
|
|
public class Activity : DependencyObject
|
|
{
|
|
private static DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(Activity), new PropertyMetadata("", DependencyPropertyOptions.Metadata, new ValidationOptionAttribute(ValidationOption.Required)));
|
|
private static DependencyProperty DescriptionProperty = DependencyProperty.Register("Description", typeof(string), typeof(Activity), new PropertyMetadata("", DependencyPropertyOptions.Metadata));
|
|
private static DependencyProperty EnabledProperty = DependencyProperty.Register("Enabled", typeof(bool), typeof(Activity), new PropertyMetadata(true, DependencyPropertyOptions.Metadata));
|
|
private static DependencyProperty QualifiedNameProperty = DependencyProperty.Register("QualifiedName", typeof(string), typeof(Activity), new PropertyMetadata(DependencyPropertyOptions.Metadata | DependencyPropertyOptions.ReadOnly));
|
|
private static DependencyProperty DottedPathProperty = DependencyProperty.Register("DottedPath", typeof(string), typeof(Activity), new PropertyMetadata(DependencyPropertyOptions.Metadata | DependencyPropertyOptions.ReadOnly));
|
|
internal static readonly DependencyProperty WorkflowXamlMarkupProperty = DependencyProperty.Register("WorkflowXamlMarkup", typeof(string), typeof(Activity));
|
|
internal static readonly DependencyProperty WorkflowRulesMarkupProperty = DependencyProperty.Register("WorkflowRulesMarkup", typeof(string), typeof(Activity));
|
|
|
|
internal static readonly DependencyProperty SynchronizationHandlesProperty = DependencyProperty.Register("SynchronizationHandles", typeof(ICollection<String>), typeof(Activity), new PropertyMetadata(DependencyPropertyOptions.Metadata));
|
|
|
|
internal static readonly DependencyProperty ActivityExecutionContextInfoProperty = DependencyProperty.RegisterAttached("ActivityExecutionContextInfo", typeof(ActivityExecutionContextInfo), typeof(Activity));
|
|
public static readonly DependencyProperty ActivityContextGuidProperty = DependencyProperty.RegisterAttached("ActivityContextGuid", typeof(Guid), typeof(Activity), new PropertyMetadata(Guid.Empty));
|
|
internal static readonly DependencyProperty CompletedExecutionContextsProperty = DependencyProperty.RegisterAttached("CompletedExecutionContexts", typeof(IList), typeof(Activity));
|
|
internal static readonly DependencyProperty ActiveExecutionContextsProperty = DependencyProperty.RegisterAttached("ActiveExecutionContexts", typeof(IList), typeof(Activity));
|
|
internal static readonly DependencyProperty CompletedOrderIdProperty = DependencyProperty.Register("CompletedOrderId", typeof(int), typeof(Activity), new PropertyMetadata(new Int32()));
|
|
private static readonly DependencyProperty SerializedStreamLengthProperty = DependencyProperty.RegisterAttached("SerializedStreamLength", typeof(long), typeof(Activity), new PropertyMetadata(DependencyPropertyOptions.NonSerialized));
|
|
|
|
// activity runtime state
|
|
internal static readonly DependencyProperty ExecutionStatusProperty = DependencyProperty.RegisterAttached("ExecutionStatus", typeof(ActivityExecutionStatus), typeof(Activity), new PropertyMetadata(ActivityExecutionStatus.Initialized, new Attribute[] { new BrowsableAttribute(false), new DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden) }));
|
|
internal static readonly DependencyProperty ExecutionResultProperty = DependencyProperty.RegisterAttached("ExecutionResult", typeof(ActivityExecutionResult), typeof(Activity), new PropertyMetadata(ActivityExecutionResult.None, new Attribute[] { new BrowsableAttribute(false), new DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden) }));
|
|
internal static readonly DependencyProperty WasExecutingProperty = DependencyProperty.RegisterAttached("WasExecuting", typeof(bool), typeof(Activity), new PropertyMetadata(false, new Attribute[] { new BrowsableAttribute(false), new DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden) }));
|
|
|
|
// lock count on status change property
|
|
private static readonly DependencyProperty LockCountOnStatusChangeProperty = DependencyProperty.RegisterAttached("LockCountOnStatusChange", typeof(int), typeof(Activity), new PropertyMetadata(new Int32()));
|
|
internal static readonly DependencyProperty HasPrimaryClosedProperty = DependencyProperty.RegisterAttached("HasPrimaryClosed", typeof(bool), typeof(Activity), new PropertyMetadata(false));
|
|
|
|
// nested activity collection used at serialization time
|
|
private static readonly DependencyProperty NestedActivitiesProperty = DependencyProperty.RegisterAttached("NestedActivities", typeof(IList<Activity>), typeof(Activity));
|
|
|
|
// Workflow Definition property, should only be visible to runtime
|
|
internal static readonly DependencyProperty WorkflowDefinitionProperty = DependencyProperty.RegisterAttached("WorkflowDefinition", typeof(Activity), typeof(Activity), new PropertyMetadata(DependencyPropertyOptions.NonSerialized));
|
|
|
|
// Workflow Runtime property, should only be visible to runtime
|
|
internal static readonly DependencyProperty WorkflowRuntimeProperty = DependencyProperty.RegisterAttached("WorkflowRuntime", typeof(IServiceProvider), typeof(Activity), new PropertyMetadata(DependencyPropertyOptions.NonSerialized));
|
|
|
|
[ThreadStatic]
|
|
internal static Hashtable ContextIdToActivityMap = null;
|
|
[ThreadStatic]
|
|
internal static Activity DefinitionActivity = null;
|
|
[ThreadStatic]
|
|
internal static ArrayList ActivityRoots = null;
|
|
|
|
private static readonly BinaryFormatter binaryFormatter = null;
|
|
private static ActivityResolveEventHandler activityDefinitionResolve = null;
|
|
private static WorkflowChangeActionsResolveEventHandler workflowChangeActionsResolve = null;
|
|
|
|
[NonSerialized]
|
|
private string cachedDottedPath = null;
|
|
|
|
[NonSerialized]
|
|
private IWorkflowCoreRuntime workflowCoreRuntime = null;
|
|
|
|
[NonSerialized]
|
|
internal CompositeActivity parent = null;
|
|
|
|
private static object staticSyncRoot = new object();
|
|
|
|
internal static readonly DependencyProperty CustomActivityProperty = DependencyProperty.Register("CustomActivity", typeof(bool), typeof(Activity), new PropertyMetadata(DependencyPropertyOptions.Metadata));
|
|
internal static Type ActivityType = null;
|
|
|
|
static Activity()
|
|
{
|
|
binaryFormatter = new BinaryFormatter();
|
|
binaryFormatter.SurrogateSelector = ActivitySurrogateSelector.Default;
|
|
|
|
// register known properties
|
|
DependencyProperty.RegisterAsKnown(ActivityExecutionContextInfoProperty, (byte)1, DependencyProperty.PropertyValidity.Reexecute);
|
|
DependencyProperty.RegisterAsKnown(CompletedExecutionContextsProperty, (byte)2, DependencyProperty.PropertyValidity.Reexecute);
|
|
DependencyProperty.RegisterAsKnown(ActiveExecutionContextsProperty, (byte)3, DependencyProperty.PropertyValidity.Uninitialize);
|
|
DependencyProperty.RegisterAsKnown(CompletedOrderIdProperty, (byte)4, DependencyProperty.PropertyValidity.Uninitialize);
|
|
DependencyProperty.RegisterAsKnown(ExecutionStatusProperty, (byte)5, DependencyProperty.PropertyValidity.Reexecute);
|
|
DependencyProperty.RegisterAsKnown(ExecutionResultProperty, (byte)6, DependencyProperty.PropertyValidity.Reexecute);
|
|
DependencyProperty.RegisterAsKnown(WasExecutingProperty, (byte)7, DependencyProperty.PropertyValidity.Uninitialize);
|
|
DependencyProperty.RegisterAsKnown(LockCountOnStatusChangeProperty, (byte)8, DependencyProperty.PropertyValidity.Uninitialize);
|
|
DependencyProperty.RegisterAsKnown(HasPrimaryClosedProperty, (byte)9, DependencyProperty.PropertyValidity.Uninitialize);
|
|
DependencyProperty.RegisterAsKnown(NestedActivitiesProperty, (byte)10, DependencyProperty.PropertyValidity.Uninitialize);
|
|
DependencyProperty.RegisterAsKnown(ActivityContextGuidProperty, (byte)11, DependencyProperty.PropertyValidity.Reexecute);
|
|
DependencyProperty.RegisterAsKnown(WorkflowXamlMarkupProperty, (byte)12, DependencyProperty.PropertyValidity.Uninitialize);
|
|
DependencyProperty.RegisterAsKnown(WorkflowRulesMarkupProperty, (byte)13, DependencyProperty.PropertyValidity.Uninitialize);
|
|
|
|
// other classes
|
|
DependencyProperty.RegisterAsKnown(ActivityExecutionContext.CurrentExceptionProperty, (byte)23, DependencyProperty.PropertyValidity.Reexecute);
|
|
DependencyProperty.RegisterAsKnown(ActivityExecutionContext.GrantedLocksProperty, (byte)24, DependencyProperty.PropertyValidity.Uninitialize);
|
|
DependencyProperty.RegisterAsKnown(ActivityExecutionContext.LockAcquiredCallbackProperty, (byte)25, DependencyProperty.PropertyValidity.Uninitialize);
|
|
|
|
|
|
// events
|
|
DependencyProperty.RegisterAsKnown(ExecutingEvent, (byte)31, DependencyProperty.PropertyValidity.Uninitialize);
|
|
DependencyProperty.RegisterAsKnown(CancelingEvent, (byte)32, DependencyProperty.PropertyValidity.Uninitialize);
|
|
DependencyProperty.RegisterAsKnown(ClosedEvent, (byte)33, DependencyProperty.PropertyValidity.Uninitialize);
|
|
DependencyProperty.RegisterAsKnown(CompensatingEvent, (byte)34, DependencyProperty.PropertyValidity.Uninitialize);
|
|
DependencyProperty.RegisterAsKnown(StatusChangedEvent, (byte)35, DependencyProperty.PropertyValidity.Uninitialize);
|
|
DependencyProperty.RegisterAsKnown(StatusChangedLockedEvent, (byte)36, DependencyProperty.PropertyValidity.Uninitialize);
|
|
DependencyProperty.RegisterAsKnown(LockCountOnStatusChangeChangedEvent, (byte)37, DependencyProperty.PropertyValidity.Uninitialize);
|
|
DependencyProperty.RegisterAsKnown(FaultingEvent, (byte)38, DependencyProperty.PropertyValidity.Uninitialize);
|
|
|
|
// misc. others
|
|
DependencyProperty.RegisterAsKnown(FaultAndCancellationHandlingFilter.FaultProcessedProperty, (byte)41, DependencyProperty.PropertyValidity.Uninitialize);
|
|
DependencyProperty.RegisterAsKnown(CompensationHandlingFilter.CompensateProcessedProperty, (byte)43, DependencyProperty.PropertyValidity.Uninitialize);
|
|
DependencyProperty.RegisterAsKnown(CompensationHandlingFilter.LastCompensatedOrderIdProperty, (byte)44, DependencyProperty.PropertyValidity.Uninitialize);
|
|
}
|
|
|
|
public Activity()
|
|
{
|
|
SetValue(CustomActivityProperty, false);
|
|
SetValue(NameProperty, GetType().Name);
|
|
}
|
|
|
|
public Activity(string name)
|
|
{
|
|
if (name == null)
|
|
throw new ArgumentNullException("name");
|
|
|
|
SetValue(CustomActivityProperty, false);
|
|
SetValue(NameProperty, name);
|
|
}
|
|
|
|
#region Execution Signals
|
|
|
|
protected internal virtual void Initialize(IServiceProvider provider)
|
|
{
|
|
if (provider == null)
|
|
throw new ArgumentNullException("provider");
|
|
|
|
}
|
|
protected internal virtual ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
|
|
{
|
|
if (executionContext == null)
|
|
throw new ArgumentNullException("executionContext");
|
|
|
|
return ActivityExecutionStatus.Closed;
|
|
}
|
|
protected internal virtual ActivityExecutionStatus Cancel(ActivityExecutionContext executionContext)
|
|
{
|
|
if (executionContext == null)
|
|
throw new ArgumentNullException("executionContext");
|
|
|
|
return ActivityExecutionStatus.Closed;
|
|
}
|
|
protected internal virtual ActivityExecutionStatus HandleFault(ActivityExecutionContext executionContext, Exception exception)
|
|
{
|
|
if (executionContext == null)
|
|
throw new ArgumentNullException("executionContext");
|
|
|
|
return ActivityExecutionStatus.Closed;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Derived implementation may do necessary cleanup here such as removing serializable instance
|
|
/// dependency properties before the activity status is set to closed.
|
|
/// </summary>
|
|
protected virtual void OnClosed(IServiceProvider provider)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called Immediatly once activity is done with it life time
|
|
/// i.e Simple Activity when they transition to close.
|
|
/// CompensatableActivity & any activity which is in compensation chain
|
|
/// when root activity close.
|
|
/// </summary>
|
|
/// <param name="serviceProvider"></param>
|
|
protected internal virtual void Uninitialize(IServiceProvider provider)
|
|
{
|
|
if (provider == null)
|
|
throw new ArgumentNullException("provider");
|
|
|
|
ResetKnownDependencyProperties(false);
|
|
}
|
|
|
|
protected internal virtual void OnActivityExecutionContextLoad(IServiceProvider provider)
|
|
{
|
|
if (provider == null)
|
|
throw new ArgumentNullException("provider");
|
|
}
|
|
|
|
protected internal virtual void OnActivityExecutionContextUnload(IServiceProvider provider)
|
|
{
|
|
if (provider == null)
|
|
throw new ArgumentNullException("provider");
|
|
}
|
|
#endregion
|
|
|
|
#region Activity Execution Helper Methods
|
|
|
|
protected internal void RaiseGenericEvent<T>(DependencyProperty dependencyEvent, object sender, T e) where T : EventArgs
|
|
{
|
|
if (dependencyEvent == null)
|
|
throw new ArgumentNullException("dependencyEvent");
|
|
|
|
if (e == null)
|
|
throw new ArgumentNullException("e");
|
|
|
|
if (this.WorkflowCoreRuntime == null)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_NoRuntimeAvailable));
|
|
|
|
EventHandler<T>[] eventHandlers = ((IDependencyObjectAccessor)this).GetInvocationList<EventHandler<T>>(dependencyEvent);
|
|
if (eventHandlers != null)
|
|
{
|
|
foreach (EventHandler<T> eventHandler in eventHandlers)
|
|
{
|
|
this.WorkflowCoreRuntime.RaiseHandlerInvoking(eventHandler);
|
|
try
|
|
{
|
|
eventHandler(sender, e);
|
|
}
|
|
finally
|
|
{
|
|
this.WorkflowCoreRuntime.RaiseHandlerInvoked();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected internal void RaiseEvent(DependencyProperty dependencyEvent, object sender, EventArgs e)
|
|
{
|
|
if (sender == null)
|
|
throw new ArgumentNullException("sender");
|
|
|
|
if (dependencyEvent == null)
|
|
throw new ArgumentNullException("dependencyEvent");
|
|
|
|
if (e == null)
|
|
throw new ArgumentNullException("e");
|
|
|
|
if (this.WorkflowCoreRuntime == null)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_NoRuntimeAvailable));
|
|
|
|
EventHandler[] eventHandlers = ((IDependencyObjectAccessor)this).GetInvocationList<EventHandler>(dependencyEvent);
|
|
if (eventHandlers != null)
|
|
{
|
|
foreach (EventHandler eventHandler in eventHandlers)
|
|
{
|
|
this.WorkflowCoreRuntime.RaiseHandlerInvoking(eventHandler);
|
|
try
|
|
{
|
|
eventHandler(sender, e);
|
|
}
|
|
finally
|
|
{
|
|
this.WorkflowCoreRuntime.RaiseHandlerInvoked();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void TrackData(object userData)
|
|
{
|
|
if (userData == null)
|
|
throw new ArgumentNullException("userData");
|
|
if (this.WorkflowCoreRuntime == null)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_NoRuntimeAvailable));
|
|
|
|
this.WorkflowCoreRuntime.Track(null, userData);
|
|
}
|
|
protected void TrackData(string userDataKey, object userData)
|
|
{
|
|
if (userData == null)
|
|
throw new ArgumentNullException("userData");
|
|
if (this.WorkflowCoreRuntime == null)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_NoRuntimeAvailable));
|
|
|
|
this.WorkflowCoreRuntime.Track(userDataKey, userData);
|
|
}
|
|
protected Guid WorkflowInstanceId
|
|
{
|
|
get
|
|
{
|
|
if (this.WorkflowCoreRuntime == null)
|
|
#pragma warning suppress 56503
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_NoRuntimeAvailable));
|
|
return this.WorkflowCoreRuntime.InstanceID;
|
|
}
|
|
}
|
|
protected internal void Invoke<T>(EventHandler<T> handler, T e) where T : EventArgs
|
|
{
|
|
|
|
if (handler == null)
|
|
throw new ArgumentNullException("handler");
|
|
|
|
if (e == null)
|
|
throw new ArgumentNullException("e");
|
|
|
|
if (this.WorkflowCoreRuntime == null)
|
|
throw new InvalidOperationException(SR.GetString(System.Globalization.CultureInfo.CurrentCulture, SR.Error_NoRuntimeAvailable));
|
|
|
|
if (this.ExecutionStatus == ActivityExecutionStatus.Initialized || this.ExecutionStatus == ActivityExecutionStatus.Closed)
|
|
throw new InvalidOperationException(SR.GetString(System.Globalization.CultureInfo.CurrentCulture, SR.Error_InvalidInvokingState));
|
|
|
|
// create subscriber
|
|
ActivityExecutorDelegateInfo<T> activityExecutorDelegate = null;
|
|
using (this.WorkflowCoreRuntime.SetCurrentActivity(this))
|
|
activityExecutorDelegate = new ActivityExecutorDelegateInfo<T>(handler, this.ContextActivity);
|
|
|
|
activityExecutorDelegate.InvokeDelegate(this.WorkflowCoreRuntime.CurrentActivity.ContextActivity, e, false);
|
|
}
|
|
|
|
protected internal void Invoke<T>(IActivityEventListener<T> eventListener, T e) where T : EventArgs
|
|
{
|
|
if (eventListener == null)
|
|
throw new ArgumentNullException("eventListener");
|
|
|
|
if (e == null)
|
|
throw new ArgumentNullException("e");
|
|
|
|
if (this.WorkflowCoreRuntime == null)
|
|
throw new InvalidOperationException(SR.GetString(System.Globalization.CultureInfo.CurrentCulture, SR.Error_NoRuntimeAvailable));
|
|
|
|
if (this.ExecutionStatus == ActivityExecutionStatus.Initialized || this.ExecutionStatus == ActivityExecutionStatus.Closed)
|
|
throw new InvalidOperationException(SR.GetString(System.Globalization.CultureInfo.CurrentCulture, SR.Error_InvalidInvokingState));
|
|
|
|
// create subscriber
|
|
ActivityExecutorDelegateInfo<T> activityExecutorDelegate = null;
|
|
using (this.WorkflowCoreRuntime.SetCurrentActivity(this))
|
|
activityExecutorDelegate = new ActivityExecutorDelegateInfo<T>(eventListener, this.ContextActivity);
|
|
|
|
activityExecutorDelegate.InvokeDelegate(this.WorkflowCoreRuntime.CurrentActivity.ContextActivity, e, false);
|
|
}
|
|
#endregion
|
|
|
|
#region Activity Meta Properties
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public CompositeActivity Parent
|
|
{
|
|
get
|
|
{
|
|
return this.parent;
|
|
}
|
|
}
|
|
|
|
internal void SetParent(CompositeActivity compositeActivity)
|
|
{
|
|
this.parent = compositeActivity;
|
|
}
|
|
|
|
[Browsable(true)]
|
|
[SRCategory(SR.Activity)]
|
|
[ParenthesizePropertyName(true)]
|
|
[SRDescription(SR.NameDescr)]
|
|
[MergableProperty(false)]
|
|
[DefaultValue("")]
|
|
public string Name
|
|
{
|
|
get
|
|
{
|
|
return (string)GetValue(NameProperty);
|
|
}
|
|
set
|
|
{
|
|
SetValue(NameProperty, value);
|
|
}
|
|
}
|
|
|
|
[Browsable(true)]
|
|
[SRCategory(SR.Activity)]
|
|
[SRDescription(SR.EnabledDescr)]
|
|
[DefaultValue(true)]
|
|
public bool Enabled
|
|
{
|
|
get
|
|
{
|
|
return (bool)GetValue(EnabledProperty);
|
|
}
|
|
set
|
|
{
|
|
SetValue(EnabledProperty, value);
|
|
}
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public string QualifiedName
|
|
{
|
|
get
|
|
{
|
|
if (!this.DesignMode && !this.DynamicUpdateMode)
|
|
{
|
|
string cachedQualifiedName = (string)GetValue(QualifiedNameProperty);
|
|
if (cachedQualifiedName != null)
|
|
return cachedQualifiedName;
|
|
}
|
|
|
|
string sbQId = null;
|
|
if (Helpers.IsActivityLocked(this))
|
|
sbQId = InternalHelpers.GenerateQualifiedNameForLockedActivity(this, null);
|
|
else
|
|
sbQId = (string)GetValue(NameProperty);
|
|
return sbQId;
|
|
}
|
|
}
|
|
|
|
[Browsable(true)]
|
|
[SRCategory(SR.Activity)]
|
|
[SRDescription(SR.DescriptionDescr)]
|
|
[Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
|
|
[DefaultValue("")]
|
|
public string Description
|
|
{
|
|
get
|
|
{
|
|
return (string)GetValue(DescriptionProperty);
|
|
}
|
|
set
|
|
{
|
|
SetValue(DescriptionProperty, value);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Activity Instance Properties
|
|
|
|
public static readonly DependencyProperty StatusChangedEvent = DependencyProperty.Register("StatusChanged", typeof(EventHandler<ActivityExecutionStatusChangedEventArgs>), typeof(Activity));
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public event EventHandler<ActivityExecutionStatusChangedEventArgs> StatusChanged
|
|
{
|
|
add
|
|
{
|
|
this.AddStatusChangeHandler(StatusChangedEvent, value);
|
|
}
|
|
remove
|
|
{
|
|
this.RemoveStatusChangeHandler(StatusChangedEvent, value);
|
|
}
|
|
}
|
|
|
|
internal static readonly DependencyProperty LockCountOnStatusChangeChangedEvent = DependencyProperty.Register("LockCountOnStatusChangeChanged", typeof(EventHandler<ActivityExecutionStatusChangedEventArgs>), typeof(Activity));
|
|
internal static readonly DependencyProperty StatusChangedLockedEvent = DependencyProperty.Register("StatusChangedLocked", typeof(EventHandler<ActivityExecutionStatusChangedEventArgs>), typeof(Activity));
|
|
internal void HoldLockOnStatusChange(IActivityEventListener<ActivityExecutionStatusChangedEventArgs> eventListener)
|
|
{
|
|
this.RegisterForStatusChange(StatusChangedLockedEvent, eventListener);
|
|
|
|
// increment count
|
|
this.SetValue(LockCountOnStatusChangeProperty, this.LockCountOnStatusChange + 1);
|
|
}
|
|
internal void ReleaseLockOnStatusChange(IActivityEventListener<ActivityExecutionStatusChangedEventArgs> eventListener)
|
|
{
|
|
// remove it
|
|
this.UnregisterForStatusChange(StatusChangedLockedEvent, eventListener);
|
|
|
|
// decrement count and fire event
|
|
int lockCountOnStatusChange = this.LockCountOnStatusChange;
|
|
Debug.Assert(lockCountOnStatusChange > 0, "lock count on status change should be > 0");
|
|
this.SetValue(LockCountOnStatusChangeProperty, --lockCountOnStatusChange);
|
|
if (lockCountOnStatusChange == 0)
|
|
{
|
|
// Work around: if primary activity was never closed, then we set it to Canceled outcome
|
|
if (!this.HasPrimaryClosed)
|
|
this.SetValue(ExecutionResultProperty, ActivityExecutionResult.Canceled);
|
|
|
|
try
|
|
{
|
|
this.MarkClosed();
|
|
}
|
|
catch
|
|
{
|
|
// roll back the lock count changes which we did
|
|
this.SetValue(LockCountOnStatusChangeProperty, ++lockCountOnStatusChange);
|
|
this.RegisterForStatusChange(StatusChangedLockedEvent, eventListener);
|
|
throw;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FireStatusChangedEvents(Activity.LockCountOnStatusChangeChangedEvent, false);
|
|
}
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
internal int LockCountOnStatusChange
|
|
{
|
|
get
|
|
{
|
|
return (int)this.GetValue(LockCountOnStatusChangeProperty);
|
|
}
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
internal bool HasPrimaryClosed
|
|
{
|
|
get
|
|
{
|
|
return (bool)this.GetValue(HasPrimaryClosedProperty);
|
|
}
|
|
}
|
|
|
|
public static readonly DependencyProperty CancelingEvent = DependencyProperty.Register("Canceling", typeof(EventHandler<ActivityExecutionStatusChangedEventArgs>), typeof(Activity));
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public event EventHandler<ActivityExecutionStatusChangedEventArgs> Canceling
|
|
{
|
|
add
|
|
{
|
|
this.AddStatusChangeHandler(CancelingEvent, value);
|
|
}
|
|
remove
|
|
{
|
|
this.RemoveStatusChangeHandler(CancelingEvent, value);
|
|
}
|
|
}
|
|
|
|
public static readonly DependencyProperty FaultingEvent = DependencyProperty.Register("Faulting", typeof(EventHandler<ActivityExecutionStatusChangedEventArgs>), typeof(Activity));
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public event EventHandler<ActivityExecutionStatusChangedEventArgs> Faulting
|
|
{
|
|
add
|
|
{
|
|
this.AddStatusChangeHandler(FaultingEvent, value);
|
|
}
|
|
remove
|
|
{
|
|
this.RemoveStatusChangeHandler(FaultingEvent, value);
|
|
}
|
|
}
|
|
|
|
|
|
public static readonly DependencyProperty ClosedEvent = DependencyProperty.Register("Closed", typeof(EventHandler<ActivityExecutionStatusChangedEventArgs>), typeof(Activity));
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public event EventHandler<ActivityExecutionStatusChangedEventArgs> Closed
|
|
{
|
|
add
|
|
{
|
|
this.AddStatusChangeHandler(ClosedEvent, value);
|
|
}
|
|
remove
|
|
{
|
|
this.RemoveStatusChangeHandler(ClosedEvent, value);
|
|
}
|
|
}
|
|
|
|
public static readonly DependencyProperty ExecutingEvent = DependencyProperty.Register("Executing", typeof(EventHandler<ActivityExecutionStatusChangedEventArgs>), typeof(Activity));
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public event EventHandler<ActivityExecutionStatusChangedEventArgs> Executing
|
|
{
|
|
add
|
|
{
|
|
this.AddStatusChangeHandler(ExecutingEvent, value);
|
|
}
|
|
remove
|
|
{
|
|
this.RemoveStatusChangeHandler(ExecutingEvent, value);
|
|
}
|
|
}
|
|
|
|
public static readonly DependencyProperty CompensatingEvent = DependencyProperty.Register("Compensating", typeof(EventHandler<ActivityExecutionStatusChangedEventArgs>), typeof(Activity));
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public event EventHandler<ActivityExecutionStatusChangedEventArgs> Compensating
|
|
{
|
|
add
|
|
{
|
|
this.AddStatusChangeHandler(CompensatingEvent, value);
|
|
}
|
|
remove
|
|
{
|
|
this.RemoveStatusChangeHandler(CompensatingEvent, value);
|
|
}
|
|
}
|
|
private void AddStatusChangeHandler(DependencyProperty dependencyProp, EventHandler<ActivityExecutionStatusChangedEventArgs> delegateValue)
|
|
{
|
|
IList handlers = null;
|
|
if (this.DependencyPropertyValues.ContainsKey(dependencyProp))
|
|
{
|
|
handlers = this.DependencyPropertyValues[dependencyProp] as IList;
|
|
}
|
|
else
|
|
{
|
|
handlers = new ArrayList();
|
|
this.DependencyPropertyValues[dependencyProp] = handlers;
|
|
}
|
|
handlers.Add(new ActivityExecutorDelegateInfo<ActivityExecutionStatusChangedEventArgs>(true, delegateValue, this.ContextActivity ?? this.RootActivity));
|
|
}
|
|
private void RemoveStatusChangeHandler(DependencyProperty dependencyProp, EventHandler<ActivityExecutionStatusChangedEventArgs> delegateValue)
|
|
{
|
|
if (this.DependencyPropertyValues.ContainsKey(dependencyProp))
|
|
{
|
|
IList handlers = this.DependencyPropertyValues[dependencyProp] as IList;
|
|
if (handlers != null)
|
|
{
|
|
handlers.Remove(new ActivityExecutorDelegateInfo<ActivityExecutionStatusChangedEventArgs>(true, delegateValue, this.ContextActivity));
|
|
if (handlers.Count == 0)
|
|
this.DependencyPropertyValues.Remove(dependencyProp);
|
|
}
|
|
}
|
|
}
|
|
private IList GetStatusChangeHandlers(DependencyProperty dependencyProp)
|
|
{
|
|
IList handlers = null;
|
|
if (this.DependencyPropertyValues.ContainsKey(dependencyProp))
|
|
handlers = this.DependencyPropertyValues[dependencyProp] as IList;
|
|
return handlers;
|
|
}
|
|
|
|
public void RegisterForStatusChange(DependencyProperty dependencyProp, IActivityEventListener<ActivityExecutionStatusChangedEventArgs> activityStatusChangeListener)
|
|
{
|
|
if (dependencyProp == null)
|
|
throw new ArgumentNullException("dependencyProp");
|
|
if (activityStatusChangeListener == null)
|
|
throw new ArgumentNullException("activityStatusChangeListener");
|
|
|
|
if (dependencyProp != Activity.ExecutingEvent &&
|
|
dependencyProp != Activity.CancelingEvent &&
|
|
dependencyProp != Activity.ClosedEvent &&
|
|
dependencyProp != Activity.CompensatingEvent &&
|
|
dependencyProp != Activity.FaultingEvent &&
|
|
dependencyProp != Activity.StatusChangedEvent &&
|
|
dependencyProp != Activity.StatusChangedLockedEvent &&
|
|
dependencyProp != Activity.LockCountOnStatusChangeChangedEvent)
|
|
throw new ArgumentException();
|
|
|
|
IList handlers = null;
|
|
if (this.DependencyPropertyValues.ContainsKey(dependencyProp))
|
|
{
|
|
handlers = this.DependencyPropertyValues[dependencyProp] as IList;
|
|
}
|
|
else
|
|
{
|
|
handlers = new ArrayList();
|
|
this.DependencyPropertyValues[dependencyProp] = handlers;
|
|
}
|
|
handlers.Add(new ActivityExecutorDelegateInfo<ActivityExecutionStatusChangedEventArgs>(true, activityStatusChangeListener, this.ContextActivity));
|
|
}
|
|
public void UnregisterForStatusChange(DependencyProperty dependencyProp, IActivityEventListener<ActivityExecutionStatusChangedEventArgs> activityStatusChangeListener)
|
|
{
|
|
if (dependencyProp == null)
|
|
throw new ArgumentNullException("dependencyProp");
|
|
if (activityStatusChangeListener == null)
|
|
throw new ArgumentNullException("activityStatusChangeListener");
|
|
|
|
if (dependencyProp != Activity.ExecutingEvent &&
|
|
dependencyProp != Activity.CancelingEvent &&
|
|
dependencyProp != Activity.ClosedEvent &&
|
|
dependencyProp != Activity.CompensatingEvent &&
|
|
dependencyProp != Activity.FaultingEvent &&
|
|
dependencyProp != Activity.StatusChangedEvent &&
|
|
dependencyProp != Activity.StatusChangedLockedEvent &&
|
|
dependencyProp != Activity.LockCountOnStatusChangeChangedEvent)
|
|
throw new ArgumentException();
|
|
|
|
if (this.DependencyPropertyValues.ContainsKey(dependencyProp))
|
|
{
|
|
IList handlers = this.DependencyPropertyValues[dependencyProp] as IList;
|
|
if (handlers != null)
|
|
{
|
|
handlers.Remove(new ActivityExecutorDelegateInfo<ActivityExecutionStatusChangedEventArgs>(true, activityStatusChangeListener, this.ContextActivity));
|
|
if (handlers.Count == 0)
|
|
this.DependencyPropertyValues.Remove(dependencyProp);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public ActivityExecutionStatus ExecutionStatus
|
|
{
|
|
get
|
|
{
|
|
return (ActivityExecutionStatus)this.GetValue(ExecutionStatusProperty);
|
|
}
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public ActivityExecutionResult ExecutionResult
|
|
{
|
|
get
|
|
{
|
|
return (ActivityExecutionResult)this.GetValue(ExecutionResultProperty);
|
|
}
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public bool IsDynamicActivity
|
|
{
|
|
get
|
|
{
|
|
if (this.DesignMode)
|
|
return false;
|
|
else
|
|
return (this.ContextActivity != this.RootActivity);
|
|
}
|
|
}
|
|
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
internal bool WasExecuting
|
|
{
|
|
get
|
|
{
|
|
return (bool)this.GetValue(WasExecutingProperty);
|
|
}
|
|
}
|
|
public Activity GetActivityByName(string activityQualifiedName)
|
|
{
|
|
return GetActivityByName(activityQualifiedName, false);
|
|
}
|
|
public Activity GetActivityByName(string activityQualifiedName, bool withinThisActivityOnly)
|
|
{
|
|
if (activityQualifiedName == null)
|
|
throw new ArgumentNullException("activityQualifiedName");
|
|
|
|
if (this.QualifiedName == activityQualifiedName)
|
|
return this;
|
|
|
|
Activity resolvedActivity = null;
|
|
|
|
// try with just the passed qualified id
|
|
resolvedActivity = ResolveActivityByName(activityQualifiedName, withinThisActivityOnly);
|
|
|
|
if (resolvedActivity == null)
|
|
{
|
|
// if custom then append its qualified id and then try it
|
|
if (this is CompositeActivity && Helpers.IsCustomActivity(this as CompositeActivity))
|
|
resolvedActivity = ResolveActivityByName(this.QualifiedName + "." + activityQualifiedName, withinThisActivityOnly);
|
|
}
|
|
|
|
return resolvedActivity;
|
|
}
|
|
|
|
private Activity ResolveActivityByName(string activityQualifiedName, bool withinThisActivityOnly)
|
|
{
|
|
Activity resolvedActivity = null;
|
|
if (!this.DesignMode && !this.DynamicUpdateMode)
|
|
{
|
|
Activity rootActivity = this.RootActivity;
|
|
|
|
Hashtable lookupPaths = (Hashtable)rootActivity.UserData[UserDataKeys.LookupPaths];
|
|
if (lookupPaths != null)
|
|
{
|
|
string path = (string)lookupPaths[activityQualifiedName];
|
|
if (path != null)
|
|
{
|
|
if (path.Length != 0)
|
|
{
|
|
string thisPath = (string)lookupPaths[this.QualifiedName];
|
|
if (path.StartsWith(thisPath, StringComparison.Ordinal))
|
|
{
|
|
if (path.Length == thisPath.Length)
|
|
resolvedActivity = this;
|
|
else if (thisPath.Length == 0 || path[thisPath.Length] == '.')
|
|
resolvedActivity = this.TraverseDottedPath(path.Substring(thisPath.Length > 0 ? thisPath.Length + 1 : 0));
|
|
}
|
|
else if (!withinThisActivityOnly)
|
|
{
|
|
resolvedActivity = rootActivity.TraverseDottedPath(path);
|
|
}
|
|
}
|
|
else if (!withinThisActivityOnly)
|
|
{
|
|
resolvedActivity = rootActivity;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (!this.DesignMode)
|
|
{
|
|
// WinOE Bug 20584: Fix this for dynamic updates only. See bug description for details.
|
|
CompositeActivity parent = (withinThisActivityOnly ? this : this.RootActivity) as CompositeActivity;
|
|
if (parent != null)
|
|
{
|
|
foreach (Activity childActivity in Helpers.GetNestedActivities(parent))
|
|
{
|
|
if (childActivity.QualifiedName == activityQualifiedName)
|
|
{
|
|
resolvedActivity = childActivity;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
resolvedActivity = Helpers.ParseActivity(this, activityQualifiedName);
|
|
|
|
if (resolvedActivity == null && !withinThisActivityOnly)
|
|
resolvedActivity = Helpers.ParseActivity(this.RootActivity, activityQualifiedName);
|
|
}
|
|
|
|
return resolvedActivity;
|
|
}
|
|
|
|
internal void ResetAllKnownDependencyProperties()
|
|
{
|
|
ResetKnownDependencyProperties(true);
|
|
}
|
|
|
|
private void ResetKnownDependencyProperties(bool forReexecute)
|
|
{
|
|
DependencyProperty[] propertyClone = new DependencyProperty[this.DependencyPropertyValues.Keys.Count];
|
|
this.DependencyPropertyValues.Keys.CopyTo(propertyClone, 0);
|
|
|
|
foreach (DependencyProperty property in propertyClone)
|
|
{
|
|
if (property.IsKnown && (property.Validity == DependencyProperty.PropertyValidity.Uninitialize || (forReexecute && property.Validity == DependencyProperty.PropertyValidity.Reexecute)))
|
|
this.RemoveProperty(property);
|
|
}
|
|
}
|
|
|
|
internal virtual Activity TraverseDottedPath(string dottedPath)
|
|
{
|
|
return null;
|
|
}
|
|
internal Activity TraverseDottedPathFromRoot(string dottedPathFromRoot)
|
|
{
|
|
string thisActivityDottedPath = this.DottedPath;
|
|
if (dottedPathFromRoot == thisActivityDottedPath)
|
|
return this;
|
|
|
|
// if it start with the smae dotted path then it's ok, otherwise return
|
|
if (!dottedPathFromRoot.StartsWith(thisActivityDottedPath, StringComparison.Ordinal))
|
|
return null;
|
|
|
|
// calculate relative path
|
|
string relativeDottedPath = dottedPathFromRoot;
|
|
if (thisActivityDottedPath.Length > 0)
|
|
relativeDottedPath = dottedPathFromRoot.Substring(thisActivityDottedPath.Length + 1);
|
|
|
|
return this.TraverseDottedPath(relativeDottedPath);
|
|
}
|
|
internal string DottedPath
|
|
{
|
|
get
|
|
{
|
|
if (!this.DesignMode && !this.DynamicUpdateMode)
|
|
{
|
|
string cachedDottedPath = (string)GetValue(DottedPathProperty);
|
|
if (cachedDottedPath != null)
|
|
return cachedDottedPath;
|
|
}
|
|
|
|
StringBuilder dottedPathBuilder = new StringBuilder();
|
|
Activity thisActivity = this;
|
|
while (thisActivity.parent != null)
|
|
{
|
|
int thisActivityIndex = thisActivity.parent.Activities.IndexOf(thisActivity);
|
|
dottedPathBuilder.Insert(0, thisActivityIndex.ToString(CultureInfo.InvariantCulture)); //15
|
|
dottedPathBuilder.Insert(0, '.'); //.15
|
|
thisActivity = thisActivity.parent;
|
|
}
|
|
if (dottedPathBuilder.Length > 0)
|
|
dottedPathBuilder.Remove(0, 1); // remove the first dot
|
|
return dottedPathBuilder.ToString();
|
|
}
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
internal IWorkflowCoreRuntime WorkflowCoreRuntime
|
|
{
|
|
get
|
|
{
|
|
return this.workflowCoreRuntime;
|
|
}
|
|
}
|
|
internal bool DynamicUpdateMode
|
|
{
|
|
get
|
|
{
|
|
return (this.cachedDottedPath != null);
|
|
}
|
|
set
|
|
{
|
|
if (value)
|
|
this.cachedDottedPath = this.DottedPath;
|
|
else
|
|
this.cachedDottedPath = null;
|
|
}
|
|
}
|
|
internal string CachedDottedPath
|
|
{
|
|
get
|
|
{
|
|
return this.cachedDottedPath;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Load/Save Static Methods
|
|
|
|
public Activity Clone()
|
|
{
|
|
if (this.DesignMode)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_NoRuntimeAvailable));
|
|
|
|
long max = (long)this.GetValue(SerializedStreamLengthProperty);
|
|
if (max == 0)
|
|
max = 10240;
|
|
MemoryStream memoryStream = new MemoryStream((int)max);
|
|
Save(memoryStream);
|
|
memoryStream.Position = 0;
|
|
this.SetValue(SerializedStreamLengthProperty, memoryStream.Length > max ? memoryStream.Length : max);
|
|
return Activity.Load(memoryStream, this);
|
|
}
|
|
|
|
public void Save(Stream stream)
|
|
{
|
|
this.Save(stream, binaryFormatter);
|
|
}
|
|
public void Save(Stream stream, IFormatter formatter)
|
|
{
|
|
if (stream == null)
|
|
throw new ArgumentNullException("stream");
|
|
if (formatter == null)
|
|
throw new ArgumentNullException("formatter");
|
|
|
|
if (this.DesignMode)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_NoRuntimeAvailable));
|
|
|
|
// cache the old values so that this fucntion can be re-entrant
|
|
Hashtable oldContextIdToActivityMap = ContextIdToActivityMap;
|
|
|
|
ContextIdToActivityMap = new Hashtable();
|
|
try
|
|
{
|
|
// fill context id to Activity map
|
|
FillContextIdToActivityMap(this);
|
|
|
|
// walk through all nested activity roots and set nested activities
|
|
foreach (Activity activityRoot in ContextIdToActivityMap.Values)
|
|
{
|
|
IList<Activity> nestedActivities = activityRoot.CollectNestedActivities();
|
|
if (nestedActivities != null && nestedActivities.Count > 0)
|
|
activityRoot.SetValue(Activity.NestedActivitiesProperty, nestedActivities);
|
|
}
|
|
|
|
// serialize the graph
|
|
formatter.Serialize(stream, this);
|
|
}
|
|
finally
|
|
{
|
|
foreach (Activity activityRoot in ContextIdToActivityMap.Values)
|
|
activityRoot.RemoveProperty(Activity.NestedActivitiesProperty);
|
|
ContextIdToActivityMap = oldContextIdToActivityMap;
|
|
ActivityRoots = null;
|
|
}
|
|
}
|
|
public static Activity Load(Stream stream, Activity outerActivity)
|
|
{
|
|
return Load(stream, outerActivity, binaryFormatter);
|
|
}
|
|
public static Activity Load(Stream stream, Activity outerActivity, IFormatter formatter)
|
|
{
|
|
if (stream == null)
|
|
throw new ArgumentNullException("stream");
|
|
if (formatter == null)
|
|
throw new ArgumentNullException("formatter");
|
|
|
|
if (outerActivity != null && outerActivity.DesignMode)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_NoRuntimeAvailable));
|
|
|
|
Activity returnActivity = null;
|
|
|
|
// cache the old values, so that this fucntion can be re-entrant
|
|
Hashtable oldContextIdToActivityMap = ContextIdToActivityMap;
|
|
Activity oldDefinitionActivity = DefinitionActivity;
|
|
|
|
// initialize the thread static guys
|
|
ContextIdToActivityMap = new Hashtable();
|
|
DefinitionActivity = outerActivity;
|
|
|
|
try
|
|
{
|
|
// fill in the context id to activity map for surrounding contexts
|
|
if (outerActivity != null)
|
|
FillContextIdToActivityMap(outerActivity.RootActivity);
|
|
|
|
// deserialize the stream
|
|
returnActivity = (Activity)formatter.Deserialize(stream);
|
|
|
|
// fix up parent child relation ships for root activity and al nested context activities
|
|
Queue<Activity> deserializedActivityRootsQueue = new Queue<Activity>();
|
|
deserializedActivityRootsQueue.Enqueue(returnActivity);
|
|
while (deserializedActivityRootsQueue.Count > 0)
|
|
{
|
|
Activity deserializedActivityRoot = deserializedActivityRootsQueue.Dequeue();
|
|
|
|
// determine the parent activity and definition activity
|
|
Activity definitionActivity = DefinitionActivity;
|
|
Activity parentActivity = outerActivity != null ? outerActivity.parent : null;
|
|
|
|
if (deserializedActivityRoot.IsContextActivity)
|
|
{
|
|
// get the corresponding definition activity
|
|
ActivityExecutionContextInfo contextInfo = (ActivityExecutionContextInfo)deserializedActivityRoot.GetValue(Activity.ActivityExecutionContextInfoProperty);
|
|
definitionActivity = definitionActivity.GetActivityByName(contextInfo.ActivityQualifiedName);
|
|
|
|
// get the corresponding parent activity
|
|
Activity parentContextActivity = (Activity)ContextIdToActivityMap[contextInfo.ParentContextId];
|
|
if (parentContextActivity != null)
|
|
parentActivity = parentContextActivity.GetActivityByName(contextInfo.ActivityQualifiedName).parent;
|
|
|
|
// fill up the cached context activities
|
|
ContextIdToActivityMap[deserializedActivityRoot.ContextId] = deserializedActivityRoot;
|
|
|
|
// get nested context activities and queue them for processing
|
|
IList<Activity> deserializedNestedActivityRoots = (IList<Activity>)deserializedActivityRoot.GetValue(Activity.ActiveExecutionContextsProperty);
|
|
if (deserializedNestedActivityRoots != null)
|
|
{
|
|
foreach (Activity deserializedNestedActivityRoot in deserializedNestedActivityRoots)
|
|
deserializedActivityRootsQueue.Enqueue(deserializedNestedActivityRoot);
|
|
}
|
|
}
|
|
|
|
// prepare hash of id to activity
|
|
Hashtable idToActivityMap = new Hashtable();
|
|
IList<Activity> nestedActivities = (IList<Activity>)deserializedActivityRoot.GetValue(Activity.NestedActivitiesProperty);
|
|
if (nestedActivities != null)
|
|
{
|
|
foreach (Activity nestedActivity in nestedActivities)
|
|
idToActivityMap.Add(nestedActivity.DottedPath, nestedActivity);
|
|
}
|
|
|
|
// fix up parent child relation ship for this activity
|
|
deserializedActivityRoot.FixUpParentChildRelationship(definitionActivity, parentActivity, idToActivityMap);
|
|
deserializedActivityRoot.FixUpMetaProperties(definitionActivity);
|
|
deserializedActivityRoot.RemoveProperty(Activity.NestedActivitiesProperty);
|
|
}
|
|
|
|
// set the Workflow Definition in case of root activity
|
|
if (returnActivity.Parent == null)
|
|
returnActivity.SetValue(Activity.WorkflowDefinitionProperty, DefinitionActivity);
|
|
}
|
|
finally
|
|
{
|
|
ContextIdToActivityMap = oldContextIdToActivityMap;
|
|
DefinitionActivity = oldDefinitionActivity;
|
|
ActivityRoots = null;
|
|
}
|
|
return returnActivity;
|
|
}
|
|
private static void FillContextIdToActivityMap(Activity seedActivity)
|
|
{
|
|
Queue<Activity> activityRootsQueue = new Queue<Activity>();
|
|
activityRootsQueue.Enqueue(seedActivity);
|
|
while (activityRootsQueue.Count > 0)
|
|
{
|
|
Activity activityRoot = activityRootsQueue.Dequeue();
|
|
if (activityRoot.IsContextActivity)
|
|
{
|
|
ContextIdToActivityMap[activityRoot.ContextId] = activityRoot;
|
|
IList<Activity> activeActivityRoots = (IList<Activity>)activityRoot.GetValue(Activity.ActiveExecutionContextsProperty);
|
|
if (activeActivityRoots != null)
|
|
{
|
|
foreach (Activity activeActivityRoot in activeActivityRoots)
|
|
activityRootsQueue.Enqueue(activeActivityRoot);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ContextIdToActivityMap[0] = activityRoot;
|
|
}
|
|
}
|
|
ActivityRoots = new ArrayList(ContextIdToActivityMap.Values);
|
|
}
|
|
|
|
internal static event ActivityResolveEventHandler ActivityResolve
|
|
{
|
|
add
|
|
{
|
|
lock (staticSyncRoot)
|
|
{
|
|
activityDefinitionResolve += value;
|
|
}
|
|
}
|
|
remove
|
|
{
|
|
lock (staticSyncRoot)
|
|
{
|
|
activityDefinitionResolve -= value;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static event WorkflowChangeActionsResolveEventHandler WorkflowChangeActionsResolve
|
|
{
|
|
add
|
|
{
|
|
lock (staticSyncRoot)
|
|
{
|
|
workflowChangeActionsResolve += value;
|
|
}
|
|
}
|
|
|
|
remove
|
|
{
|
|
lock (staticSyncRoot)
|
|
{
|
|
workflowChangeActionsResolve -= value;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static Activity OnResolveActivityDefinition(Type type, string workflowMarkup, string rulesMarkup, bool createNew, bool initForRuntime, IServiceProvider serviceProvider)
|
|
{
|
|
// get invocation list
|
|
Delegate[] invocationList = null;
|
|
lock (staticSyncRoot)
|
|
{
|
|
if (activityDefinitionResolve != null)
|
|
invocationList = activityDefinitionResolve.GetInvocationList();
|
|
}
|
|
|
|
// call resovlers one by one
|
|
Activity activityDefinition = null;
|
|
if (invocationList != null)
|
|
{
|
|
foreach (ActivityResolveEventHandler activityDefinitionResolver in invocationList)
|
|
{
|
|
activityDefinition = activityDefinitionResolver(null, new ActivityResolveEventArgs(type, workflowMarkup, rulesMarkup, createNew, initForRuntime, serviceProvider));
|
|
if (activityDefinition != null)
|
|
return activityDefinition;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
internal static ArrayList OnResolveWorkflowChangeActions(string workflowChangesMarkup, Activity root)
|
|
{
|
|
// get invocation list
|
|
Delegate[] invocationList = null;
|
|
lock (staticSyncRoot)
|
|
{
|
|
if (workflowChangeActionsResolve != null)
|
|
invocationList = workflowChangeActionsResolve.GetInvocationList();
|
|
}
|
|
|
|
// call resovlers one by one
|
|
ArrayList changeActions = null;
|
|
if (invocationList != null)
|
|
{
|
|
foreach (WorkflowChangeActionsResolveEventHandler workflowChangeActionsResolver in invocationList)
|
|
{
|
|
changeActions = workflowChangeActionsResolver(root, new WorkflowChangeActionsResolveEventArgs(workflowChangesMarkup));
|
|
if (changeActions != null)
|
|
return changeActions;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Context Activity properties
|
|
|
|
internal bool IsContextActivity
|
|
{
|
|
get
|
|
{
|
|
return this.GetValue(Activity.ActivityExecutionContextInfoProperty) != null;
|
|
}
|
|
}
|
|
internal int ContextId
|
|
{
|
|
get
|
|
{
|
|
return ((ActivityExecutionContextInfo)this.ContextActivity.GetValue(Activity.ActivityExecutionContextInfoProperty)).ContextId;
|
|
}
|
|
}
|
|
internal Guid ContextGuid
|
|
{
|
|
get
|
|
{
|
|
return ((ActivityExecutionContextInfo)this.ContextActivity.GetValue(Activity.ActivityExecutionContextInfoProperty)).ContextGuid;
|
|
}
|
|
}
|
|
internal Activity ContextActivity
|
|
{
|
|
get
|
|
{
|
|
Activity contextActivity = this;
|
|
while (contextActivity != null && contextActivity.GetValue(Activity.ActivityExecutionContextInfoProperty) == null)
|
|
contextActivity = contextActivity.parent;
|
|
return contextActivity;
|
|
}
|
|
}
|
|
internal Activity ParentContextActivity
|
|
{
|
|
get
|
|
{
|
|
Activity contextActivity = this.ContextActivity;
|
|
ActivityExecutionContextInfo executionContextInfo = (ActivityExecutionContextInfo)contextActivity.GetValue(Activity.ActivityExecutionContextInfoProperty);
|
|
if (executionContextInfo.ParentContextId == -1)
|
|
return null;
|
|
return this.WorkflowCoreRuntime.GetContextActivityForId(executionContextInfo.ParentContextId);
|
|
}
|
|
}
|
|
internal Activity RootContextActivity
|
|
{
|
|
get
|
|
{
|
|
return this.WorkflowCoreRuntime.RootActivity;
|
|
}
|
|
}
|
|
internal Activity RootActivity
|
|
{
|
|
get
|
|
{
|
|
Activity parent = this;
|
|
while (parent.parent != null)
|
|
parent = parent.parent;
|
|
return parent;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Runtime Initialization
|
|
|
|
internal override void OnInitializeDefinitionForRuntime()
|
|
{
|
|
// only if we are in design mode, execute this code, other wise ignore this call
|
|
if (this.DesignMode)
|
|
{
|
|
// call base
|
|
base.OnInitializeDefinitionForRuntime();
|
|
|
|
this.UserData[UserDataKeys.CustomActivity] = this.GetValue(CustomActivityProperty);
|
|
|
|
// Work around !! Supports Synchronization and atomic transaction isolation
|
|
ICollection<String> handles = (ICollection<String>)GetValue(SynchronizationHandlesProperty);
|
|
if (this.SupportsTransaction)
|
|
{
|
|
if (handles == null)
|
|
handles = new List<string>();
|
|
handles.Add(TransactionScopeActivity.TransactionScopeActivityIsolationHandle);
|
|
}
|
|
if (handles != null)
|
|
this.SetValue(SynchronizationHandlesProperty, new ReadOnlyCollection<string>(new List<string>(handles)));
|
|
|
|
// lookup paths for root activity
|
|
if (this.Parent == null)
|
|
{
|
|
Hashtable lookupPaths = new Hashtable();
|
|
this.UserData[UserDataKeys.LookupPaths] = lookupPaths;
|
|
lookupPaths.Add(this.QualifiedName, string.Empty);
|
|
}
|
|
|
|
// Initialize the cache at runtime
|
|
SetReadOnlyPropertyValue(QualifiedNameProperty, this.QualifiedName);
|
|
SetReadOnlyPropertyValue(DottedPathProperty, this.DottedPath);
|
|
|
|
// cache attributes
|
|
this.UserData[typeof(PersistOnCloseAttribute)] = (this.GetType().GetCustomAttributes(typeof(PersistOnCloseAttribute), true).Length > 0);
|
|
}
|
|
}
|
|
internal override void OnInitializeInstanceForRuntime(IWorkflowCoreRuntime workflowCoreRuntime)
|
|
{
|
|
base.OnInitializeInstanceForRuntime(workflowCoreRuntime);
|
|
this.workflowCoreRuntime = workflowCoreRuntime;
|
|
|
|
}
|
|
|
|
internal override void OnInitializeActivatingInstanceForRuntime(IWorkflowCoreRuntime workflowCoreRuntime)
|
|
{
|
|
//doing this will call OnRuntimeInitialized() which is a hook for the activity writers
|
|
//to initialize/wire up their DPs correctly for the activating instance
|
|
base.OnInitializeActivatingInstanceForRuntime(workflowCoreRuntime);
|
|
this.workflowCoreRuntime = workflowCoreRuntime;
|
|
}
|
|
|
|
internal override void FixUpMetaProperties(DependencyObject originalObject)
|
|
{
|
|
if (originalObject == null)
|
|
throw new ArgumentNullException();
|
|
|
|
// call base class
|
|
base.FixUpMetaProperties(originalObject);
|
|
}
|
|
internal virtual void FixUpParentChildRelationship(Activity definitionActivity, Activity parentActivity, Hashtable deserializedActivities)
|
|
{
|
|
// set parent for myself, root activity will have null parent
|
|
if (parentActivity != null)
|
|
this.SetParent((CompositeActivity)parentActivity);
|
|
}
|
|
internal virtual IList<Activity> CollectNestedActivities()
|
|
{
|
|
return null;
|
|
}
|
|
#endregion
|
|
|
|
#region Activity Status Change Signals
|
|
|
|
internal void SetStatus(ActivityExecutionStatus newStatus, bool transacted)
|
|
{
|
|
System.Workflow.Runtime.WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 0, "Activity Status Change - Activity: {0} Old:{1}; New:{2}", this.QualifiedName, ActivityExecutionStatusEnumToString(this.ExecutionStatus), ActivityExecutionStatusEnumToString(newStatus));
|
|
|
|
// Set Was Executing
|
|
if (newStatus == ActivityExecutionStatus.Faulting &&
|
|
this.ExecutionStatus == ActivityExecutionStatus.Executing)
|
|
{
|
|
this.SetValue(WasExecutingProperty, true);
|
|
}
|
|
this.SetValue(ExecutionStatusProperty, newStatus);
|
|
|
|
// fire status change events
|
|
FireStatusChangedEvents(Activity.StatusChangedEvent, transacted);
|
|
switch (newStatus)
|
|
{
|
|
case ActivityExecutionStatus.Closed:
|
|
FireStatusChangedEvents(Activity.ClosedEvent, transacted);
|
|
break;
|
|
case ActivityExecutionStatus.Executing:
|
|
FireStatusChangedEvents(Activity.ExecutingEvent, transacted);
|
|
break;
|
|
case ActivityExecutionStatus.Canceling:
|
|
FireStatusChangedEvents(Activity.CancelingEvent, transacted);
|
|
break;
|
|
case ActivityExecutionStatus.Faulting:
|
|
FireStatusChangedEvents(Activity.FaultingEvent, transacted);
|
|
break;
|
|
case ActivityExecutionStatus.Compensating:
|
|
FireStatusChangedEvents(Activity.CompensatingEvent, transacted);
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
// inform the workflow synchronously about this
|
|
this.WorkflowCoreRuntime.ActivityStatusChanged(this, transacted, false);
|
|
if (newStatus == ActivityExecutionStatus.Closed)
|
|
{
|
|
// remove these
|
|
this.RemoveProperty(Activity.LockCountOnStatusChangeProperty);
|
|
this.RemoveProperty(Activity.HasPrimaryClosedProperty);
|
|
this.RemoveProperty(Activity.WasExecutingProperty);
|
|
}
|
|
}
|
|
private void FireStatusChangedEvents(DependencyProperty dependencyProperty, bool transacted)
|
|
{
|
|
IList eventListeners = this.GetStatusChangeHandlers(dependencyProperty);
|
|
if (eventListeners != null)
|
|
{
|
|
ActivityExecutionStatusChangedEventArgs statusChangeEventArgs = new ActivityExecutionStatusChangedEventArgs(this.ExecutionStatus, this.ExecutionResult, this);
|
|
foreach (ActivityExecutorDelegateInfo<ActivityExecutionStatusChangedEventArgs> delegateInfo in eventListeners)
|
|
delegateInfo.InvokeDelegate(this.ContextActivity, statusChangeEventArgs, delegateInfo.ActivityQualifiedName == null, transacted);
|
|
}
|
|
}
|
|
internal void MarkCanceled()
|
|
{
|
|
if (this.ExecutionStatus != ActivityExecutionStatus.Closed)
|
|
{
|
|
if (this.ExecutionStatus != ActivityExecutionStatus.Canceling)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_InvalidCancelActivityState)); //DCR01
|
|
this.SetValue(ExecutionResultProperty, ActivityExecutionResult.Canceled);
|
|
this.MarkClosed();
|
|
}
|
|
}
|
|
internal void MarkCompleted()
|
|
{
|
|
this.SetValue(ExecutionResultProperty, ActivityExecutionResult.Succeeded);
|
|
this.MarkClosed();
|
|
}
|
|
internal void MarkCompensated()
|
|
{
|
|
if (this.ExecutionStatus != ActivityExecutionStatus.Compensating)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_InvalidCompensateActivityState)); //DCR01
|
|
|
|
this.SetValue(ExecutionResultProperty, ActivityExecutionResult.Compensated);
|
|
this.MarkClosed();
|
|
}
|
|
internal void MarkFaulted()
|
|
{
|
|
this.SetValue(ExecutionResultProperty, ActivityExecutionResult.Faulted);
|
|
this.MarkClosed();
|
|
}
|
|
private void MarkClosed()
|
|
{
|
|
switch (this.ExecutionStatus)
|
|
{
|
|
case ActivityExecutionStatus.Executing:
|
|
case ActivityExecutionStatus.Faulting:
|
|
case ActivityExecutionStatus.Compensating:
|
|
case ActivityExecutionStatus.Canceling:
|
|
break;
|
|
default:
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_InvalidCloseActivityState)); //DCR01
|
|
}
|
|
|
|
if (this is CompositeActivity)
|
|
{
|
|
foreach (Activity childActivity in ((CompositeActivity)this).Activities)
|
|
if (childActivity.Enabled && !(childActivity.ExecutionStatus == ActivityExecutionStatus.Initialized || childActivity.ExecutionStatus == ActivityExecutionStatus.Closed))
|
|
throw new InvalidOperationException(SR.GetString(System.Globalization.CultureInfo.CurrentCulture, SR.Error_ActiveChildExist));
|
|
|
|
ActivityExecutionContext currentContext = new ActivityExecutionContext(this);
|
|
|
|
foreach (ActivityExecutionContext childContext in currentContext.ExecutionContextManager.ExecutionContexts)
|
|
{
|
|
if (this.GetActivityByName(childContext.Activity.QualifiedName, true) != null)
|
|
throw new InvalidOperationException(SR.GetString(System.Globalization.CultureInfo.CurrentCulture, SR.Error_ActiveChildContextExist));
|
|
}
|
|
}
|
|
|
|
if (this.LockCountOnStatusChange > 0)
|
|
{
|
|
this.SetValue(HasPrimaryClosedProperty, true);
|
|
this.FireStatusChangedEvents(Activity.StatusChangedLockedEvent, false);
|
|
}
|
|
else if (this.parent == null ||
|
|
(this.ExecutionResult == ActivityExecutionResult.Succeeded && (this is ICompensatableActivity || this.PersistOnClose))
|
|
)
|
|
{
|
|
ActivityExecutionStatus oldStatus = this.ExecutionStatus;
|
|
ActivityExecutionResult oldOutcome = this.ExecutionResult;
|
|
|
|
this.SetStatus(ActivityExecutionStatus.Closed, true);
|
|
try
|
|
{
|
|
// The activity may remove any instance specific dependency properties to reduce serialization size
|
|
this.OnClosed(this.RootActivity.WorkflowCoreRuntime);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
this.SetValue(ExecutionResultProperty, ActivityExecutionResult.Faulted);
|
|
this.SetValueCommon(ActivityExecutionContext.CurrentExceptionProperty, e, ActivityExecutionContext.CurrentExceptionProperty.DefaultMetadata, false);
|
|
}
|
|
|
|
|
|
if (this.parent != null && (this is ICompensatableActivity))
|
|
{
|
|
this.SetValue(CompletedOrderIdProperty, this.IncrementCompletedOrderId());
|
|
}
|
|
if (CanUninitializeNow)
|
|
{
|
|
//
|
|
|
|
this.Uninitialize(this.RootActivity.WorkflowCoreRuntime);
|
|
this.SetValue(ExecutionResultProperty, ActivityExecutionResult.Uninitialized);
|
|
}
|
|
else if (this.parent == null) //Root Activity Closure
|
|
{
|
|
UninitializeCompletedContext(this, new ActivityExecutionContext(this));
|
|
}
|
|
|
|
try
|
|
{
|
|
Exception exception = (Exception)this.GetValue(ActivityExecutionContext.CurrentExceptionProperty);
|
|
if (exception != null && this.parent == null)
|
|
{
|
|
this.WorkflowCoreRuntime.ActivityStatusChanged(this, false, true);
|
|
// terminate the workflow instance
|
|
string errorString = "Uncaught exception escaped to the root of the workflow.\n"
|
|
+ string.Format(CultureInfo.CurrentCulture, " In instance {0} in activity {1}\n", new object[] { this.WorkflowInstanceId, string.Empty })
|
|
+ string.Format(CultureInfo.CurrentCulture, "Inner exception: {0}", new object[] { exception });
|
|
System.Workflow.Runtime.WorkflowTrace.Runtime.TraceEvent(TraceEventType.Critical, 0, errorString);
|
|
this.WorkflowCoreRuntime.TerminateInstance(exception);
|
|
}
|
|
else if (exception != null && this.parent != null)
|
|
{
|
|
this.WorkflowCoreRuntime.RaiseException(exception, this.Parent, string.Empty);
|
|
this.RemoveProperty(ActivityExecutionContext.CurrentExceptionProperty);
|
|
}
|
|
else if (this.parent == null || this.PersistOnClose)
|
|
{
|
|
this.WorkflowCoreRuntime.PersistInstanceState(this);
|
|
this.WorkflowCoreRuntime.ActivityStatusChanged(this, false, true);
|
|
|
|
// throw exception to outer
|
|
if (exception != null)
|
|
{
|
|
this.WorkflowCoreRuntime.RaiseException(exception, this.Parent, string.Empty);
|
|
this.RemoveProperty(ActivityExecutionContext.CurrentExceptionProperty);
|
|
}
|
|
}
|
|
|
|
// remove the cached lock values
|
|
Activity parent = this.parent;
|
|
while (parent != null)
|
|
{
|
|
if (parent.SupportsSynchronization || parent.Parent == null)
|
|
parent.RemoveProperty(ActivityExecutionContext.CachedGrantedLocksProperty);
|
|
|
|
parent = parent.parent;
|
|
}
|
|
|
|
}
|
|
catch
|
|
{
|
|
if (this.parent != null && (this is ICompensatableActivity))
|
|
{
|
|
this.RemoveProperty(CompletedOrderIdProperty);
|
|
this.DecrementCompletedOrderId();
|
|
}
|
|
this.SetValue(ExecutionResultProperty, oldOutcome);
|
|
this.SetStatus(oldStatus, true);
|
|
|
|
// copy back the old locks values
|
|
Activity parent = this.parent;
|
|
while (parent != null)
|
|
{
|
|
if (parent.SupportsSynchronization || parent.Parent == null)
|
|
{
|
|
object cachedGrantedLocks = parent.GetValue(ActivityExecutionContext.CachedGrantedLocksProperty);
|
|
if (cachedGrantedLocks != null)
|
|
parent.SetValue(ActivityExecutionContext.GrantedLocksProperty, cachedGrantedLocks);
|
|
parent.RemoveProperty(ActivityExecutionContext.CachedGrantedLocksProperty);
|
|
}
|
|
parent = parent.parent;
|
|
}
|
|
throw;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The activity may remove any instance specific dependency properties to reduce serialization size
|
|
this.SetStatus(ActivityExecutionStatus.Closed, false);
|
|
try
|
|
{
|
|
this.OnClosed(this.RootActivity.WorkflowCoreRuntime);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
this.SetValue(ExecutionResultProperty, ActivityExecutionResult.Faulted);
|
|
this.SetValueCommon(ActivityExecutionContext.CurrentExceptionProperty, e, ActivityExecutionContext.CurrentExceptionProperty.DefaultMetadata, false);
|
|
}
|
|
if (CanUninitializeNow)
|
|
{
|
|
//
|
|
|
|
this.Uninitialize(this.RootActivity.WorkflowCoreRuntime);
|
|
this.SetValue(ExecutionResultProperty, ActivityExecutionResult.Uninitialized);
|
|
}
|
|
|
|
Exception exception = (Exception)this.GetValue(ActivityExecutionContext.CurrentExceptionProperty);
|
|
if (exception != null)
|
|
{
|
|
this.WorkflowCoreRuntime.RaiseException(exception, this.Parent, string.Empty);
|
|
this.RemoveProperty(ActivityExecutionContext.CurrentExceptionProperty);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal bool CanUninitializeNow
|
|
{
|
|
get
|
|
{
|
|
//This check finds
|
|
//1) Existence of Succeeded ISC in same context.
|
|
//2) If activity is ContextActivity? Checks existence of completed child
|
|
//context which needs compensation
|
|
if (this.NeedsCompensation)
|
|
return false;
|
|
|
|
//3) If this activity is not a context activity, check for completed child context
|
|
//which needs compensation.
|
|
Activity contextActivity = this.ContextActivity;
|
|
|
|
if (contextActivity != this)
|
|
{
|
|
IList<ActivityExecutionContextInfo> childsCompletedContexts = contextActivity.GetValue(Activity.CompletedExecutionContextsProperty) as IList<ActivityExecutionContextInfo>;
|
|
|
|
if (childsCompletedContexts != null && childsCompletedContexts.Count > 0)
|
|
{
|
|
foreach (ActivityExecutionContextInfo contextInfo in childsCompletedContexts)
|
|
{
|
|
if ((contextInfo.Flags & PersistFlags.NeedsCompensation) != 0 && this.GetActivityByName(contextInfo.ActivityQualifiedName, true) != null)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Safe to Uninitialize this activity now.
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static void UninitializeCompletedContext(Activity activity, ActivityExecutionContext executionContext)
|
|
{
|
|
//Uninitialize Compensatable Children which ran in Sub Contextee.
|
|
IList<ActivityExecutionContextInfo> childsCompletedContexts = activity.GetValue(Activity.CompletedExecutionContextsProperty) as IList<ActivityExecutionContextInfo>;
|
|
|
|
if (childsCompletedContexts != null && childsCompletedContexts.Count > 0)
|
|
{
|
|
IList<ActivityExecutionContextInfo> childsCompletedContextsClone = new List<ActivityExecutionContextInfo>(childsCompletedContexts);
|
|
foreach (ActivityExecutionContextInfo contextInfo in childsCompletedContextsClone)
|
|
{
|
|
if ((contextInfo.Flags & PersistFlags.NeedsCompensation) != 0 && activity.GetActivityByName(contextInfo.ActivityQualifiedName, true) != null)
|
|
{
|
|
ActivityExecutionContext resurrectedContext = executionContext.ExecutionContextManager.DiscardPersistedExecutionContext(contextInfo);
|
|
UninitializeCompletedContext(resurrectedContext.Activity, resurrectedContext);
|
|
executionContext.ExecutionContextManager.CompleteExecutionContext(resurrectedContext);
|
|
}
|
|
}
|
|
}
|
|
|
|
//UnInitialize any compensatable children which ran in same context.
|
|
CompositeActivity compositeActivity = activity as CompositeActivity;
|
|
if (compositeActivity != null)
|
|
{
|
|
Activity[] compensatableChildren = CompensationUtils.GetCompensatableChildren(compositeActivity);
|
|
|
|
for (int i = compensatableChildren.Length - 1; i >= 0; --i)
|
|
{
|
|
Activity compensatableChild = (Activity)compensatableChildren.GetValue(i);
|
|
compensatableChild.Uninitialize(activity.RootActivity.WorkflowCoreRuntime);
|
|
compensatableChild.SetValue(ExecutionResultProperty, ActivityExecutionResult.Uninitialized);
|
|
}
|
|
}
|
|
|
|
//UnInitialize Self
|
|
activity.Uninitialize(activity.RootActivity.WorkflowCoreRuntime);
|
|
activity.SetValue(ExecutionResultProperty, ActivityExecutionResult.Uninitialized);
|
|
}
|
|
|
|
internal bool NeedsCompensation
|
|
{
|
|
get
|
|
{
|
|
IList<ActivityExecutionContextInfo> childsCompletedContexts = this.GetValue(Activity.CompletedExecutionContextsProperty) as IList<ActivityExecutionContextInfo>;
|
|
if (childsCompletedContexts != null && childsCompletedContexts.Count > 0)
|
|
{
|
|
foreach (ActivityExecutionContextInfo completedActivityInfo in childsCompletedContexts)
|
|
{
|
|
if ((completedActivityInfo.Flags & PersistFlags.NeedsCompensation) != 0 && this.GetActivityByName(completedActivityInfo.ActivityQualifiedName, true) != null)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// walk through all compensatable children and compensate them
|
|
Queue<Activity> completedActivities = new Queue<Activity>();
|
|
completedActivities.Enqueue(this);
|
|
while (completedActivities.Count > 0)
|
|
{
|
|
Activity completedChild = completedActivities.Dequeue();
|
|
if (completedChild is ICompensatableActivity &&
|
|
completedChild.ExecutionStatus == ActivityExecutionStatus.Closed &&
|
|
completedChild.ExecutionResult == ActivityExecutionResult.Succeeded)
|
|
return true;
|
|
|
|
if (completedChild is CompositeActivity)
|
|
{
|
|
foreach (Activity completedChild2 in ((CompositeActivity)completedChild).Activities)
|
|
{
|
|
if (completedChild2.Enabled)
|
|
completedActivities.Enqueue(completedChild2);
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Behaviors Supports
|
|
|
|
internal bool SupportsTransaction
|
|
{
|
|
get
|
|
{
|
|
return this is CompensatableTransactionScopeActivity || this is TransactionScopeActivity;
|
|
}
|
|
}
|
|
internal bool SupportsSynchronization
|
|
{
|
|
get
|
|
{
|
|
return this is SynchronizationScopeActivity;
|
|
}
|
|
}
|
|
internal bool PersistOnClose
|
|
{
|
|
get
|
|
{
|
|
if (this.UserData.Contains(typeof(PersistOnCloseAttribute)))
|
|
return (bool)this.UserData[typeof(PersistOnCloseAttribute)];
|
|
|
|
object[] attributes = this.GetType().GetCustomAttributes(typeof(PersistOnCloseAttribute), true);
|
|
return (attributes != null && attributes.Length > 0);
|
|
}
|
|
}
|
|
|
|
internal int IncrementCompletedOrderId()
|
|
{
|
|
int completedOrderId = (int)this.RootActivity.GetValue(Activity.CompletedOrderIdProperty);
|
|
this.RootActivity.SetValue(Activity.CompletedOrderIdProperty, completedOrderId + 1);
|
|
return (completedOrderId + 1);
|
|
}
|
|
internal void DecrementCompletedOrderId()
|
|
{
|
|
int completedOrderId = (int)this.RootActivity.GetValue(Activity.CompletedOrderIdProperty);
|
|
this.RootActivity.SetValue(Activity.CompletedOrderIdProperty, completedOrderId - 1);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region EnumToString Converters
|
|
|
|
internal static string ActivityExecutionStatusEnumToString(ActivityExecutionStatus status)
|
|
{
|
|
string retVal = string.Empty;
|
|
switch (status)
|
|
{
|
|
case ActivityExecutionStatus.Initialized:
|
|
retVal = "Initialized";
|
|
break;
|
|
case ActivityExecutionStatus.Executing:
|
|
retVal = "Executing";
|
|
break;
|
|
case ActivityExecutionStatus.Canceling:
|
|
retVal = "Canceling";
|
|
break;
|
|
case ActivityExecutionStatus.Faulting:
|
|
retVal = "Faulting";
|
|
break;
|
|
case ActivityExecutionStatus.Compensating:
|
|
retVal = "Compensating";
|
|
break;
|
|
case ActivityExecutionStatus.Closed:
|
|
retVal = "Closed";
|
|
break;
|
|
}
|
|
return retVal;
|
|
}
|
|
internal static string ActivityExecutionResultEnumToString(ActivityExecutionResult activityExecutionResult)
|
|
{
|
|
string retVal = string.Empty;
|
|
switch (activityExecutionResult)
|
|
{
|
|
case ActivityExecutionResult.None:
|
|
retVal = "None";
|
|
break;
|
|
case ActivityExecutionResult.Succeeded:
|
|
retVal = "Succeeded";
|
|
break;
|
|
case ActivityExecutionResult.Canceled:
|
|
retVal = "Canceled";
|
|
break;
|
|
case ActivityExecutionResult.Faulted:
|
|
retVal = "Faulted";
|
|
break;
|
|
case ActivityExecutionResult.Compensated:
|
|
retVal = "Compensated";
|
|
break;
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
#endregion
|
|
|
|
public override String ToString()
|
|
{
|
|
return this.QualifiedName + " [" + GetType().FullName + "]";
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Class CompositeActivity
|
|
|
|
[ContentProperty("Activities")]
|
|
[DesignerSerializer(typeof(CompositeActivityMarkupSerializer), typeof(WorkflowMarkupSerializer))]
|
|
[ActivityCodeGenerator(typeof(CompositeActivityCodeGenerator))]
|
|
[ActivityValidator(typeof(CompositeActivityValidator))]
|
|
[ActivityExecutor(typeof(CompositeActivityExecutor<CompositeActivity>))]
|
|
[TypeDescriptionProvider(typeof(CompositeActivityTypeDescriptorProvider))]
|
|
[Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")]
|
|
public class CompositeActivity : Activity, ISupportAlternateFlow
|
|
{
|
|
private static DependencyProperty CanModifyActivitiesProperty = DependencyProperty.Register("CanModifyActivities", typeof(bool), typeof(CompositeActivity), new PropertyMetadata(DependencyPropertyOptions.Metadata, new Attribute[] { new DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden) }));
|
|
|
|
[NonSerialized]
|
|
private ActivityCollection activities = null;
|
|
|
|
public CompositeActivity()
|
|
{
|
|
this.activities = new ActivityCollection(this);
|
|
this.activities.ListChanging += new EventHandler<ActivityCollectionChangeEventArgs>(OnListChangingEventHandler);
|
|
this.activities.ListChanged += new EventHandler<ActivityCollectionChangeEventArgs>(OnListChangedEventHandler);
|
|
|
|
SetValue(CanModifyActivitiesProperty, false);
|
|
}
|
|
|
|
public CompositeActivity(IEnumerable<Activity> children)
|
|
: this()
|
|
{
|
|
if (children == null)
|
|
throw new ArgumentNullException("children");
|
|
|
|
foreach (Activity child in children)
|
|
this.activities.Add(child);
|
|
}
|
|
|
|
public CompositeActivity(string name)
|
|
: base(name)
|
|
{
|
|
this.activities = new ActivityCollection(this);
|
|
this.activities.ListChanging += new EventHandler<ActivityCollectionChangeEventArgs>(OnListChangingEventHandler);
|
|
this.activities.ListChanged += new EventHandler<ActivityCollectionChangeEventArgs>(OnListChangedEventHandler);
|
|
|
|
SetValue(CanModifyActivitiesProperty, false);
|
|
}
|
|
|
|
protected Activity[] GetDynamicActivities(Activity activity)
|
|
{
|
|
if (activity == null)
|
|
throw new ArgumentNullException("activity");
|
|
|
|
// Work around - make sure that we return the parent property value
|
|
// otherwise .Parent property would have set the workflowCoreRuntime for parent
|
|
if (activity.parent != this)
|
|
throw new ArgumentException(SR.GetString(SR.GetDynamicActivities_InvalidActivity), "activity");
|
|
|
|
// get context activity
|
|
Activity contextActivity = this.ContextActivity;
|
|
List<Activity> dynamicActivities = new List<Activity>();
|
|
if (contextActivity != null)
|
|
{
|
|
IList<Activity> activeContextActivities = (IList<Activity>)contextActivity.GetValue(Activity.ActiveExecutionContextsProperty);
|
|
if (activeContextActivities != null)
|
|
{
|
|
foreach (Activity activeContextActivity in activeContextActivities)
|
|
{
|
|
if (activeContextActivity.MetaEquals(activity))
|
|
dynamicActivities.Add(activeContextActivity);
|
|
}
|
|
}
|
|
}
|
|
return dynamicActivities.ToArray();
|
|
}
|
|
|
|
protected internal override void Initialize(IServiceProvider provider)
|
|
{
|
|
if (provider == null)
|
|
throw new ArgumentNullException("provider");
|
|
|
|
if (!(provider is ActivityExecutionContext))
|
|
throw new ArgumentException(SR.GetString(SR.Error_InvalidServiceProvider, "provider"));
|
|
|
|
foreach (Activity childActivity in Helpers.GetAllEnabledActivities(this))
|
|
{
|
|
ActivityExecutionContext executionContext = provider as ActivityExecutionContext;
|
|
executionContext.InitializeActivity(childActivity);
|
|
}
|
|
}
|
|
|
|
protected internal override void Uninitialize(IServiceProvider provider)
|
|
{
|
|
if (provider == null)
|
|
throw new ArgumentNullException("provider");
|
|
|
|
foreach (Activity childActivity in Helpers.GetAllEnabledActivities(this))
|
|
{
|
|
//Case for Template/Conditional Branch/Non Context based Composite which
|
|
//exists in path between compensatable context.
|
|
if (childActivity.ExecutionResult != ActivityExecutionResult.Uninitialized)
|
|
{
|
|
childActivity.Uninitialize(provider);
|
|
childActivity.SetValue(ExecutionResultProperty, ActivityExecutionResult.Uninitialized);
|
|
}
|
|
}
|
|
base.Uninitialize(provider);
|
|
}
|
|
protected internal override void OnActivityExecutionContextLoad(IServiceProvider provider)
|
|
{
|
|
if (provider == null)
|
|
throw new ArgumentNullException("provider");
|
|
|
|
base.OnActivityExecutionContextLoad(provider);
|
|
|
|
foreach (Activity childActivity in Helpers.GetAllEnabledActivities(this))
|
|
{
|
|
childActivity.OnActivityExecutionContextLoad(provider);
|
|
}
|
|
}
|
|
protected internal override void OnActivityExecutionContextUnload(IServiceProvider provider)
|
|
{
|
|
if (provider == null)
|
|
throw new ArgumentNullException("provider");
|
|
|
|
base.OnActivityExecutionContextUnload(provider);
|
|
|
|
foreach (Activity childActivity in Helpers.GetAllEnabledActivities(this))
|
|
{
|
|
childActivity.OnActivityExecutionContextUnload(provider);
|
|
}
|
|
}
|
|
|
|
protected internal override ActivityExecutionStatus HandleFault(ActivityExecutionContext executionContext, Exception exception)
|
|
{
|
|
if (executionContext == null)
|
|
throw new ArgumentNullException("executionContext");
|
|
|
|
if (exception == null)
|
|
throw new ArgumentNullException("exception");
|
|
|
|
ActivityExecutionStatus newStatus = this.Cancel(executionContext);
|
|
if (newStatus == ActivityExecutionStatus.Canceling)
|
|
return ActivityExecutionStatus.Faulting;
|
|
|
|
return newStatus;
|
|
}
|
|
|
|
protected void ApplyWorkflowChanges(WorkflowChanges workflowChanges)
|
|
{
|
|
if (workflowChanges == null)
|
|
throw new ArgumentNullException("workflowChanges");
|
|
|
|
if (this.Parent != null)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_InvalidActivityForWorkflowChanges));
|
|
|
|
if (this.RootActivity == null)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_MissingRootActivity));
|
|
|
|
if (this.WorkflowCoreRuntime == null)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_NoRuntimeAvailable));
|
|
|
|
workflowChanges.ApplyTo(this);
|
|
}
|
|
|
|
|
|
#region Workflow Change Notification Methods
|
|
protected internal virtual void OnActivityChangeAdd(ActivityExecutionContext executionContext, Activity addedActivity)
|
|
{
|
|
if (executionContext == null)
|
|
throw new ArgumentNullException("executionContext");
|
|
|
|
if (addedActivity == null)
|
|
throw new ArgumentNullException("addedActivity");
|
|
|
|
|
|
}
|
|
|
|
protected internal virtual void OnActivityChangeRemove(ActivityExecutionContext executionContext, Activity removedActivity)
|
|
{
|
|
|
|
}
|
|
|
|
protected internal virtual void OnWorkflowChangesCompleted(ActivityExecutionContext rootContext)
|
|
{
|
|
|
|
}
|
|
#endregion
|
|
|
|
#region CompositeActivity Meta Properties
|
|
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
[Browsable(false)]
|
|
public ActivityCollection Activities
|
|
{
|
|
get
|
|
{
|
|
return this.activities;
|
|
}
|
|
}
|
|
|
|
protected internal bool CanModifyActivities
|
|
{
|
|
get
|
|
{
|
|
return (bool)GetValue(CanModifyActivitiesProperty);
|
|
}
|
|
set
|
|
{
|
|
SetValue(CanModifyActivitiesProperty, value);
|
|
if (this.Activities.Count > 0)
|
|
SetValue(CustomActivityProperty, true);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CompositeActivity Instance Properties
|
|
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
[Browsable(false)]
|
|
public ReadOnlyCollection<Activity> EnabledActivities
|
|
{
|
|
get
|
|
{
|
|
List<Activity> executableActivities = new List<Activity>();
|
|
foreach (Activity activity in this.activities)
|
|
{
|
|
// This check makes sure that only Enabled activities are returned
|
|
// and the framwork provided activities are skipped.
|
|
if (activity.Enabled && !Helpers.IsFrameworkActivity(activity))
|
|
executableActivities.Add(activity);
|
|
}
|
|
return executableActivities.AsReadOnly();
|
|
}
|
|
}
|
|
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
[Browsable(false)]
|
|
IList<Activity> ISupportAlternateFlow.AlternateFlowActivities
|
|
{
|
|
get
|
|
{
|
|
List<Activity> secondaryFlowActivities = new List<Activity>();
|
|
foreach (Activity activity in this.activities)
|
|
{
|
|
if (activity.Enabled && Helpers.IsFrameworkActivity(activity))
|
|
secondaryFlowActivities.Add(activity);
|
|
}
|
|
return secondaryFlowActivities.AsReadOnly();
|
|
}
|
|
}
|
|
|
|
internal override Activity TraverseDottedPath(string dottedPath)
|
|
{
|
|
string subPath = dottedPath;
|
|
string remainingPath = string.Empty;
|
|
int indexOfDot = dottedPath.IndexOf('.');
|
|
if (indexOfDot != -1)
|
|
{
|
|
subPath = dottedPath.Substring(0, indexOfDot);
|
|
remainingPath = dottedPath.Substring(indexOfDot + 1);
|
|
}
|
|
|
|
int index = Convert.ToInt32(subPath, CultureInfo.InvariantCulture);
|
|
if (index >= this.activities.Count)
|
|
return null;
|
|
|
|
Activity nextActivity = this.activities[index];
|
|
if (!string.IsNullOrEmpty(remainingPath))
|
|
return nextActivity.TraverseDottedPath(remainingPath);
|
|
return nextActivity;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Runtime Initialize
|
|
|
|
internal override void OnInitializeDefinitionForRuntime()
|
|
{
|
|
// only if we are in design mode, execute this code, other wise ignore this call
|
|
if (this.DesignMode)
|
|
{
|
|
// call base
|
|
base.OnInitializeDefinitionForRuntime();
|
|
|
|
// get the lookup path
|
|
Activity rootActivity = this.RootActivity;
|
|
Hashtable lookupPaths = (Hashtable)rootActivity.UserData[UserDataKeys.LookupPaths];
|
|
string thisLookupPath = (string)lookupPaths[this.QualifiedName];
|
|
|
|
// call initializeForRuntime for every activity
|
|
foreach (Activity childActivity in (IList)this.activities)
|
|
{
|
|
if (childActivity.Enabled)
|
|
{
|
|
// setup lookup path
|
|
string lookupPath = thisLookupPath;
|
|
if (!string.IsNullOrEmpty(thisLookupPath))
|
|
lookupPath += ".";
|
|
lookupPath += this.activities.IndexOf(childActivity).ToString(CultureInfo.InvariantCulture);
|
|
lookupPaths.Add(childActivity.QualifiedName, lookupPath);
|
|
|
|
// initialize for runtime
|
|
((IDependencyObjectAccessor)childActivity).InitializeDefinitionForRuntime(null);
|
|
}
|
|
else
|
|
{
|
|
// There are sevrel properties that are required even for disabled activities. They include
|
|
// DottedPath, QualifiedName and Readonly. To initialize these properties, we call
|
|
// OnInitializeDefinitionForRuntime directly and skip the InitializeProperties call inside
|
|
// IDependencyObjectAccessor.InitializeDefinitionForRuntime because other properties are not
|
|
// validated and they may not initialize properly, which the runtime really doesn't care.
|
|
childActivity.OnInitializeDefinitionForRuntime();
|
|
childActivity.Readonly = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
internal override void OnInitializeInstanceForRuntime(IWorkflowCoreRuntime workflowCoreRuntime)
|
|
{
|
|
base.OnInitializeInstanceForRuntime(workflowCoreRuntime);
|
|
|
|
// call children to do initialize runtime instance
|
|
foreach (Activity childActivity in this.activities)
|
|
{
|
|
if (childActivity.Enabled)
|
|
((IDependencyObjectAccessor)childActivity).InitializeInstanceForRuntime(workflowCoreRuntime);
|
|
}
|
|
}
|
|
|
|
internal override void OnInitializeActivatingInstanceForRuntime(IWorkflowCoreRuntime workflowCoreRuntime)
|
|
{
|
|
// call base: this will call activity
|
|
base.OnInitializeActivatingInstanceForRuntime(workflowCoreRuntime);
|
|
|
|
// call children to do initialize runtime instance
|
|
foreach (Activity childActivity in this.activities)
|
|
{
|
|
if (childActivity.Enabled)
|
|
((IDependencyObjectAccessor)childActivity).InitializeActivatingInstanceForRuntime(null, workflowCoreRuntime);
|
|
else
|
|
this.Readonly = true;
|
|
}
|
|
}
|
|
|
|
internal override void FixUpMetaProperties(DependencyObject originalObject)
|
|
{
|
|
if (originalObject == null)
|
|
throw new ArgumentNullException();
|
|
if (!(originalObject is CompositeActivity))
|
|
throw new ArgumentException();
|
|
|
|
// call base
|
|
base.FixUpMetaProperties(originalObject);
|
|
|
|
// ask each child to fixup
|
|
if (this.activities != null)
|
|
{
|
|
CompositeActivity originalCompositeActivity = originalObject as CompositeActivity;
|
|
if (originalCompositeActivity != null)
|
|
{
|
|
int index = 0;
|
|
foreach (Activity childActivity in this.activities)
|
|
childActivity.FixUpMetaProperties(originalCompositeActivity.activities[index++]);
|
|
}
|
|
}
|
|
}
|
|
internal override void FixUpParentChildRelationship(Activity definitionActivity, Activity parentActivity, Hashtable deserializedActivities)
|
|
{
|
|
CompositeActivity definitionCompositeActivity = definitionActivity as CompositeActivity;
|
|
if (definitionCompositeActivity == null)
|
|
throw new ArgumentException("definitionActivity");
|
|
|
|
// call base
|
|
base.FixUpParentChildRelationship(definitionActivity, parentActivity, deserializedActivities);
|
|
|
|
// fix up the children collection
|
|
this.activities = new ActivityCollection(this);
|
|
this.activities.ListChanging += new EventHandler<ActivityCollectionChangeEventArgs>(OnListChangingEventHandler);
|
|
this.activities.ListChanged += new EventHandler<ActivityCollectionChangeEventArgs>(OnListChangedEventHandler);
|
|
|
|
// detect if there was a context
|
|
string prefix = this.DottedPath;
|
|
|
|
// fixup all the children, and then call them to fixup their relation ships
|
|
int index = 0;
|
|
foreach (Activity definitionChildActivity in definitionCompositeActivity.activities)
|
|
{
|
|
Activity childActivity = (Activity)deserializedActivities[prefix.Length == 0 ? index.ToString(CultureInfo.InvariantCulture) : prefix + "." + index.ToString(CultureInfo.InvariantCulture)];
|
|
this.activities.InnerAdd(childActivity);
|
|
|
|
// ask child to fix up its parent child relation ship
|
|
childActivity.FixUpParentChildRelationship(definitionChildActivity, this, deserializedActivities);
|
|
index++;
|
|
}
|
|
}
|
|
internal override IList<Activity> CollectNestedActivities()
|
|
{
|
|
List<Activity> nestedActivities = new List<Activity>();
|
|
Queue<Activity> activityQueue = new Queue<Activity>(this.activities);
|
|
while (activityQueue.Count > 0)
|
|
{
|
|
Activity nestedActivity = activityQueue.Dequeue();
|
|
nestedActivities.Add(nestedActivity);
|
|
if (nestedActivity is CompositeActivity)
|
|
{
|
|
foreach (Activity nestedChildActivity in ((CompositeActivity)nestedActivity).activities)
|
|
activityQueue.Enqueue(nestedChildActivity);
|
|
}
|
|
}
|
|
return nestedActivities;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Collection's Event Handlers
|
|
private void OnListChangingEventHandler(object sender, ActivityCollectionChangeEventArgs e)
|
|
{
|
|
if (!this.DesignMode && !this.DynamicUpdateMode)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_CanNotChangeAtRuntime));
|
|
|
|
if (!this.CanModifyActivities)
|
|
{
|
|
// Check the ActivityType only during design mode
|
|
if (this.DesignMode && Activity.ActivityType != null && this.GetType() == Activity.ActivityType)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_Missing_CanModifyProperties_True, this.GetType().FullName));
|
|
|
|
if (!IsDynamicMode(this) && CannotModifyChildren(this, false))
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_CannotAddRemoveChildActivities));
|
|
|
|
if (IsDynamicMode(this) && CannotModifyChildren(this, true))
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_CannotAddRemoveChildActivities));
|
|
}
|
|
|
|
if (e.Action == ActivityCollectionChangeAction.Add && e.AddedItems != null)
|
|
{
|
|
Activity parent = this;
|
|
while (parent != null)
|
|
{
|
|
if (e.AddedItems.Contains(parent))
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_ActivityCircularReference));
|
|
|
|
parent = parent.Parent;
|
|
}
|
|
}
|
|
|
|
OnListChanging(e);
|
|
}
|
|
|
|
protected virtual void OnListChanging(ActivityCollectionChangeEventArgs e)
|
|
{
|
|
if (e == null)
|
|
throw new ArgumentNullException("e");
|
|
if (e.Action == ActivityCollectionChangeAction.Add && e.AddedItems != null)
|
|
{
|
|
foreach (Activity activity in e.AddedItems)
|
|
{
|
|
if (activity.Parent != null)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_ActivityHasParent, activity.QualifiedName, activity.Parent.QualifiedName));
|
|
if (activity == this)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_Recursion, activity.QualifiedName));
|
|
}
|
|
}
|
|
if (((IComponent)this).Site != null)
|
|
{
|
|
IComponentChangeService changeService = ((IComponent)this).Site.GetService(typeof(IComponentChangeService)) as IComponentChangeService;
|
|
if (changeService != null)
|
|
changeService.OnComponentChanging(this, null);
|
|
}
|
|
}
|
|
|
|
private void OnListChangedEventHandler(object sender, ActivityCollectionChangeEventArgs e)
|
|
{
|
|
OnListChanged(e);
|
|
}
|
|
|
|
protected virtual void OnListChanged(ActivityCollectionChangeEventArgs e)
|
|
{
|
|
if (e == null)
|
|
throw new ArgumentNullException("e");
|
|
// remove the parent
|
|
if ((e.Action == ActivityCollectionChangeAction.Replace || e.Action == ActivityCollectionChangeAction.Remove) &&
|
|
e.RemovedItems != null)
|
|
{
|
|
foreach (Activity activity in e.RemovedItems)
|
|
activity.SetParent(null);
|
|
}
|
|
|
|
// set the parent on the activity
|
|
if ((e.Action == ActivityCollectionChangeAction.Replace || e.Action == ActivityCollectionChangeAction.Add) &&
|
|
e.AddedItems != null)
|
|
{
|
|
foreach (Activity activity in e.AddedItems)
|
|
activity.SetParent(this);
|
|
|
|
Queue<Activity> queue = new Queue<Activity>(e.AddedItems as IEnumerable<Activity>);
|
|
while (queue.Count > 0)
|
|
{
|
|
Activity activity = queue.Dequeue() as Activity;
|
|
if (activity != null && (activity.Name == null || activity.Name.Length == 0 || activity.Name == activity.GetType().Name))
|
|
{
|
|
Activity rootActivity = Helpers.GetRootActivity(activity);
|
|
string className = rootActivity.GetValue(WorkflowMarkupSerializer.XClassProperty) as string;
|
|
if (rootActivity.Parent == null || !string.IsNullOrEmpty(className))
|
|
{
|
|
ArrayList identifiers = new ArrayList();
|
|
identifiers.AddRange(Helpers.GetIdentifiersInCompositeActivity(rootActivity as CompositeActivity));
|
|
activity.Name = DesignerHelpers.GenerateUniqueIdentifier(((IComponent)this).Site, Helpers.GetBaseIdentifier(activity), (string[])identifiers.ToArray(typeof(string)));
|
|
}
|
|
}
|
|
if (activity is CompositeActivity)
|
|
{
|
|
foreach (Activity activity2 in ((CompositeActivity)activity).Activities)
|
|
queue.Enqueue(activity2);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
if (((IComponent)this).Site != null)
|
|
{
|
|
IComponentChangeService changeService = ((IComponent)this).Site.GetService(typeof(IComponentChangeService)) as IComponentChangeService;
|
|
if (changeService != null)
|
|
changeService.OnComponentChanged(this, null, e, null);
|
|
}
|
|
}
|
|
|
|
private static bool IsDynamicMode(CompositeActivity compositeActivity)
|
|
{
|
|
if (compositeActivity == null)
|
|
throw new ArgumentNullException("compositeActivity");
|
|
|
|
while (compositeActivity.Parent != null)
|
|
{
|
|
if (compositeActivity.DynamicUpdateMode)
|
|
return true;
|
|
compositeActivity = compositeActivity.Parent;
|
|
}
|
|
return compositeActivity.DynamicUpdateMode;
|
|
}
|
|
|
|
private static bool CannotModifyChildren(CompositeActivity compositeActivity, bool parent)
|
|
{
|
|
if (compositeActivity == null)
|
|
throw new ArgumentNullException("compositeActivity");
|
|
|
|
if (parent && compositeActivity.Parent == null)
|
|
return false;
|
|
|
|
if ((bool)compositeActivity.GetValue(CustomActivityProperty) == true)
|
|
return true;
|
|
|
|
if (compositeActivity.Parent != null)
|
|
return CannotModifyChildren(compositeActivity.Parent, parent);
|
|
|
|
return false;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IDisposable
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
foreach (Activity activity in this.Activities)
|
|
activity.Dispose();
|
|
}
|
|
base.Dispose(disposing);
|
|
}
|
|
#endregion
|
|
}
|
|
#endregion
|
|
}
|