protected override void UpdateInstance(NativeActivityUpdateContext updateContext) { StateMachineEventManager eventManager = updateContext.GetValue(this.EventManager) as StateMachineEventManager; Fx.Assert(eventManager != null, "eventManager is available in every internalActivity."); if (eventManager.CurrentBeingProcessedEvent != null || eventManager.Queue.Any()) { // Updated state is evaluating conditions or transitioning to another state, // Then we need to update the index of the current evaluated trigger (in case the trigger is moved) // and the condition index. // if the state is transitioning already, then we should update destination state id. bool isUpdateSuccessful = this.UpdateEventManager(updateContext, eventManager); if (!isUpdateSuccessful) { updateContext.DisallowUpdate(SR.DUTriggerOrConditionChangedDuringTransitioning); return; } if (updateContext.GetValue(this.isExiting) != true) { this.RescheduleNewlyAddedTriggers(updateContext); } } else if (updateContext.GetValue(this.currentRunningTriggers) > 0) { Fx.Assert(updateContext.GetValue(this.isExiting) != true, "No triggers have completed, state should not be transitioning."); // the state is not transitioning yet and is persisted at trigger. this.RescheduleNewlyAddedTriggers(updateContext); } }
protected override void UpdateInstance(NativeActivityUpdateContext updateContext) { TryCatchState state = updateContext.GetValue(this.state); if (state != null && !state.SuppressCancel && state.CaughtException != null && this.FindCatch(state.CaughtException.Exception) == null) { // This is a very small window of time in which we want to block update inside TryCatch. // This is in between OnExceptionFromTry faultHandler and OnTryComplete completionHandler. // A Catch handler could be found at OnExceptionFromTry before update, yet that appropriate Catch handler could have been removed during update and not be found at OnTryComplete. // In such case, the exception can be unintentionally ----ed without ever propagating it upward. // Such TryCatch state is detected by inspecting the TryCatchState private variable for SuppressCancel == false && CaughtException != Null && this.FindCatch(state.CaughtException.Exception) == null. updateContext.DisallowUpdate(SR.TryCatchInvalidStateForUpdate(state.CaughtException.Exception)); } }
/// <summary> /// Used for Dynamic Update: after the instance is updated, if the statemachine is already transitioning, the index of the to-be-scheduled state /// would need to be updated. /// </summary> /// <param name="updateContext">Dynamic Update context</param> /// <param name="eventManager">Internal StateMachineEventManager</param> /// <returns>True, 1. if update is successful and the instanced is updated with the new indexes, and 2 all the trigger ID in the queue are updated; /// false otherwise and the update should fail.</returns> private bool UpdateEventManager( NativeActivityUpdateContext updateContext, StateMachineEventManager eventManager) { Fx.Assert(null != eventManager.CurrentBeingProcessedEvent, "The eventManager must have some info that needs to be updated during transition."); int updatedEventsInQueue = 0; int originalTriggerId = int.MinValue; int originalConditionIndex = int.MinValue; bool updateCurrentEventSucceed = null == eventManager.CurrentBeingProcessedEvent ? true : false; foreach (InternalTransition transition in this.internalTransitions) { object savedTriggerIndex = updateContext.GetSavedOriginalValue(transition.Trigger); if (savedTriggerIndex != null) { Fx.Assert(!updateContext.IsNewlyAdded(transition.Trigger), "the trigger in transition already exist."); if (null != eventManager.CurrentBeingProcessedEvent && eventManager.CurrentBeingProcessedEvent.TriggedId == (int)savedTriggerIndex) { // found a match of the running trigger update the current processed event // Don't match the trigger ID, match only when the Condition is also matched. if (eventManager.CurrentConditionIndex == -1) { if (transition.IsUnconditional) { // executing transition before persist is unconditional originalTriggerId = eventManager.CurrentBeingProcessedEvent.TriggedId; originalConditionIndex = 0; eventManager.CurrentBeingProcessedEvent.TriggedId = transition.InternalTransitionIndex; if (updateContext.GetValue(this.isExiting)) { Fx.Assert(eventManager.OnTransition, "The state is transitioning."); updateContext.SetValue(this.Result, GetTo(transition.InternalTransitionIndex)); } updateCurrentEventSucceed = true; } else { updateContext.DisallowUpdate(SR.ChangeTransitionTypeDuringTransitioningBlockDU); return false; } } else if (eventManager.CurrentConditionIndex >= 0) { Fx.Assert(!transition.IsUnconditional, "Cannot update a running conditional transition with a unconditional one."); if (!transition.IsUnconditional) { // executing transition before and after are conditional for (int updatedIndex = 0; updatedIndex < transition.TransitionDataList.Count; updatedIndex++) { Activity condition = transition.TransitionDataList[updatedIndex].Condition; Fx.Assert(null != condition, "Conditional transition must have Condition activity."); int? savedCondIndex = updateContext.GetSavedOriginalValue(condition) as int?; if (eventManager.CurrentConditionIndex == savedCondIndex) { originalTriggerId = eventManager.CurrentBeingProcessedEvent.TriggedId; originalConditionIndex = eventManager.CurrentConditionIndex; eventManager.CurrentBeingProcessedEvent.TriggedId = transition.InternalTransitionIndex; eventManager.CurrentConditionIndex = updatedIndex; if (updateContext.GetValue(this.isExiting)) { Fx.Assert(eventManager.OnTransition, "The state is transitioning."); updateContext.SetValue(this.Result, this.GetTo(transition.InternalTransitionIndex, (int)updatedIndex)); } updateCurrentEventSucceed = true; break; } } } } } foreach (TriggerCompletedEvent completedEvent in eventManager.Queue) { if ((int)savedTriggerIndex == completedEvent.TriggedId) { completedEvent.TriggedId = transition.InternalTransitionIndex; updatedEventsInQueue++; } } } } return eventManager.Queue.Count() == updatedEventsInQueue ? updateCurrentEventSucceed : false; }
protected override void UpdateInstance(NativeActivityUpdateContext updateContext) { // we only care about the server-side Receive since the client-side Receive is not persistable. // only valid instance update condition is when a bookmark with OperationBookmarkName is found. CorrelationHandle followingCorrelation = (this.CorrelatesWith == null) ? null : (CorrelationHandle)updateContext.GetValue(this.CorrelatesWith); if (followingCorrelation == null) { followingCorrelation = updateContext.FindExecutionProperty(CorrelationHandle.StaticExecutionPropertyName) as CorrelationHandle; } BookmarkScope bookmarkScope; if (followingCorrelation != null && followingCorrelation.Scope != null) { bookmarkScope = followingCorrelation.Scope; } else { bookmarkScope = updateContext.DefaultBookmarkScope; } string savedOriginalOperationName = (string)updateContext.GetSavedOriginalValue(OperationNamePropertyName); XName savedOriginalServiceContractName = (XName)updateContext.GetSavedOriginalValue(ServiceContractNamePropertyName); if ((savedOriginalOperationName == null && savedOriginalServiceContractName == null) || (savedOriginalOperationName == this.OperationName && savedOriginalServiceContractName == this.ServiceContractName)) { // neither ServiceContractName nor OperationName have changed // nothing to do, so exit early. return; } string originalOperationBookmarkName = BookmarkNameHelper.CreateBookmarkName(savedOriginalOperationName ?? this.OperationName, savedOriginalServiceContractName ?? this.ServiceContractName); if (updateContext.RemoveBookmark(originalOperationBookmarkName, bookmarkScope)) { // if we are here, it means Receive is on the server-side and waiting for a request message to arrive updateContext.CreateBookmark(this.OperationBookmarkName, new BookmarkCallback(this.OnMessage), bookmarkScope); } else { // this means Receive is in a state DU is not allowed. updateContext.DisallowUpdate(SR.InvalidReceiveStateForDU); } }