/// <summary> /// Create internal states /// </summary> /// <param name="metadata">NativeActivityMetadata reference.</param> private void ProcessStates(NativeActivityMetadata metadata) { // remove duplicate state in the collection during evaluation IEnumerable <State> distinctStates = this.states.Distinct(); foreach (State state in distinctStates) { InternalState internalState = state.InternalState; this.internalStates.Add(internalState); DelegateInArgument <StateMachineEventManager> eventManager = new DelegateInArgument <Statements.StateMachineEventManager>(); internalState.EventManager = eventManager; ActivityFunc <StateMachineEventManager, string> activityFunc = new ActivityFunc <StateMachineEventManager, string> { Argument = eventManager, Handler = internalState, }; if (state.Reachable) { // If this state is not reached, we should not add it as child because it's even not well validated. metadata.AddDelegate(activityFunc, /* origin = */ state); } this.internalStateFuncs.Add(activityFunc); } }
private void ProcessStates(NativeActivityMetadata metadata) { foreach (System.Activities.Statements.State state in this.states.Distinct <System.Activities.Statements.State>()) { InternalState internalState = state.InternalState; this.internalStates.Add(internalState); DelegateInArgument <StateMachineEventManager> argument = new DelegateInArgument <StateMachineEventManager>(); internalState.EventManager = argument; ActivityFunc <StateMachineEventManager, string> activityDelegate = new ActivityFunc <StateMachineEventManager, string> { Argument = argument, Handler = internalState }; if (state.Reachable) { metadata.AddDelegate(activityDelegate); } this.internalStateFuncs.Add(activityDelegate); } }
protected override void OnCreateDynamicUpdateMap(NativeActivityUpdateMapMetadata metadata, Activity originalActivity) { InternalState originalInternalState = (InternalState)originalActivity; // NOTE: State.Entry/Exit are allowed to be removed, because it doesn't change the execution semantics of SM // if this removed activity was executing, WF runtime would disallow the update. Activity entryActivityMatch = metadata.GetMatch(this.Entry); Activity exitActivityMatch = metadata.GetMatch(this.Exit); if ((null != entryActivityMatch && !object.ReferenceEquals(entryActivityMatch, originalInternalState.Entry)) || (null != exitActivityMatch && !object.ReferenceEquals(exitActivityMatch, originalInternalState.Exit))) { // original State.Entry/Exit is replaced with another child activities with InternalState // new State.Entry/Exit is moved from another child activities within InternalState. metadata.DisallowUpdateInsideThisActivity(SR.MovingActivitiesInStateBlockDU); return; } int originalTriggerInUpdatedDefinition = 0; foreach (InternalTransition originalTransition in originalInternalState.internalTransitions) { if (metadata.IsReferenceToImportedChild(originalTransition.Trigger)) { metadata.DisallowUpdateInsideThisActivity(SR.TriggerOrConditionIsReferenced); return; } if (!originalTransition.IsUnconditional) { // new Trigger activity foreach (TransitionData transitionData in originalTransition.TransitionDataList) { if (metadata.IsReferenceToImportedChild(transitionData.Condition)) { metadata.DisallowUpdateInsideThisActivity(SR.TriggerOrConditionIsReferenced); return; } } } } foreach (InternalTransition updatedTransition in this.internalTransitions) { if (metadata.IsReferenceToImportedChild(updatedTransition.Trigger)) { // if the trigger is referenced, it might have another save values already. metadata.DisallowUpdateInsideThisActivity(SR.TriggerOrConditionIsReferenced); return; } Activity triggerMatch = metadata.GetMatch(updatedTransition.Trigger); if (null != triggerMatch) { InternalTransition originalTransition; if (originalInternalState.triggerInternalTransitionMapping.TryGetValue(triggerMatch, out originalTransition)) { originalTriggerInUpdatedDefinition++; if (originalTransition.IsUnconditional) { string errorMessage; bool canTransitionBeUpdated = ValidateDUInUnconditionalTransition(metadata, updatedTransition, originalTransition, out errorMessage); if (!canTransitionBeUpdated) { metadata.DisallowUpdateInsideThisActivity(errorMessage); return; } } else { if (updatedTransition.IsUnconditional) { // cannot change the transition from condition to unconditional. metadata.DisallowUpdateInsideThisActivity(SR.ChangeConditionalTransitionToUnconditionalBlockDU); return; } else { string errorMessage; bool canTransitionBeUpdated = ValidateDUInConditionTransition(metadata, updatedTransition, originalTransition, out errorMessage); if (!canTransitionBeUpdated) { metadata.DisallowUpdateInsideThisActivity(errorMessage); return; } } } } else { // the trigger is an child activity moved from elsewhere within the state metadata.DisallowUpdateInsideThisActivity(SR.MovingActivitiesInStateBlockDU); return; } } else { // new Trigger activity foreach (TransitionData transitionData in updatedTransition.TransitionDataList) { if ((null != transitionData.Condition && null != metadata.GetMatch(transitionData.Condition)) || (null != transitionData.Action && null != metadata.GetMatch(transitionData.Action))) { // if a new transition is added, it is expected that the Condition/Action // are newly created. metadata.DisallowUpdateInsideThisActivity(SR.ChangingTriggerOrUseOriginalConditionActionBlockDU); return; } } } } if (originalTriggerInUpdatedDefinition != originalInternalState.internalTransitions.Count) { // NOTE: in general, if the transition is removed when there are pending triggers, // runtime would be able to detect the missing child activities. However, in cases, // where the transition is happening already (in between completion of Transition.Action // callback but before InternalState is completed), the workflow definition can be unloaded // and updated. The InternalState is unable to trace the original transition that set the // destination state index. In that case, the update would fail at UpdateInstance. // To simplify the model, it is more convenient to disallow removing existing transitions // from an executing InternalState. The only extra restriction it brings, is that it disables // update even if the InternalState is uploaded at State.Entry. This scenario, however, is uncommon. metadata.DisallowUpdateInsideThisActivity(SR.RemovingTransitionsBlockDU); } }
/// <summary> /// Clear internal state. /// </summary> internal void ClearInternalState() { this.internalState = null; }