#pragma warning disable 1634, 1691 namespace System.Workflow.ComponentModel { #region Imports using System; using System.Collections; using System.Collections.Specialized; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.ComponentModel; using System.ComponentModel.Design; using System.ComponentModel.Design.Serialization; using System.Reflection; using System.Workflow.ComponentModel.Compiler; using System.Workflow.ComponentModel.Serialization; using System.Workflow.ComponentModel.Design; using System.Xml; using System.IO; #endregion [Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")] public sealed class WorkflowChanges { #region Data members public static readonly DependencyProperty ConditionProperty = DependencyProperty.RegisterAttached("Condition", typeof(ActivityCondition), typeof(WorkflowChanges), new PropertyMetadata(DependencyPropertyOptions.Metadata)); internal static DependencyProperty WorkflowChangeActionsProperty = DependencyProperty.RegisterAttached("WorkflowChangeActions", typeof(IList), typeof(WorkflowChanges), new PropertyMetadata(DependencyPropertyOptions.NonSerialized)); internal static DependencyProperty WorkflowChangeVersionProperty = DependencyProperty.RegisterAttached("WorkflowChangeVersion", typeof(Guid), typeof(WorkflowChanges), new PropertyMetadata(Guid.Empty, DependencyPropertyOptions.NonSerialized)); private Activity originalRootActivity = null; private Activity clonedRootActivity = null; private List modelChangeActions = new List(); private bool saved = false; #endregion #region Constuctor & Destructor public WorkflowChanges(Activity rootActivity) { if (rootActivity == null) throw new ArgumentNullException("rootActivity"); if (!(rootActivity is CompositeActivity) || rootActivity.Parent != null) throw new ArgumentException(SR.GetString(SR.Error_RootActivityTypeInvalid2), "rootActivity"); #pragma warning suppress 56506 if (rootActivity.DesignMode) throw new InvalidOperationException(SR.GetString(SR.Error_NoRuntimeAvailable)); // get the original activity this.originalRootActivity = (Activity)((Activity)rootActivity).GetValue(Activity.WorkflowDefinitionProperty); if (this.originalRootActivity == null) this.originalRootActivity = rootActivity; // Work around: for dynamic update create a clone, without calling initialize for runtime this.clonedRootActivity = (Activity)CloneRootActivity(originalRootActivity); // make the tree readonly ApplyDynamicUpdateMode((Activity)this.clonedRootActivity); } #endregion #region Public members // WhenConditionProperty Get and Set Accessors public static object GetCondition(object dependencyObject) { if (dependencyObject == null) throw new ArgumentNullException("dependencyObject"); if (!(dependencyObject is DependencyObject)) throw new ArgumentException(SR.GetString(SR.Error_UnexpectedArgumentType, typeof(DependencyObject).FullName), "dependencyObject"); return (dependencyObject as DependencyObject).GetValue(ConditionProperty); } public static void SetCondition(object dependencyObject, object value) { if (dependencyObject == null) throw new ArgumentNullException("dependencyObject"); if (!(dependencyObject is DependencyObject)) throw new ArgumentException(SR.GetString(SR.Error_UnexpectedArgumentType, typeof(DependencyObject).FullName), "dependencyObject"); (dependencyObject as DependencyObject).SetValue(ConditionProperty, value); } public CompositeActivity TransientWorkflow { get { return this.clonedRootActivity as CompositeActivity; } } public ValidationErrorCollection Validate() { TypeProvider typeProvider = CreateTypeProvider(this.originalRootActivity); // create service provider ServiceContainer serviceContainer = new ServiceContainer(); serviceContainer.AddService(typeof(ITypeProvider), typeProvider); ValidationManager validationManager = new ValidationManager(serviceContainer); ValidationErrorCollection errors; using (WorkflowCompilationContext.CreateScope(validationManager)) { errors = ValidationHelpers.ValidateObject(validationManager, this.clonedRootActivity); } return XomlCompilerHelper.MorphIntoFriendlyValidationErrors(errors); } private void Save() { ValidationErrorCollection errors = Validate(); if (errors.HasErrors) throw new WorkflowValidationFailedException(SR.GetString(SR.Error_CompilerValidationFailed), errors); //work around !!!for conditions we do diff object originalConditions = ((Activity)this.originalRootActivity).GetValue(ConditionTypeConverter.DeclarativeConditionDynamicProp); object changedConditions = ((Activity)this.clonedRootActivity).GetValue(ConditionTypeConverter.DeclarativeConditionDynamicProp); if (null != originalConditions) this.modelChangeActions.AddRange(((IWorkflowChangeDiff)originalConditions).Diff(originalConditions, changedConditions)); else if (null != changedConditions) this.modelChangeActions.AddRange(((IWorkflowChangeDiff)changedConditions).Diff(originalConditions, changedConditions)); // diff the process model this.modelChangeActions.AddRange(DiffTrees(this.originalRootActivity as CompositeActivity, this.clonedRootActivity as CompositeActivity)); // always call it after diff tree, otherwise it turns on the Locked. ReleaseDynamicUpdateMode((Activity)this.clonedRootActivity); // cache the change actions into the new workflow definition ArrayList workflowChanges = (ArrayList)((Activity)this.clonedRootActivity).GetValue(WorkflowChanges.WorkflowChangeActionsProperty); if (workflowChanges == null) { workflowChanges = new ArrayList(); ((Activity)this.clonedRootActivity).SetValue(WorkflowChanges.WorkflowChangeActionsProperty, workflowChanges); } workflowChanges.AddRange(this.modelChangeActions); ((Activity)this.clonedRootActivity).SetValue(WorkflowChanges.WorkflowChangeVersionProperty, Guid.NewGuid()); this.saved = true; // now initialize for runtime ((IDependencyObjectAccessor)this.clonedRootActivity).InitializeDefinitionForRuntime(null); } internal void ApplyTo(Activity activity) { if (activity == null) throw new ArgumentNullException("activity"); if (activity.Parent != null) throw new ArgumentException(SR.GetString(SR.Error_RootActivityTypeInvalid), "activity"); if (activity.RootActivity == null) throw new InvalidOperationException(SR.GetString(SR.Error_MissingRootActivity)); if (activity.WorkflowCoreRuntime == null) throw new InvalidOperationException(SR.GetString(SR.Error_NoRuntimeAvailable)); if (this.saved) throw new InvalidOperationException(SR.GetString(SR.Error_TransactionAlreadyApplied)); if (!CompareWorkflowDefinition((Activity)this.originalRootActivity, (Activity)activity.RootActivity.GetValue(Activity.WorkflowDefinitionProperty))) throw new ArgumentException(SR.GetString(SR.Error_WorkflowDefinitionModified), "activity"); this.Save(); // go up in the chain and then apply changes IWorkflowCoreRuntime workflowCoreRuntime = activity.WorkflowCoreRuntime; if (workflowCoreRuntime.CurrentAtomicActivity != null) throw new InvalidOperationException(SR.GetString(SR.Error_InsideAtomicScope)); bool suspended = workflowCoreRuntime.SuspendInstance(SR.GetString(SR.SuspendReason_WorkflowChange)); try { // collect all context Activities List contextActivities = new List(); Queue contextActivitiesQueue = new Queue(); contextActivitiesQueue.Enqueue(workflowCoreRuntime.RootActivity); while (contextActivitiesQueue.Count > 0) { Activity contextActivity = contextActivitiesQueue.Dequeue(); contextActivities.Add(contextActivity); // enqueue child context Activities IList nestedContextActivities = (IList)contextActivity.GetValue(Activity.ActiveExecutionContextsProperty); if (nestedContextActivities != null) { foreach (Activity nestedContextActivity in nestedContextActivities) contextActivitiesQueue.Enqueue(nestedContextActivity); } } // run instance level validations ValidationErrorCollection validationErrors = new ValidationErrorCollection(); foreach (WorkflowChangeAction changeAction in this.modelChangeActions) { if (changeAction is ActivityChangeAction) { foreach (Activity contextActivity in contextActivities) { // WinOE Bug 16903: Ask the contextActivity itself whether or not it can be removed. // An activity can not be removed if it's in the executing mode. if (changeAction is RemovedActivityAction && contextActivity.DottedPath == ((RemovedActivityAction)changeAction).OriginalRemovedActivity.DottedPath) validationErrors.AddRange(changeAction.ValidateChanges(contextActivity)); // Ask the parent context activity whether or not this child activity can be added or removed. // The call to TraverseDottedPathFromRoot here should return the parent context activity for this change action. if (contextActivity.TraverseDottedPathFromRoot(((ActivityChangeAction)changeAction).OwnerActivityDottedPath) != null) validationErrors.AddRange(changeAction.ValidateChanges(contextActivity)); } } } // if errors then return if (validationErrors.HasErrors) throw new WorkflowValidationFailedException(SR.GetString(SR.Error_RuntimeValidationFailed), validationErrors); // verify if workflow can be changed VerifyWorkflowCanBeChanged(workflowCoreRuntime); // inform workflow runtime workflowCoreRuntime.OnBeforeDynamicChange(this.modelChangeActions); // set the new Workflow Definition workflowCoreRuntime.RootActivity.SetValue(Activity.WorkflowDefinitionProperty, this.clonedRootActivity); // apply changes to all context Activities foreach (Activity contextActivity in contextActivities) { // apply change to state reader foreach (WorkflowChangeAction changeAction in this.modelChangeActions) { if (changeAction is ActivityChangeAction) { if (contextActivity.TraverseDottedPathFromRoot(((ActivityChangeAction)changeAction).OwnerActivityDottedPath) != null) { bool result = changeAction.ApplyTo(contextActivity); Debug.Assert(result, "ApplyTo failed"); } } } // fixup meta properties and notify changes // if the context activity is the one that's being removed, we do not fixup the meta properties. Activity clonedActivity = ((Activity)this.clonedRootActivity).GetActivityByName(contextActivity.QualifiedName); if (clonedActivity != null) contextActivity.FixUpMetaProperties(clonedActivity); NotifyChangesToChildExecutors(workflowCoreRuntime, contextActivity, this.modelChangeActions); NotifyChangesCompletedToChildExecutors(workflowCoreRuntime, contextActivity); } // inform workflow runtime workflowCoreRuntime.OnAfterDynamicChange(true, this.modelChangeActions); } catch { workflowCoreRuntime.OnAfterDynamicChange(false, this.modelChangeActions); throw; } finally { if (suspended) workflowCoreRuntime.Resume(); } } #endregion #region Internal Helpers private void OnActivityListChanged(object sender, ActivityCollectionChangeEventArgs e) { if (e.RemovedItems != null) { foreach (Activity removedActivity in e.RemovedItems) { if (removedActivity.Readonly) ReleaseDynamicUpdateMode(removedActivity); } } } private void ApplyDynamicUpdateMode(Activity seedActivity) { Queue queue = new Queue(); queue.Enqueue(seedActivity); while (queue.Count > 0) { Activity activity = queue.Dequeue(); activity.Readonly = true; activity.DynamicUpdateMode = true; foreach (DependencyProperty dependencyProperty in activity.MetaDependencyProperties) { if (activity.IsBindingSet(dependencyProperty)) { ActivityBind activityBind = activity.GetBinding(dependencyProperty); if (activityBind != null) activityBind.DynamicUpdateMode = true; } } if (activity is CompositeActivity) { CompositeActivity compositeActivity = activity as CompositeActivity; compositeActivity.Activities.ListChanged += new EventHandler(this.OnActivityListChanged); foreach (Activity activity2 in ((CompositeActivity)activity).Activities) queue.Enqueue(activity2); } } } private void ReleaseDynamicUpdateMode(Activity seedActivity) { Queue queue = new Queue(); queue.Enqueue(seedActivity); while (queue.Count > 0) { Activity activity = queue.Dequeue() as Activity; activity.Readonly = false; activity.DynamicUpdateMode = false; foreach (DependencyProperty dependencyProperty in activity.MetaDependencyProperties) { if (activity.IsBindingSet(dependencyProperty)) { ActivityBind activityBind = activity.GetBinding(dependencyProperty); if (activityBind != null) activityBind.DynamicUpdateMode = false; } } if (activity is CompositeActivity) { CompositeActivity compositeActivity = activity as CompositeActivity; compositeActivity.Activities.ListChanged -= new EventHandler(this.OnActivityListChanged); foreach (Activity activity2 in ((CompositeActivity)activity).Activities) queue.Enqueue(activity2); } } } private void VerifyWorkflowCanBeChanged(IWorkflowCoreRuntime workflowCoreRuntime) { // check if the update is allowed on this root-activity. ActivityCondition dynamicUpdateCondition = ((Activity)workflowCoreRuntime.RootActivity).GetValue(WorkflowChanges.ConditionProperty) as ActivityCondition; if (dynamicUpdateCondition != null) { using (workflowCoreRuntime.SetCurrentActivity(workflowCoreRuntime.RootActivity)) { if (!dynamicUpdateCondition.Evaluate(workflowCoreRuntime.RootActivity, workflowCoreRuntime)) throw new InvalidOperationException(SR.GetString(CultureInfo.CurrentCulture, SR.Error_DynamicUpdateEvaluation, new object[] { workflowCoreRuntime.InstanceID.ToString() })); } } } private void NotifyChangesCompletedToChildExecutors(IWorkflowCoreRuntime workflowCoreRuntime, Activity contextActivity) { Queue compositeActivities = new Queue(); compositeActivities.Enqueue(contextActivity); while (compositeActivities.Count > 0) { CompositeActivity compositeActivity = compositeActivities.Dequeue() as CompositeActivity; if (compositeActivity == null || !WorkflowChanges.IsActivityExecutable(compositeActivity)) continue; ISupportWorkflowChanges compositeActivityExecutor = ActivityExecutors.GetActivityExecutor(compositeActivity) as ISupportWorkflowChanges; if (compositeActivityExecutor != null) { using (workflowCoreRuntime.SetCurrentActivity(compositeActivity)) { using (ActivityExecutionContext executionContext = new ActivityExecutionContext(compositeActivity)) compositeActivityExecutor.OnWorkflowChangesCompleted(executionContext); } } foreach (Activity activity in compositeActivity.Activities) { if (activity is CompositeActivity) compositeActivities.Enqueue(activity); } } } // internal static bool IsActivityExecutable(Activity activity) { if (!activity.Enabled) return false; if (activity.Parent != null) return IsActivityExecutable(activity.Parent); return activity.Enabled; } private void NotifyChangesToChildExecutors(IWorkflowCoreRuntime workflowCoreRuntime, Activity contextActivity, IList changeActions) { foreach (WorkflowChangeAction action in changeActions) { if (!(action is ActivityChangeAction)) continue; CompositeActivity ownerActivity = contextActivity.TraverseDottedPathFromRoot(((ActivityChangeAction)action).OwnerActivityDottedPath) as CompositeActivity; if (ownerActivity == null || !WorkflowChanges.IsActivityExecutable(ownerActivity)) continue; ISupportWorkflowChanges compositeActivityExecutor = ActivityExecutors.GetActivityExecutor(ownerActivity) as ISupportWorkflowChanges; if (compositeActivityExecutor == null) throw new ApplicationException(SR.GetString(SR.Error_WorkflowChangesNotSupported, ownerActivity.GetType().FullName)); using (workflowCoreRuntime.SetCurrentActivity(ownerActivity)) { using (ActivityExecutionContext executionContext = new ActivityExecutionContext(ownerActivity)) { if (action is AddedActivityAction) { Activity addedActivity = ownerActivity.Activities[((AddedActivityAction)action).Index]; if (WorkflowChanges.IsActivityExecutable(addedActivity)) { addedActivity.OnActivityExecutionContextLoad(executionContext.Activity.RootActivity.WorkflowCoreRuntime); executionContext.InitializeActivity(addedActivity); compositeActivityExecutor.OnActivityAdded(executionContext, addedActivity); } } else if (action is RemovedActivityAction) { RemovedActivityAction removedActivityAction = (RemovedActivityAction)action; if (WorkflowChanges.IsActivityExecutable(removedActivityAction.OriginalRemovedActivity)) { compositeActivityExecutor.OnActivityRemoved(executionContext, removedActivityAction.OriginalRemovedActivity); if (removedActivityAction.OriginalRemovedActivity.ExecutionResult != ActivityExecutionResult.Uninitialized) { removedActivityAction.OriginalRemovedActivity.Uninitialize(executionContext.Activity.RootActivity.WorkflowCoreRuntime); removedActivityAction.OriginalRemovedActivity.SetValue(Activity.ExecutionResultProperty, ActivityExecutionResult.Uninitialized); } removedActivityAction.OriginalRemovedActivity.OnActivityExecutionContextUnload(executionContext.Activity.RootActivity.WorkflowCoreRuntime); removedActivityAction.OriginalRemovedActivity.Dispose(); } } } } } } #endregion #region Static helpers private static bool CompareWorkflowDefinition(Activity originalWorkflowDefinition, Activity currentWorkflowDefinition) { if (originalWorkflowDefinition == currentWorkflowDefinition) return true; if (originalWorkflowDefinition.GetType() != currentWorkflowDefinition.GetType()) return false; Guid originalChangeVersion = (Guid)originalWorkflowDefinition.GetValue(WorkflowChanges.WorkflowChangeVersionProperty); Guid currentChangeVersion = (Guid)currentWorkflowDefinition.GetValue(WorkflowChanges.WorkflowChangeVersionProperty); return (originalChangeVersion == currentChangeVersion); } private static List DiffTrees(CompositeActivity originalCompositeActivity, CompositeActivity clonedCompositeActivity) { List listChanges = new List(); IEnumerator clonedActivitiesEnum = clonedCompositeActivity.Activities.GetEnumerator(); IEnumerator originalActivitiesEnum = originalCompositeActivity.Activities.GetEnumerator(); int currentRemoveIndex = 0; while (originalActivitiesEnum.MoveNext()) { bool foundMatching = false; Activity originalActivity = originalActivitiesEnum.Current; while (clonedActivitiesEnum.MoveNext()) { Activity clonedActivity = clonedActivitiesEnum.Current; if (clonedActivity.Readonly) { if (originalActivity.DottedPath == clonedActivity.CachedDottedPath) { currentRemoveIndex++; foundMatching = true; if (originalActivity is CompositeActivity) listChanges.AddRange(DiffTrees(originalActivity as CompositeActivity, clonedActivity as CompositeActivity)); break; } else { listChanges.Add(new RemovedActivityAction(currentRemoveIndex, originalActivity, clonedCompositeActivity)); while (originalActivitiesEnum.MoveNext()) { originalActivity = originalActivitiesEnum.Current; if (originalActivity.DottedPath == clonedActivity.CachedDottedPath) { currentRemoveIndex++; foundMatching = true; if (originalActivity is CompositeActivity) listChanges.AddRange(DiffTrees(originalActivity as CompositeActivity, clonedActivity as CompositeActivity)); break; } else { listChanges.Add(new RemovedActivityAction(currentRemoveIndex, originalActivity, clonedCompositeActivity)); } } } break; } else { listChanges.Add(new AddedActivityAction(clonedCompositeActivity, clonedActivity)); currentRemoveIndex++; } } if (!foundMatching) { listChanges.Add(new RemovedActivityAction(currentRemoveIndex, originalActivity, clonedCompositeActivity)); } } while (clonedActivitiesEnum.MoveNext()) listChanges.Add(new AddedActivityAction(clonedCompositeActivity, clonedActivitiesEnum.Current)); return listChanges; } private static Activity CloneRootActivity(Activity originalRootActivity) { // create new definition root string xomlText = originalRootActivity.GetValue(Activity.WorkflowXamlMarkupProperty) as string; string rulesText = null; Activity clonedRootActivity = null; IServiceProvider serviceProvider = originalRootActivity.GetValue(Activity.WorkflowRuntimeProperty) as IServiceProvider; Debug.Assert(serviceProvider != null); if (!string.IsNullOrEmpty(xomlText)) { rulesText = originalRootActivity.GetValue(Activity.WorkflowRulesMarkupProperty) as string; clonedRootActivity = Activity.OnResolveActivityDefinition(null, xomlText, rulesText, true, false, serviceProvider); } else clonedRootActivity = Activity.OnResolveActivityDefinition(originalRootActivity.GetType(), null, null, true, false, serviceProvider); if (clonedRootActivity == null) throw new NullReferenceException(SR.GetString(SR.Error_InvalidRootForWorkflowChanges)); // deserialize change history and apply it to new definition tree ArrayList workflowChanges = (ArrayList)((Activity)originalRootActivity).GetValue(WorkflowChanges.WorkflowChangeActionsProperty); if (workflowChanges != null) { workflowChanges = CloneWorkflowChangeActions(workflowChanges, originalRootActivity); if (workflowChanges != null) { // apply changes to the shared schedule Defn to get the instance specific copy foreach (WorkflowChangeAction action in workflowChanges) { bool result = action.ApplyTo((Activity)clonedRootActivity); Debug.Assert(result, "ApplyTo Failed"); } ((Activity)clonedRootActivity).SetValue(WorkflowChanges.WorkflowChangeActionsProperty, workflowChanges); } } return clonedRootActivity; } private static ArrayList CloneWorkflowChangeActions(ArrayList workflowChanges, Activity rootActivity) { if (workflowChanges == null) throw new ArgumentNullException("workflowChanges"); if (rootActivity == null) throw new ArgumentNullException("rootActivity"); string dynamicUpdateHistory = null; TypeProvider typeProvider = CreateTypeProvider(rootActivity); ServiceContainer serviceContainer = new ServiceContainer(); serviceContainer.AddService(typeof(ITypeProvider), typeProvider); DesignerSerializationManager manager = new DesignerSerializationManager(serviceContainer); WorkflowMarkupSerializer xomlSerializer = new WorkflowMarkupSerializer(); ArrayList clonedWorkflowChanges = null; // serialize dynamic updates using (manager.CreateSession()) { using (StringWriter sw = new StringWriter(CultureInfo.InvariantCulture)) { using (XmlWriter xmlWriter = Helpers.CreateXmlWriter(sw)) { WorkflowMarkupSerializationManager xomlSerializationManager = new WorkflowMarkupSerializationManager(manager); xomlSerializer.Serialize(xomlSerializationManager, xmlWriter, workflowChanges); dynamicUpdateHistory = sw.ToString(); } } // deserialize those using (StringReader sr = new StringReader(dynamicUpdateHistory)) { using (XmlReader xmlReader = XmlReader.Create(sr)) { WorkflowMarkupSerializationManager xomlSerializationManager = new WorkflowMarkupSerializationManager(manager); clonedWorkflowChanges = xomlSerializer.Deserialize(xomlSerializationManager, xmlReader) as ArrayList; } } } return clonedWorkflowChanges; } internal static TypeProvider CreateTypeProvider(Activity rootActivity) { TypeProvider typeProvider = new TypeProvider(null); Type companionType = rootActivity.GetType(); typeProvider.SetLocalAssembly(companionType.Assembly); typeProvider.AddAssembly(companionType.Assembly); foreach (AssemblyName assemblyName in companionType.Assembly.GetReferencedAssemblies()) { Assembly referencedAssembly = null; try { referencedAssembly = Assembly.Load(assemblyName); if (referencedAssembly != null) typeProvider.AddAssembly(referencedAssembly); } catch { } if (referencedAssembly == null && assemblyName.CodeBase != null) typeProvider.AddAssemblyReference(assemblyName.CodeBase); } return typeProvider; } #endregion } #region WorkflowChangeAction classes [DesignerSerializer(typeof(WorkflowMarkupSerializer), typeof(WorkflowMarkupSerializer))] [Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")] public abstract class WorkflowChangeAction { protected internal abstract bool ApplyTo(Activity rootActivity); protected internal abstract ValidationErrorCollection ValidateChanges(Activity activity); } [DesignerSerializer(typeof(ActivityChangeActionMarkupSerializer), typeof(WorkflowMarkupSerializer))] [Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")] public abstract class ActivityChangeAction : WorkflowChangeAction { private string ownerActivityDottedPath = string.Empty; protected ActivityChangeAction() { } protected ActivityChangeAction(CompositeActivity compositeActivity) { if (compositeActivity == null) throw new ArgumentNullException("compositeActivity"); this.ownerActivityDottedPath = compositeActivity.DottedPath; } [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public string OwnerActivityDottedPath { get { return this.ownerActivityDottedPath; } internal set { this.ownerActivityDottedPath = value; } } protected internal override ValidationErrorCollection ValidateChanges(Activity contextActivity) { if (contextActivity == null) throw new ArgumentNullException("contextActivity"); ValidationErrorCollection errors = new ValidationErrorCollection(); CompositeActivity ownerActivity = contextActivity.TraverseDottedPathFromRoot(this.OwnerActivityDottedPath) as CompositeActivity; if (ownerActivity != null && WorkflowChanges.IsActivityExecutable(ownerActivity)) { foreach (Validator validator in ComponentDispenser.CreateComponents(ownerActivity.GetType(), typeof(ActivityValidatorAttribute))) { ValidationError error = validator.ValidateActivityChange(ownerActivity, this); if (error != null) errors.Add(error); } } return errors; } } [Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")] public sealed class AddedActivityAction : ActivityChangeAction { private int index = 0; private Activity addedActivity = null; public AddedActivityAction() { } public AddedActivityAction(CompositeActivity compositeActivity, Activity activityAdded) : base(compositeActivity) { if (compositeActivity == null) throw new ArgumentNullException("compositeActivity"); if (activityAdded == null) throw new ArgumentNullException("activityAdded"); this.index = (compositeActivity.Activities != null) ? compositeActivity.Activities.IndexOf(activityAdded) : -1; this.addedActivity = activityAdded; } public int Index { get { return this.index; } internal set { this.index = value; } } public Activity AddedActivity { get { return this.addedActivity; } internal set { this.addedActivity = value; } } protected internal override bool ApplyTo(Activity rootActivity) { if (rootActivity == null) throw new ArgumentNullException("rootActivity"); if (!(rootActivity is CompositeActivity)) throw new ArgumentException(SR.GetString(SR.Error_RootActivityTypeInvalid), "rootActivity"); CompositeActivity ownerActivity = rootActivity.TraverseDottedPathFromRoot(this.OwnerActivityDottedPath) as CompositeActivity; if (ownerActivity == null) return false; // !!!work around: ownerActivity.DynamicUpdateMode = true; CompositeActivity addedActivityOwner = this.addedActivity.Parent; try { this.addedActivity.SetParent(ownerActivity); Activity clonedAddedActivity = this.addedActivity; if (!this.addedActivity.DesignMode) clonedAddedActivity = this.addedActivity.Clone(); // We need to serialize and deserialize in order to clone during design mode else { TypeProvider typeProvider = WorkflowChanges.CreateTypeProvider(rootActivity); ServiceContainer serviceContainer = new ServiceContainer(); serviceContainer.AddService(typeof(ITypeProvider), typeProvider); DesignerSerializationManager manager = new DesignerSerializationManager(serviceContainer); WorkflowMarkupSerializer xomlSerializer = new WorkflowMarkupSerializer(); string addedActivityText = string.Empty; // serialize dynamic updates using (manager.CreateSession()) { using (StringWriter sw = new StringWriter(CultureInfo.InvariantCulture)) { using (XmlWriter xmlWriter = Helpers.CreateXmlWriter(sw)) { WorkflowMarkupSerializationManager xomlSerializationManager = new WorkflowMarkupSerializationManager(manager); xomlSerializer.Serialize(xomlSerializationManager, xmlWriter, this.addedActivity); addedActivityText = sw.ToString(); } } // deserialize those using (StringReader sr = new StringReader(addedActivityText)) { using (XmlReader xmlReader = XmlReader.Create(sr)) { WorkflowMarkupSerializationManager xomlSerializationManager = new WorkflowMarkupSerializationManager(manager); clonedAddedActivity = xomlSerializer.Deserialize(xomlSerializationManager, xmlReader) as Activity; } } } if (clonedAddedActivity == null) throw new InvalidOperationException(SR.GetString(SR.Error_ApplyDynamicChangeFailed)); } if (ownerActivity.WorkflowCoreRuntime != null) ((IDependencyObjectAccessor)clonedAddedActivity).InitializeInstanceForRuntime(ownerActivity.WorkflowCoreRuntime); clonedAddedActivity.SetParent(null); ownerActivity.Activities.Insert(this.index, clonedAddedActivity); } finally { this.addedActivity.SetParent(addedActivityOwner); ownerActivity.DynamicUpdateMode = false; } return true; } } [Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")] public sealed class RemovedActivityAction : ActivityChangeAction { private int removedActivityIndex = -1; private Activity originalRemovedActivity = null; public RemovedActivityAction() { } public RemovedActivityAction(int removedActivityIndex, Activity originalActivity, CompositeActivity clonedParentActivity) : base(clonedParentActivity) { if (originalActivity == null) throw new ArgumentNullException("originalActivity"); if (clonedParentActivity == null) throw new ArgumentNullException("clonedParentActivity"); this.originalRemovedActivity = originalActivity; this.removedActivityIndex = removedActivityIndex; } [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public int RemovedActivityIndex { get { return this.removedActivityIndex; } internal set { this.removedActivityIndex = value; } } [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Activity OriginalRemovedActivity { get { return this.originalRemovedActivity; } internal set { this.originalRemovedActivity = value; } } protected internal override ValidationErrorCollection ValidateChanges(Activity contextActivity) { ValidationErrorCollection errors = base.ValidateChanges(contextActivity); Activity removedActivityInContext = contextActivity.TraverseDottedPathFromRoot(this.originalRemovedActivity.DottedPath); if (WorkflowChanges.IsActivityExecutable(removedActivityInContext) && removedActivityInContext.ExecutionStatus == ActivityExecutionStatus.Executing) errors.Add(new ValidationError(SR.GetString(SR.Error_RemoveExecutingActivity, this.originalRemovedActivity.QualifiedName), ErrorNumbers.Error_RemoveExecutingActivity)); return errors; } protected internal override bool ApplyTo(Activity rootActivity) { if (rootActivity == null) throw new ArgumentNullException("rootActivity"); if (!(rootActivity is CompositeActivity)) throw new ArgumentException(SR.GetString(SR.Error_RootActivityTypeInvalid), "rootActivity"); CompositeActivity ownerActivity = rootActivity.TraverseDottedPathFromRoot(this.OwnerActivityDottedPath) as CompositeActivity; if (ownerActivity == null) return false; if (this.removedActivityIndex >= ownerActivity.Activities.Count) return false; // !!!work around: ownerActivity.DynamicUpdateMode = true; try { this.originalRemovedActivity = ownerActivity.Activities[this.removedActivityIndex]; ownerActivity.Activities.RemoveAt(this.removedActivityIndex); } finally { ownerActivity.DynamicUpdateMode = false; } return true; } } #endregion #region Class ActivityChangeActionMarkupSerializer internal sealed class ActivityChangeActionMarkupSerializer : WorkflowMarkupSerializer { protected internal override PropertyInfo[] GetProperties(WorkflowMarkupSerializationManager serializationManager, object obj) { List properties = new List(base.GetProperties(serializationManager, obj)); //Collect the internal properties, we do this so that activity change action apis don't need to expose unnecessary setters foreach (PropertyInfo property in obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy)) { DesignerSerializationVisibility visibility = Helpers.GetSerializationVisibility(property); if (visibility != DesignerSerializationVisibility.Hidden && property.GetSetMethod() == null && property.GetSetMethod(true) != null) properties.Add(property); } return properties.ToArray(); } } #endregion }