Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / System.Activities / System / Activities / Statements / CompensableActivity.cs / 1305376 / CompensableActivity.cs
//---------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //--------------------------------------------------------------- namespace System.Activities.Statements { using System.Activities.Validation; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Runtime; using System.Runtime.Collections; using System.Windows.Markup; using System.Linq; [ContentProperty("Body")] public sealed class CompensableActivity : NativeActivity{ static Constraint noCompensableActivityInSecondaryRoot = CompensableActivity.NoCompensableActivityInSecondaryRoot(); Collection variables; CompensationParticipant compensationParticipant; // workflowCompensationBehavior field is used to store the singleton WokflowCompensationBehavior activity which needs to be scheduled once. // We currenly don't have runtime support to store both activity's name and activity. Using this field as a work around. WorkflowCompensationBehavior workflowCompensationBehavior; Variable currentCompensationId; Variable currentCompensationToken; // This id will be passed to secondary root. Variable compensationId; public CompensableActivity() : base() { this.currentCompensationToken = new Variable (); this.currentCompensationId = new Variable (); this.compensationId = new Variable (); } public Collection Variables { get { if (this.variables == null) { this.variables = new ValidatingCollection { // disallow null values OnAddValidationCallback = item => { if (item == null) { throw FxTrace.Exception.ArgumentNull("item"); } } }; } return this.variables; } } [DefaultValue(null)] [DependsOn("Variables")] public Activity Body { get; set; } [DefaultValue(null)] [DependsOn("Body")] public Activity CancellationHandler { get; set; } [DefaultValue(null)] [DependsOn("CancellationHandler")] public Activity CompensationHandler { get; set; } [DefaultValue(null)] [DependsOn("CompensationHandler")] public Activity ConfirmationHandler { get; set; } protected override bool CanInduceIdle { get { return true; } } // Internal properties. CompensationParticipant CompensationParticipant { get { if (this.compensationParticipant == null) { this.compensationParticipant = new CompensationParticipant(this.compensationId); if (CompensationHandler != null) { this.compensationParticipant.CompensationHandler = CompensationHandler; } if (ConfirmationHandler != null) { this.compensationParticipant.ConfirmationHandler = ConfirmationHandler; } if (CancellationHandler != null) { this.compensationParticipant.CancellationHandler = CancellationHandler; } } return this.compensationParticipant; } set { this.compensationParticipant = value; } } protected override void CacheMetadata(NativeActivityMetadata metadata) { metadata.SetVariablesCollection(this.Variables); metadata.SetImplementationVariablesCollection( new Collection { this.currentCompensationId, this.currentCompensationToken, // Add the variables which are only used by the secondary root this.compensationId }); if (this.Body != null) { metadata.SetChildrenCollection(new Collection { this.Body }); } // Declare the handlers as public children. if (this.CompensationHandler != null) { metadata.AddImportedChild(this.CompensationHandler); } if (this.ConfirmationHandler != null) { metadata.AddImportedChild(this.ConfirmationHandler); } if (this.CancellationHandler != null) { metadata.AddImportedChild(this.CancellationHandler); } Collection implementationChildren = new Collection (); if (!this.IsSingletonActivityDeclared(CompensationActivityStrings.WorkflowImplicitCompensationBehavior)) { this.workflowCompensationBehavior = new WorkflowCompensationBehavior(); this.DeclareSingletonActivity(CompensationActivityStrings.WorkflowImplicitCompensationBehavior); implementationChildren.Add(this.workflowCompensationBehavior); metadata.AddDefaultExtensionProvider(CreateCompensationExtension); } // Clear the cached handler values as workflow definition could be updated. CompensationParticipant = null; implementationChildren.Add(CompensationParticipant); metadata.SetImplementationChildrenCollection(implementationChildren); } CompensationExtension CreateCompensationExtension() { Fx.Assert(this.workflowCompensationBehavior != null, "workflowCompensationBehavior should be assigned in CacheMetadata."); CompensationExtension compensationExtension = new CompensationExtension(); compensationExtension.WorkflowCompensationBehavior = this.workflowCompensationBehavior; return compensationExtension; } internal override IList InternalGetConstraints() { return new List (1) { noCompensableActivityInSecondaryRoot }; } static Constraint NoCompensableActivityInSecondaryRoot() { DelegateInArgument validationContext = new DelegateInArgument { Name = "validationContext" }; DelegateInArgument element = new DelegateInArgument { Name = "element" }; Variable assertFlag = new Variable { Name = "assertFlag", Default = true }; Variable > elements = new Variable >() { Name = "elements" }; Variable index = new Variable () { Name = "index" }; return new Constraint { Body = new ActivityAction { Argument1 = element, Argument2 = validationContext, Handler = new Sequence { Variables = { assertFlag, elements, index }, Activities = { new Assign > { To = elements, Value = new GetParentChain { ValidationContext = validationContext, }, }, new While(env => (assertFlag.Get(env) != false) && index.Get(env) < elements.Get(env).Count()) { Body = new Sequence { Activities = { new If(env => (elements.Get(env).ElementAt(index.Get(env))).GetType() == typeof(CompensationParticipant)) { Then = new Assign { To = assertFlag, Value = false }, }, new Assign { To = index, Value = new InArgument (env => index.Get(env) + 1) }, } } }, new AssertValidation { Assertion = new InArgument (assertFlag), Message = new InArgument (SR.NoCAInSecondaryRoot) } } } } }; } protected override void Execute(NativeActivityContext context) { CompensationExtension compensationExtension = context.GetExtension (); Fx.Assert(compensationExtension != null, "CompensationExtension must be valid"); if (compensationExtension.IsWorkflowCompensationBehaviorScheduled) { ScheduleBody(context, compensationExtension); } else { compensationExtension.SetupWorkflowCompensationBehavior(context, new BookmarkCallback(OnWorkflowCompensationBehaviorScheduled)); } } protected override void Cancel(NativeActivityContext context) { context.CancelChildren(); } void OnWorkflowCompensationBehaviorScheduled(NativeActivityContext context, Bookmark bookmark, object value) { CompensationExtension compensationExtension = context.GetExtension (); Fx.Assert(compensationExtension != null, "CompensationExtension must be valid"); ScheduleBody(context, compensationExtension); } void ScheduleBody(NativeActivityContext context, CompensationExtension compensationExtension) { Fx.Assert(compensationExtension != null, "CompensationExtension must be valid"); CompensationToken parentToken = null; long parentCompensationId = CompensationToken.RootCompensationId; parentToken = (CompensationToken)context.Properties.Find(CompensationToken.PropertyName); if (parentToken != null) { if (compensationExtension.Get(parentToken.CompensationId).IsTokenValidInSecondaryRoot) { throw FxTrace.Exception.AsError(new InvalidOperationException(SR.NoCAInSecondaryRoot)); } parentCompensationId = parentToken.CompensationId; } CompensationTokenData tokenData = new CompensationTokenData(compensationExtension.GetNextId(), parentCompensationId) { CompensationState = CompensationState.Active, DisplayName = this.DisplayName, }; CompensationToken token = new CompensationToken(tokenData); context.Properties.Add(CompensationToken.PropertyName, token); this.currentCompensationId.Set(context, token.CompensationId); this.currentCompensationToken.Set(context, token); compensationExtension.Add(token.CompensationId, tokenData); if(TD.CompensationStateIsEnabled()) { TD.CompensationState(tokenData.DisplayName, tokenData.CompensationState.ToString()); } if (this.Body != null) { context.ScheduleActivity(this.Body, new CompletionCallback(OnBodyExecutionComplete)); } else { //empty body case. Assume the body has completed successfully tokenData.CompensationState = CompensationState.Completed; if(TD.CompensationStateIsEnabled()) { TD.CompensationState(tokenData.DisplayName, tokenData.CompensationState.ToString()); } ScheduleSecondaryRoot(context, compensationExtension, tokenData); } } void OnBodyExecutionComplete(NativeActivityContext context, ActivityInstance completedInstance) { CompensationExtension compensationExtension = context.GetExtension (); Fx.Assert(compensationExtension != null, "CompensationExtension must be valid"); CompensationTokenData token = compensationExtension.Get(this.currentCompensationId.Get(context)); Fx.Assert(token != null, "CompensationTokenData must be valid"); if (completedInstance.State == ActivityInstanceState.Closed) { token.CompensationState = CompensationState.Completed; if(TD.CompensationStateIsEnabled()) { TD.CompensationState(token.DisplayName, token.CompensationState.ToString()); } if (context.IsCancellationRequested) { token.CompensationState = CompensationState.Compensating; } } else if (completedInstance.State == ActivityInstanceState.Canceled || completedInstance.State == ActivityInstanceState.Faulted) { // we check for faulted as well for one odd case where an exception can be thrown from the body activity itself. token.CompensationState = CompensationState.Canceling; } else { Fx.Assert(false, "completedInstance in unexpected state"); } ScheduleSecondaryRoot(context, compensationExtension, token); } void ScheduleSecondaryRoot(NativeActivityContext context, CompensationExtension compensationExtension, CompensationTokenData token) { if (token.ParentCompensationId != CompensationToken.RootCompensationId) { CompensationTokenData parentToken = compensationExtension.Get(token.ParentCompensationId); Fx.Assert(parentToken != null, "parentToken must be valid"); parentToken.ExecutionTracker.Add(token); } else { CompensationTokenData parentToken = compensationExtension.Get(CompensationToken.RootCompensationId); Fx.Assert(parentToken != null, "parentToken must be valid"); parentToken.ExecutionTracker.Add(token); } // If we are going to Cancel, don't set the out arg... if (Result != null && token.CompensationState == CompensationState.Completed) { Result.Set(context, this.currentCompensationToken.Get(context)); } Fx.Assert(token.BookmarkTable[CompensationBookmarkName.OnSecondaryRootScheduled] == null, "Bookmark should not be already initialized in the bookmark table."); token.BookmarkTable[CompensationBookmarkName.OnSecondaryRootScheduled] = context.CreateBookmark(new BookmarkCallback(OnSecondaryRootScheduled)); this.compensationId.Set(context, token.CompensationId); context.ScheduleSecondaryRoot(CompensationParticipant, context.Environment); } void OnSecondaryRootScheduled(NativeActivityContext context, Bookmark bookmark, object value) { CompensationExtension compensationExtension = context.GetExtension (); Fx.Assert(compensationExtension != null, "CompensationExtension must be valid"); long compensationId = (long)value; CompensationTokenData compensationToken = compensationExtension.Get(compensationId); Fx.Assert(compensationToken != null, "CompensationTokenData must be valid"); if (compensationToken.CompensationState == CompensationState.Canceling) { Fx.Assert(compensationToken.BookmarkTable[CompensationBookmarkName.Canceled] == null, "Bookmark should not be already initialized in the bookmark table."); compensationToken.BookmarkTable[CompensationBookmarkName.Canceled] = context.CreateBookmark(new BookmarkCallback(OnCanceledOrCompensated)); compensationExtension.NotifyMessage(context, compensationToken.CompensationId, CompensationBookmarkName.OnCancellation); } else if (compensationToken.CompensationState == CompensationState.Compensating) { Fx.Assert(compensationToken.BookmarkTable[CompensationBookmarkName.Compensated] == null, "Bookmark should not be already initialized in the bookmark table."); compensationToken.BookmarkTable[CompensationBookmarkName.Compensated] = context.CreateBookmark(new BookmarkCallback(OnCanceledOrCompensated)); compensationExtension.NotifyMessage(context, compensationToken.CompensationId, CompensationBookmarkName.OnCompensation); } } void OnCanceledOrCompensated(NativeActivityContext context, Bookmark bookmark, object value) { CompensationExtension compensationExtension = context.GetExtension (); Fx.Assert(compensationExtension != null, "CompensationExtension must be valid"); long compensationId = (long)value; CompensationTokenData compensationToken = compensationExtension.Get(compensationId); Fx.Assert(compensationToken != null, "CompensationTokenData must be valid"); switch(compensationToken.CompensationState) { case CompensationState.Canceling: compensationToken.CompensationState = CompensationState.Canceled; break; case CompensationState.Compensating: compensationToken.CompensationState = CompensationState.Compensated; break; default: break; } if(TD.CompensationStateIsEnabled()) { TD.CompensationState(compensationToken.DisplayName, compensationToken.CompensationState.ToString()); } AppCompletionCleanup(context, compensationExtension, compensationToken); // Mark the activity as canceled. context.MarkCanceled(); } void AppCompletionCleanup(NativeActivityContext context, CompensationExtension compensationExtension, CompensationTokenData compensationToken) { Fx.Assert(compensationToken != null, "CompensationTokenData must be valid"); // Remove the token from the parent! if (compensationToken.ParentCompensationId != CompensationToken.RootCompensationId) { CompensationTokenData parentToken = compensationExtension.Get(compensationToken.ParentCompensationId); Fx.Assert(parentToken != null, "parentToken must be valid"); parentToken.ExecutionTracker.Remove(compensationToken); } else { // remove from workflow root... CompensationTokenData parentToken = compensationExtension.Get(CompensationToken.RootCompensationId); Fx.Assert(parentToken != null, "parentToken must be valid"); parentToken.ExecutionTracker.Remove(compensationToken); } compensationToken.RemoveBookmark(context, CompensationBookmarkName.Canceled); compensationToken.RemoveBookmark(context, CompensationBookmarkName.Compensated); // Remove the token from the extension... compensationExtension.Remove(compensationToken.CompensationId); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ResourceSet.cs
- panel.cs
- TextElementCollectionHelper.cs
- Lease.cs
- InteropBitmapSource.cs
- FontUnit.cs
- ResourceCodeDomSerializer.cs
- MultitargetingHelpers.cs
- HorizontalAlignConverter.cs
- ManagementOptions.cs
- SoapIncludeAttribute.cs
- XamlToRtfWriter.cs
- Msmq3PoisonHandler.cs
- XmlEncoding.cs
- SafeNativeMethods.cs
- InvalidPropValue.cs
- SystemIPv6InterfaceProperties.cs
- OpenTypeCommon.cs
- DataTrigger.cs
- CriticalFinalizerObject.cs
- _SSPIWrapper.cs
- StylusDevice.cs
- PagesSection.cs
- DataControlExtensions.cs
- SchemaImporterExtension.cs
- DesignTimeTemplateParser.cs
- RectangleF.cs
- XmlLoader.cs
- COM2PropertyPageUITypeConverter.cs
- DrawListViewItemEventArgs.cs
- SqlProvider.cs
- ReadContentAsBinaryHelper.cs
- BinaryParser.cs
- BrowserDefinitionCollection.cs
- Select.cs
- D3DImage.cs
- SelectionListComponentEditor.cs
- RegexBoyerMoore.cs
- SHA256Cng.cs
- ValueTypeFixupInfo.cs
- Token.cs
- TrustLevel.cs
- SQLChars.cs
- SessionIDManager.cs
- BufferAllocator.cs
- ApplicationBuildProvider.cs
- CodeFieldReferenceExpression.cs
- DbXmlEnabledProviderManifest.cs
- UdpAnnouncementEndpoint.cs
- BindingContext.cs
- DataControlReference.cs
- WorkflowTimerService.cs
- InternalBase.cs
- ProfileSettingsCollection.cs
- BatchParser.cs
- CodeGenerationManager.cs
- ArrayTypeMismatchException.cs
- CompensationDesigner.cs
- ListViewGroup.cs
- Misc.cs
- TextElementEnumerator.cs
- ScrollBarRenderer.cs
- HuffmanTree.cs
- WorkflowHostingResponseContext.cs
- MessageSecurityOverMsmq.cs
- StorageBasedPackageProperties.cs
- FieldNameLookup.cs
- LocatorPart.cs
- SplineKeyFrames.cs
- SqlServer2KCompatibilityAnnotation.cs
- DoubleAnimation.cs
- DataObjectAttribute.cs
- CapabilitiesState.cs
- GridViewSelectEventArgs.cs
- SingleKeyFrameCollection.cs
- DatatypeImplementation.cs
- ForwardPositionQuery.cs
- StylusButtonEventArgs.cs
- ReadOnlyHierarchicalDataSource.cs
- _IPv6Address.cs
- path.cs
- XmlSchemaObjectTable.cs
- PublisherIdentityPermission.cs
- BaseComponentEditor.cs
- ClientRuntimeConfig.cs
- CatalogPart.cs
- EventRoute.cs
- ConfigurationElementProperty.cs
- TextEditorMouse.cs
- InstanceKeyCollisionException.cs
- KoreanLunisolarCalendar.cs
- CellQuery.cs
- Bezier.cs
- XmlHierarchicalEnumerable.cs
- MouseButton.cs
- RegexTree.cs
- ColumnCollection.cs
- StringUtil.cs
- InvalidateEvent.cs
- WebEvents.cs