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
- SQLByte.cs
- StateBag.cs
- HttpHandlerAction.cs
- Label.cs
- StringWriter.cs
- SchemaElement.cs
- CommentEmitter.cs
- SecurityTokenProvider.cs
- XmlBindingWorker.cs
- LocalizableResourceBuilder.cs
- CheckBoxRenderer.cs
- SqlNotificationRequest.cs
- EditorOptionAttribute.cs
- DesignTimeTemplateParser.cs
- ShutDownListener.cs
- MembershipPasswordException.cs
- TemplateBindingExtensionConverter.cs
- ClientUrlResolverWrapper.cs
- DataGridViewRowEventArgs.cs
- GeneralTransform2DTo3D.cs
- QueryFunctions.cs
- DictionaryBase.cs
- GroupItemAutomationPeer.cs
- ProcessInfo.cs
- ProgramPublisher.cs
- Int32EqualityComparer.cs
- Pair.cs
- HtmlInputCheckBox.cs
- CodeAttachEventStatement.cs
- SecurityKeyIdentifierClause.cs
- ConversionValidationRule.cs
- DeviceContexts.cs
- Rect3D.cs
- BindingBase.cs
- CompilerResults.cs
- InstanceCreationEditor.cs
- OracleDateTime.cs
- COAUTHINFO.cs
- MessageDirection.cs
- DiscoveryExceptionDictionary.cs
- ResourceType.cs
- FigureParagraph.cs
- Odbc32.cs
- RemotingHelper.cs
- SerialPinChanges.cs
- CodeIdentifier.cs
- ConfigXmlWhitespace.cs
- DBDataPermissionAttribute.cs
- PermissionToken.cs
- Tokenizer.cs
- CompatibleIComparer.cs
- SharedPersonalizationStateInfo.cs
- WebPageTraceListener.cs
- StylusTip.cs
- RecordsAffectedEventArgs.cs
- NonSerializedAttribute.cs
- MobileUserControlDesigner.cs
- xml.cs
- Tokenizer.cs
- Clock.cs
- ObjectFactoryCodeDomTreeGenerator.cs
- IisTraceWebEventProvider.cs
- CheckBoxRenderer.cs
- ResourceAttributes.cs
- ObjectDataSource.cs
- GridViewHeaderRowPresenter.cs
- QilFactory.cs
- BorderGapMaskConverter.cs
- AttributeEmitter.cs
- ConnectionsZone.cs
- EntityDataSourceQueryBuilder.cs
- ServiceReference.cs
- TreeNodeCollection.cs
- SoapAttributeAttribute.cs
- OleServicesContext.cs
- TimeEnumHelper.cs
- ContextProperty.cs
- X509Certificate2.cs
- TdsParser.cs
- PermissionAttributes.cs
- DotExpr.cs
- HttpGetClientProtocol.cs
- EdmComplexPropertyAttribute.cs
- LeaseManager.cs
- ObjectItemCollection.cs
- diagnosticsswitches.cs
- DataGridRow.cs
- SchemaRegistration.cs
- TrackingMemoryStreamFactory.cs
- Serializer.cs
- CompositeCollectionView.cs
- ResourcePool.cs
- BaseWebProxyFinder.cs
- RSAPKCS1KeyExchangeFormatter.cs
- XmlSchemaComplexContentExtension.cs
- XmlAttributeAttribute.cs
- linebase.cs
- Soap.cs
- FixedStringLookup.cs
- ContainerVisual.cs