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
- ZipIOExtraFieldZip64Element.cs
- TextEffectResolver.cs
- AbstractSvcMapFileLoader.cs
- TemplateKey.cs
- WorkflowPrinting.cs
- WebPartsPersonalization.cs
- formatter.cs
- BaseTypeViewSchema.cs
- KeyValueConfigurationCollection.cs
- ListChangedEventArgs.cs
- SerializerProvider.cs
- ClientFormsIdentity.cs
- AdapterUtil.cs
- MetaTable.cs
- BuildManagerHost.cs
- SafeNativeMemoryHandle.cs
- Size3D.cs
- HyperLink.cs
- BigIntegerStorage.cs
- CFGGrammar.cs
- EntryWrittenEventArgs.cs
- SoapClientMessage.cs
- LocatorGroup.cs
- ClientEventManager.cs
- AudioSignalProblemOccurredEventArgs.cs
- HttpConfigurationContext.cs
- MessageQueuePermissionEntryCollection.cs
- NullableDecimalSumAggregationOperator.cs
- RegexMatchCollection.cs
- HtmlMeta.cs
- PropertyValueUIItem.cs
- EntityContainer.cs
- AudioFormatConverter.cs
- CompositeActivityTypeDescriptor.cs
- DiagnosticEventProvider.cs
- HttpContextBase.cs
- RuleSetBrowserDialog.cs
- DesignerPerfEventProvider.cs
- OleAutBinder.cs
- WindowManager.cs
- MDIClient.cs
- ImageButton.cs
- BitmapEffectInputData.cs
- DrawingImage.cs
- Int64AnimationUsingKeyFrames.cs
- InOutArgumentConverter.cs
- Point4DConverter.cs
- DelegatingTypeDescriptionProvider.cs
- SqlUtils.cs
- Attributes.cs
- NameValueSectionHandler.cs
- AttributeProviderAttribute.cs
- XmlParserContext.cs
- ContainerFilterService.cs
- NamespaceList.cs
- Span.cs
- EntityType.cs
- TypeGeneratedEventArgs.cs
- Profiler.cs
- OdbcConnectionHandle.cs
- AnonymousIdentificationSection.cs
- XmlBinaryWriterSession.cs
- ScrollBar.cs
- Trace.cs
- HGlobalSafeHandle.cs
- DragAssistanceManager.cs
- GC.cs
- PolicyException.cs
- Popup.cs
- RootBrowserWindowProxy.cs
- MethodBody.cs
- CapabilitiesUse.cs
- AppDomainFactory.cs
- Binding.cs
- TableRowCollection.cs
- XmlEventCache.cs
- DSACryptoServiceProvider.cs
- FormsIdentity.cs
- CorrelationHandle.cs
- MbpInfo.cs
- QilName.cs
- OpenTypeLayout.cs
- SqlUnionizer.cs
- ConfigurationLocationCollection.cs
- HttpServerVarsCollection.cs
- HotCommands.cs
- Cursor.cs
- StringCollectionMarkupSerializer.cs
- StandardCommands.cs
- RowToParametersTransformer.cs
- ObjectParameter.cs
- SystemIcmpV4Statistics.cs
- SqlException.cs
- BitSet.cs
- Root.cs
- BufferedStream.cs
- storepermission.cs
- DispatcherTimer.cs
- TextCompositionEventArgs.cs
- ArgIterator.cs