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
- MemberNameValidator.cs
- CookielessData.cs
- ProcessHostConfigUtils.cs
- DbResourceAllocator.cs
- ConfigErrorGlyph.cs
- Decorator.cs
- CodeTypeDeclaration.cs
- TokenCreationException.cs
- XsltException.cs
- Hash.cs
- IndicCharClassifier.cs
- RouteItem.cs
- HyperLink.cs
- StringHelper.cs
- SecurityUtils.cs
- DotExpr.cs
- WebAdminConfigurationHelper.cs
- FormViewDeletedEventArgs.cs
- Gdiplus.cs
- TouchDevice.cs
- QueueProcessor.cs
- XPathNodeIterator.cs
- TypeConverter.cs
- TitleStyle.cs
- XmlLanguage.cs
- TemplateControlCodeDomTreeGenerator.cs
- RawKeyboardInputReport.cs
- CellRelation.cs
- FrameworkContextData.cs
- assertwrapper.cs
- TypeElement.cs
- DefaultSerializationProviderAttribute.cs
- AsyncInvokeContext.cs
- RsaSecurityTokenParameters.cs
- SiteMap.cs
- TextEditorThreadLocalStore.cs
- FontInfo.cs
- OutputCacheProfile.cs
- ConfigXmlText.cs
- Button.cs
- BooleanAnimationBase.cs
- CompositeDataBoundControl.cs
- SystemIPAddressInformation.cs
- PrintPreviewGraphics.cs
- GroupedContextMenuStrip.cs
- CatchDesigner.xaml.cs
- BulletedList.cs
- BitmapEffectCollection.cs
- EntityDataSourceEntityTypeFilterConverter.cs
- MetricEntry.cs
- IncrementalCompileAnalyzer.cs
- MemoryMappedFile.cs
- DrawingImage.cs
- CriticalHandle.cs
- SectionInput.cs
- ErrorProvider.cs
- HtmlTextArea.cs
- UnsupportedPolicyOptionsException.cs
- datacache.cs
- RadioButton.cs
- FontStretch.cs
- AnnotationComponentManager.cs
- CellPartitioner.cs
- StyleTypedPropertyAttribute.cs
- HMACSHA512.cs
- RichTextBox.cs
- RepeaterItemCollection.cs
- ServicePoint.cs
- DataGridViewRowEventArgs.cs
- PreservationFileWriter.cs
- IssuanceLicense.cs
- OletxTransactionHeader.cs
- LoginName.cs
- MetadataArtifactLoaderComposite.cs
- HTMLTagNameToTypeMapper.cs
- ToolStripSplitStackLayout.cs
- SatelliteContractVersionAttribute.cs
- TokenizerHelper.cs
- ToolCreatedEventArgs.cs
- CorrelationManager.cs
- ObjectPersistData.cs
- _UncName.cs
- XmlIgnoreAttribute.cs
- SecurityPermission.cs
- CharacterString.cs
- HttpPostedFile.cs
- typedescriptorpermission.cs
- RegexCompilationInfo.cs
- SimpleTypeResolver.cs
- ClientBase.cs
- SafeRightsManagementPubHandle.cs
- InheritanceRules.cs
- TcpChannelHelper.cs
- control.ime.cs
- WmlCommandAdapter.cs
- TreeNodeStyleCollection.cs
- WebControlsSection.cs
- WindowHelperService.cs
- FileDialog_Vista_Interop.cs
- Geometry.cs