You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@@ -0,0 +1,63 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace System.Activities.Statements
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Markup;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
[SuppressMessage(FxCop.Category.Naming, FxCop.Rule.IdentifiersShouldNotHaveIncorrectSuffix, Justification = "Optimizing for XAML naming.")]
|
||||
[ContentProperty("Collection")]
|
||||
public sealed class AddToCollection<T> : CodeActivity
|
||||
{
|
||||
[RequiredArgument]
|
||||
[DefaultValue(null)]
|
||||
public InArgument<ICollection<T>> Collection
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[RequiredArgument]
|
||||
[DefaultValue(null)]
|
||||
public InArgument<T> Item
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
|
||||
protected override void CacheMetadata(CodeActivityMetadata metadata)
|
||||
{
|
||||
Collection<RuntimeArgument> arguments = new Collection<RuntimeArgument>();
|
||||
|
||||
RuntimeArgument collectionArgument = new RuntimeArgument("Collection", typeof(ICollection<T>), ArgumentDirection.In, true);
|
||||
metadata.Bind(this.Collection, collectionArgument);
|
||||
arguments.Add(collectionArgument);
|
||||
|
||||
RuntimeArgument itemArgument = new RuntimeArgument("Item", typeof(T), ArgumentDirection.In, true);
|
||||
metadata.Bind(this.Item, itemArgument);
|
||||
arguments.Add(itemArgument);
|
||||
|
||||
metadata.SetArgumentsCollection(arguments);
|
||||
}
|
||||
|
||||
protected override void Execute(CodeActivityContext context)
|
||||
{
|
||||
ICollection<T> collection = this.Collection.Get(context);
|
||||
if (collection == null)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CollectionActivityRequiresCollection(this.DisplayName)));
|
||||
}
|
||||
T item = this.Item.Get(context);
|
||||
|
||||
collection.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace System.Activities.Statements
|
||||
{
|
||||
using System.Activities;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime;
|
||||
|
||||
public sealed class Assign : CodeActivity
|
||||
{
|
||||
public Assign()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
[RequiredArgument]
|
||||
[DefaultValue(null)]
|
||||
public OutArgument To
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[RequiredArgument]
|
||||
[DefaultValue(null)]
|
||||
public InArgument Value
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
protected override void CacheMetadata(CodeActivityMetadata metadata)
|
||||
{
|
||||
Collection<RuntimeArgument> arguments = new Collection<RuntimeArgument>();
|
||||
|
||||
Type valueType = TypeHelper.ObjectType;
|
||||
|
||||
if (this.Value != null)
|
||||
{
|
||||
valueType = this.Value.ArgumentType;
|
||||
}
|
||||
|
||||
RuntimeArgument valueArgument = new RuntimeArgument("Value", valueType, ArgumentDirection.In, true);
|
||||
metadata.Bind(this.Value, valueArgument);
|
||||
|
||||
Type toType = TypeHelper.ObjectType;
|
||||
|
||||
if (this.To != null)
|
||||
{
|
||||
toType = this.To.ArgumentType;
|
||||
}
|
||||
|
||||
RuntimeArgument toArgument = new RuntimeArgument("To", toType, ArgumentDirection.Out, true);
|
||||
metadata.Bind(this.To, toArgument);
|
||||
|
||||
arguments.Add(valueArgument);
|
||||
arguments.Add(toArgument);
|
||||
|
||||
metadata.SetArgumentsCollection(arguments);
|
||||
|
||||
if (this.Value != null && this.To != null)
|
||||
{
|
||||
if (!TypeHelper.AreTypesCompatible(this.Value.ArgumentType, this.To.ArgumentType))
|
||||
{
|
||||
metadata.AddValidationError(SR.TypeMismatchForAssign(
|
||||
this.Value.ArgumentType,
|
||||
this.To.ArgumentType,
|
||||
this.DisplayName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Execute(CodeActivityContext context)
|
||||
{
|
||||
this.To.Set(context, this.Value.Get(context));
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Assign<T> : CodeActivity
|
||||
{
|
||||
public Assign()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
[RequiredArgument]
|
||||
[DefaultValue(null)]
|
||||
public OutArgument<T> To
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[RequiredArgument]
|
||||
[DefaultValue(null)]
|
||||
public InArgument<T> Value
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
protected override void CacheMetadata(CodeActivityMetadata metadata)
|
||||
{
|
||||
Collection<RuntimeArgument> arguments = new Collection<RuntimeArgument>();
|
||||
|
||||
RuntimeArgument valueArgument = new RuntimeArgument("Value", typeof(T), ArgumentDirection.In, true);
|
||||
metadata.Bind(this.Value, valueArgument);
|
||||
|
||||
RuntimeArgument toArgument = new RuntimeArgument("To", typeof(T), ArgumentDirection.Out, true);
|
||||
metadata.Bind(this.To, toArgument);
|
||||
|
||||
arguments.Add(valueArgument);
|
||||
arguments.Add(toArgument);
|
||||
|
||||
metadata.SetArgumentsCollection(arguments);
|
||||
}
|
||||
|
||||
protected override void Execute(CodeActivityContext context)
|
||||
{
|
||||
context.SetValue(this.To, this.Value.Get(context));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
namespace System.Activities.Statements
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime;
|
||||
|
||||
[DataContract]
|
||||
class BookmarkTable
|
||||
{
|
||||
//Number of bookmarks used internally
|
||||
static int tableSize = Enum.GetValues(typeof(CompensationBookmarkName)).Length;
|
||||
|
||||
Bookmark[] bookmarkTable;
|
||||
|
||||
public BookmarkTable()
|
||||
{
|
||||
this.bookmarkTable = new Bookmark[tableSize];
|
||||
}
|
||||
|
||||
public Bookmark this[CompensationBookmarkName bookmarkName]
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.bookmarkTable[(int)bookmarkName];
|
||||
}
|
||||
set
|
||||
{
|
||||
this.bookmarkTable[(int)bookmarkName] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember(Name = "bookmarkTable")]
|
||||
internal Bookmark[] SerializedBookmarkTable
|
||||
{
|
||||
get { return this.bookmarkTable; }
|
||||
set { this.bookmarkTable = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace System.Activities.Statements
|
||||
{
|
||||
using System;
|
||||
using System.Activities;
|
||||
using System.Activities.DynamicUpdate;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.Collections;
|
||||
using System.Windows.Markup;
|
||||
|
||||
[ContentProperty("Body")]
|
||||
public sealed class CancellationScope : NativeActivity
|
||||
{
|
||||
Collection<Variable> variables;
|
||||
Variable<bool> suppressCancel;
|
||||
|
||||
public CancellationScope()
|
||||
: base()
|
||||
{
|
||||
this.suppressCancel = new Variable<bool>();
|
||||
}
|
||||
|
||||
public Collection<Variable> Variables
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.variables == null)
|
||||
{
|
||||
this.variables = new ValidatingCollection<Variable>
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
protected override void OnCreateDynamicUpdateMap(NativeActivityUpdateMapMetadata metadata, Activity originalActivity)
|
||||
{
|
||||
metadata.AllowUpdateInsideThisActivity();
|
||||
}
|
||||
|
||||
protected override void CacheMetadata(NativeActivityMetadata metadata)
|
||||
{
|
||||
metadata.AddChild(this.Body);
|
||||
metadata.AddChild(this.CancellationHandler);
|
||||
metadata.SetVariablesCollection(this.Variables);
|
||||
metadata.AddImplementationVariable(this.suppressCancel);
|
||||
}
|
||||
|
||||
protected override void Execute(NativeActivityContext context)
|
||||
{
|
||||
if (this.Body != null)
|
||||
{
|
||||
context.ScheduleActivity(this.Body, new CompletionCallback(OnBodyComplete));
|
||||
}
|
||||
}
|
||||
|
||||
void OnBodyComplete(NativeActivityContext context, ActivityInstance completedInstance)
|
||||
{
|
||||
// Determine whether to run the Cancel based on whether the body
|
||||
// canceled rather than whether cancel had been requested.
|
||||
if (completedInstance.State == ActivityInstanceState.Canceled ||
|
||||
(context.IsCancellationRequested && completedInstance.State == ActivityInstanceState.Faulted))
|
||||
{
|
||||
// We don't cancel the cancel handler
|
||||
this.suppressCancel.Set(context, true);
|
||||
|
||||
context.MarkCanceled();
|
||||
|
||||
if (this.CancellationHandler != null)
|
||||
{
|
||||
context.ScheduleActivity(this.CancellationHandler, onFaulted: new FaultCallback(OnExceptionFromCancelHandler));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Cancel(NativeActivityContext context)
|
||||
{
|
||||
bool suppressCancel = this.suppressCancel.Get(context);
|
||||
if (!suppressCancel)
|
||||
{
|
||||
context.CancelChildren();
|
||||
}
|
||||
}
|
||||
|
||||
void OnExceptionFromCancelHandler(NativeActivityFaultContext context, Exception propagatedException, ActivityInstance propagatedFrom)
|
||||
{
|
||||
this.suppressCancel.Set(context, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace System.Activities.Statements
|
||||
{
|
||||
using System;
|
||||
using System.Activities;
|
||||
using System.Activities.Runtime;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime;
|
||||
using System.Windows.Markup;
|
||||
|
||||
[SuppressMessage(FxCop.Category.Naming, FxCop.Rule.IdentifiersShouldNotMatchKeywords, Justification = "Optimizing for XAML naming. VB imperative users will [] qualify (e.g. New [Catch](Of Exception))")]
|
||||
public abstract class Catch
|
||||
{
|
||||
internal Catch()
|
||||
{
|
||||
}
|
||||
|
||||
public abstract Type ExceptionType
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
internal abstract ActivityDelegate GetAction();
|
||||
internal abstract void ScheduleAction(NativeActivityContext context, Exception exception, CompletionCallback completionCallback, FaultCallback faultCallback);
|
||||
}
|
||||
|
||||
[ContentProperty("Action")]
|
||||
[SuppressMessage(FxCop.Category.Naming, FxCop.Rule.IdentifiersShouldNotMatchKeywords, Justification = "Optimizing for XAML naming. VB imperative users will [] qualify (e.g. New [Catch](Of Exception))")]
|
||||
public sealed class Catch<TException> : Catch
|
||||
where TException : Exception
|
||||
{
|
||||
public Catch()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
public override Type ExceptionType
|
||||
{
|
||||
get
|
||||
{
|
||||
return typeof(TException);
|
||||
}
|
||||
}
|
||||
|
||||
[DefaultValue(null)]
|
||||
public ActivityAction<TException> Action
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
internal override ActivityDelegate GetAction()
|
||||
{
|
||||
return this.Action;
|
||||
}
|
||||
|
||||
internal override void ScheduleAction(NativeActivityContext context, Exception exception,
|
||||
CompletionCallback completionCallback, FaultCallback faultCallback)
|
||||
{
|
||||
context.ScheduleAction(this.Action, (TException)exception, completionCallback, faultCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace System.Activities.Statements
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Markup;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
[SuppressMessage(FxCop.Category.Naming, FxCop.Rule.IdentifiersShouldNotHaveIncorrectSuffix, Justification = "Optimizing for XAML naming.")]
|
||||
[ContentProperty("Collection")]
|
||||
public sealed class ClearCollection<T> : CodeActivity
|
||||
{
|
||||
[RequiredArgument]
|
||||
[DefaultValue(null)]
|
||||
public InArgument<ICollection<T>> Collection
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
|
||||
protected override void CacheMetadata(CodeActivityMetadata metadata)
|
||||
{
|
||||
RuntimeArgument collectionArgument = new RuntimeArgument("Collection", typeof(ICollection<T>), ArgumentDirection.In, true);
|
||||
metadata.Bind(this.Collection, collectionArgument);
|
||||
|
||||
metadata.SetArgumentsCollection(new Collection<RuntimeArgument> { collectionArgument });
|
||||
}
|
||||
|
||||
protected override void Execute(CodeActivityContext context)
|
||||
{
|
||||
ICollection<T> collection = this.Collection.Get(context);
|
||||
if (collection == null)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CollectionActivityRequiresCollection(this.DisplayName)));
|
||||
}
|
||||
collection.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,231 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
namespace System.Activities.Statements
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime;
|
||||
using System.Activities.Validation;
|
||||
using System.Linq;
|
||||
using System.Activities.Expressions;
|
||||
|
||||
public sealed class Compensate : NativeActivity
|
||||
{
|
||||
static Constraint compensateWithNoTarget = Compensate.CompensateWithNoTarget();
|
||||
|
||||
InternalCompensate internalCompensate;
|
||||
DefaultCompensation defaultCompensation;
|
||||
|
||||
Variable<CompensationToken> currentCompensationToken;
|
||||
|
||||
public Compensate()
|
||||
: base()
|
||||
{
|
||||
this.currentCompensationToken = new Variable<CompensationToken>();
|
||||
}
|
||||
|
||||
[DefaultValue(null)]
|
||||
public InArgument<CompensationToken> Target
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
DefaultCompensation DefaultCompensation
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.defaultCompensation == null)
|
||||
{
|
||||
this.defaultCompensation = new DefaultCompensation()
|
||||
{
|
||||
Target = new InArgument<CompensationToken>(this.currentCompensationToken),
|
||||
};
|
||||
}
|
||||
|
||||
return this.defaultCompensation;
|
||||
}
|
||||
}
|
||||
|
||||
InternalCompensate InternalCompensate
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.internalCompensate == null)
|
||||
{
|
||||
this.internalCompensate = new InternalCompensate()
|
||||
{
|
||||
Target = new InArgument<CompensationToken>(new ArgumentValue<CompensationToken> { ArgumentName = "Target" }),
|
||||
};
|
||||
}
|
||||
|
||||
return this.internalCompensate;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void CacheMetadata(NativeActivityMetadata metadata)
|
||||
{
|
||||
RuntimeArgument targetArgument = new RuntimeArgument("Target", typeof(CompensationToken), ArgumentDirection.In);
|
||||
metadata.Bind(this.Target, targetArgument);
|
||||
metadata.SetArgumentsCollection(new Collection<RuntimeArgument> { targetArgument });
|
||||
|
||||
metadata.SetImplementationVariablesCollection(new Collection<Variable> { this.currentCompensationToken });
|
||||
|
||||
Fx.Assert(DefaultCompensation != null, "DefaultCompensation must be valid");
|
||||
Fx.Assert(InternalCompensate != null, "InternalCompensate must be valid");
|
||||
metadata.SetImplementationChildrenCollection(
|
||||
new Collection<Activity>
|
||||
{
|
||||
DefaultCompensation,
|
||||
InternalCompensate
|
||||
});
|
||||
}
|
||||
|
||||
internal override IList<Constraint> InternalGetConstraints()
|
||||
{
|
||||
return new List<Constraint>(1) { compensateWithNoTarget };
|
||||
}
|
||||
|
||||
static Constraint CompensateWithNoTarget()
|
||||
{
|
||||
DelegateInArgument<Compensate> element = new DelegateInArgument<Compensate> { Name = "element" };
|
||||
DelegateInArgument<ValidationContext> validationContext = new DelegateInArgument<ValidationContext> { Name = "validationContext" };
|
||||
Variable<bool> assertFlag = new Variable<bool> { Name = "assertFlag" };
|
||||
Variable<IEnumerable<Activity>> elements = new Variable<IEnumerable<Activity>>() { Name = "elements" };
|
||||
Variable<int> index = new Variable<int>() { Name = "index" };
|
||||
|
||||
return new Constraint<Compensate>
|
||||
{
|
||||
Body = new ActivityAction<Compensate, ValidationContext>
|
||||
{
|
||||
Argument1 = element,
|
||||
Argument2 = validationContext,
|
||||
Handler = new Sequence
|
||||
{
|
||||
Variables =
|
||||
{
|
||||
assertFlag,
|
||||
elements,
|
||||
index
|
||||
},
|
||||
Activities =
|
||||
{
|
||||
new If
|
||||
{
|
||||
Condition = new InArgument<bool>((env) => element.Get(env).Target != null),
|
||||
Then = new Assign<bool>
|
||||
{
|
||||
To = assertFlag,
|
||||
Value = true
|
||||
},
|
||||
Else = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new Assign<IEnumerable<Activity>>
|
||||
{
|
||||
To = elements,
|
||||
Value = new GetParentChain
|
||||
{
|
||||
ValidationContext = validationContext,
|
||||
},
|
||||
},
|
||||
new While(env => (assertFlag.Get(env) != true) && 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<bool>
|
||||
{
|
||||
To = assertFlag,
|
||||
Value = true
|
||||
},
|
||||
},
|
||||
new Assign<int>
|
||||
{
|
||||
To = index,
|
||||
Value = new InArgument<int>(env => index.Get(env) + 1)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new AssertValidation
|
||||
{
|
||||
Assertion = new InArgument<bool>(assertFlag),
|
||||
Message = new InArgument<string>(SR.CompensateWithNoTargetConstraint)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void Execute(NativeActivityContext context)
|
||||
{
|
||||
CompensationExtension compensationExtension = context.GetExtension<CompensationExtension>();
|
||||
if (compensationExtension == null)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CompensateWithoutCompensableActivity(this.DisplayName)));
|
||||
}
|
||||
|
||||
if (Target.IsEmpty)
|
||||
{
|
||||
CompensationToken ambientCompensationToken = (CompensationToken)context.Properties.Find(CompensationToken.PropertyName);
|
||||
CompensationTokenData ambientTokenData = ambientCompensationToken == null ? null : compensationExtension.Get(ambientCompensationToken.CompensationId);
|
||||
|
||||
if (ambientTokenData != null && ambientTokenData.IsTokenValidInSecondaryRoot)
|
||||
{
|
||||
this.currentCompensationToken.Set(context, ambientCompensationToken);
|
||||
if (ambientTokenData.ExecutionTracker.Count > 0)
|
||||
{
|
||||
context.ScheduleActivity(DefaultCompensation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.InvalidCompensateActivityUsage(this.DisplayName)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CompensationToken compensationToken = Target.Get(context);
|
||||
CompensationTokenData tokenData = compensationToken == null ? null : compensationExtension.Get(compensationToken.CompensationId);
|
||||
|
||||
if (compensationToken == null)
|
||||
{
|
||||
throw FxTrace.Exception.Argument("Target", SR.InvalidCompensationToken(this.DisplayName));
|
||||
}
|
||||
|
||||
if (compensationToken.CompensateCalled)
|
||||
{
|
||||
// No-Op
|
||||
return;
|
||||
}
|
||||
|
||||
if (tokenData == null || tokenData.CompensationState != CompensationState.Completed)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CompensableActivityAlreadyConfirmedOrCompensated));
|
||||
}
|
||||
|
||||
// A valid in-arg was passed...
|
||||
tokenData.CompensationState = CompensationState.Compensating;
|
||||
compensationToken.CompensateCalled = true;
|
||||
context.ScheduleActivity(InternalCompensate);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Cancel(NativeActivityContext context)
|
||||
{
|
||||
// Suppress Cancel
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
namespace System.Activities.Statements
|
||||
{
|
||||
using System;
|
||||
|
||||
static class CompensationActivityStrings
|
||||
{
|
||||
public const string WorkflowImplicitCompensationBehavior = "Activities.Compensation.WorkflowImplicitCompensationBehavior";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
namespace System.Activities.Statements
|
||||
{
|
||||
using System;
|
||||
|
||||
enum CompensationBookmarkName
|
||||
{
|
||||
Confirmed = 0,
|
||||
Canceled = 1,
|
||||
Compensated = 2,
|
||||
OnConfirmation = 3,
|
||||
OnCompensation = 4,
|
||||
OnCancellation = 5,
|
||||
OnSecondaryRootScheduled = 6,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
namespace System.Activities.Statements
|
||||
{
|
||||
using System;
|
||||
using System.Activities.Hosting;
|
||||
using System.Activities.Persistence;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime;
|
||||
using System.Xml.Linq;
|
||||
|
||||
public class CompensationExtension : PersistenceParticipant, IWorkflowInstanceExtension
|
||||
{
|
||||
static readonly XNamespace compensationNamespace = XNamespace.Get("urn:schemas-microsoft-com:System.Activities/4.0/compensation");
|
||||
static readonly XName compensationExtensionData = compensationNamespace.GetName("Data");
|
||||
|
||||
[Fx.Tag.SynchronizationObject(Blocking = false)]
|
||||
Dictionary<long, CompensationTokenData> compensationTokenTable;
|
||||
|
||||
public CompensationExtension()
|
||||
{
|
||||
this.compensationTokenTable = new Dictionary<long, CompensationTokenData>();
|
||||
}
|
||||
|
||||
internal Dictionary<long, CompensationTokenData> CompensationTokenTable
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.compensationTokenTable;
|
||||
}
|
||||
private set
|
||||
{
|
||||
this.compensationTokenTable = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal long Id
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
internal Bookmark WorkflowCompensation
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
internal Bookmark WorkflowConfirmation
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
internal Bookmark WorkflowCompensationScheduled
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
internal bool IsWorkflowCompensationBehaviorScheduled
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
internal WorkflowInstanceProxy Instance
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
internal void Add(long compensationId, CompensationTokenData compensationToken)
|
||||
{
|
||||
Fx.Assert(compensationToken != null, "compensationToken must be valid");
|
||||
|
||||
this.CompensationTokenTable[compensationId] = compensationToken;
|
||||
}
|
||||
|
||||
internal void Remove(long compensationId)
|
||||
{
|
||||
this.CompensationTokenTable.Remove(compensationId);
|
||||
}
|
||||
|
||||
internal CompensationTokenData Get(long compensationId)
|
||||
{
|
||||
CompensationTokenData compensationToken = null;
|
||||
this.CompensationTokenTable.TryGetValue(compensationId, out compensationToken);
|
||||
return compensationToken;
|
||||
}
|
||||
|
||||
internal Bookmark FindBookmark(long compensationId, CompensationBookmarkName bookmarkName)
|
||||
{
|
||||
CompensationTokenData compensationToken = null;
|
||||
Bookmark bookmark = null;
|
||||
|
||||
if (this.CompensationTokenTable.TryGetValue(compensationId, out compensationToken))
|
||||
{
|
||||
bookmark = compensationToken.BookmarkTable[bookmarkName];
|
||||
}
|
||||
|
||||
return bookmark;
|
||||
}
|
||||
|
||||
internal void SetupWorkflowCompensationBehavior(NativeActivityContext context, BookmarkCallback callback, Activity workflowCompensationBehavior)
|
||||
{
|
||||
this.WorkflowCompensationScheduled = context.CreateBookmark(callback);
|
||||
|
||||
Fx.Assert(workflowCompensationBehavior != null, "WorkflowCompensationBehavior must be valid");
|
||||
context.ScheduleSecondaryRoot(workflowCompensationBehavior, null);
|
||||
|
||||
// Add the root compensationToken to track all root CA execution order.
|
||||
this.Add(CompensationToken.RootCompensationId, new CompensationTokenData(CompensationToken.RootCompensationId, CompensationToken.RootCompensationId));
|
||||
this.IsWorkflowCompensationBehaviorScheduled = true;
|
||||
}
|
||||
|
||||
internal long GetNextId()
|
||||
{
|
||||
return ++this.Id;
|
||||
}
|
||||
|
||||
internal void NotifyMessage(NativeActivityContext context, long compensationId, CompensationBookmarkName compensationBookmark)
|
||||
{
|
||||
Bookmark bookmark = FindBookmark(compensationId, compensationBookmark);
|
||||
|
||||
if (bookmark != null)
|
||||
{
|
||||
context.ResumeBookmark(bookmark, compensationId);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.BookmarkNotRegistered(compensationBookmark)));
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage(FxCop.Category.Design, FxCop.Rule.InterfaceMethodsShouldBeCallableByChildTypes,
|
||||
Justification = "The inherit class don't need to call this method or access this method")]
|
||||
IEnumerable<object> IWorkflowInstanceExtension.GetAdditionalExtensions()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
[SuppressMessage(FxCop.Category.Design, FxCop.Rule.InterfaceMethodsShouldBeCallableByChildTypes,
|
||||
Justification = "The inherit class don't need to call this method or access this method")]
|
||||
void IWorkflowInstanceExtension.SetInstance(WorkflowInstanceProxy instance)
|
||||
{
|
||||
this.Instance = instance;
|
||||
}
|
||||
|
||||
// PersistenceParticipant
|
||||
protected override void CollectValues(out IDictionary<XName, object> readWriteValues, out IDictionary<XName, object> writeOnlyValues)
|
||||
{
|
||||
writeOnlyValues = null;
|
||||
readWriteValues = new Dictionary<XName, object>(1)
|
||||
{
|
||||
{
|
||||
compensationExtensionData,
|
||||
new List<object>(6)
|
||||
{
|
||||
this.CompensationTokenTable,
|
||||
this.WorkflowCompensation,
|
||||
this.WorkflowConfirmation,
|
||||
this.WorkflowCompensationScheduled,
|
||||
this.IsWorkflowCompensationBehaviorScheduled,
|
||||
this.Id
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void PublishValues(IDictionary<XName, object> readWriteValues)
|
||||
{
|
||||
object data;
|
||||
|
||||
if (readWriteValues.TryGetValue(compensationExtensionData, out data))
|
||||
{
|
||||
List<object> list = (List<object>)data;
|
||||
this.CompensationTokenTable = (Dictionary<long, CompensationTokenData>)list[0];
|
||||
this.WorkflowCompensation = (Bookmark)list[1];
|
||||
this.WorkflowConfirmation = (Bookmark)list[2];
|
||||
this.WorkflowCompensationScheduled = (Bookmark)list[3];
|
||||
this.IsWorkflowCompensationBehaviorScheduled = (bool)list[4];
|
||||
this.Id = (long)list[5];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,424 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
namespace System.Activities.Statements
|
||||
{
|
||||
using System;
|
||||
using System.Activities.DynamicUpdate;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
sealed class CompensationParticipant : NativeActivity
|
||||
{
|
||||
InArgument<long> compensationId;
|
||||
|
||||
Variable<CompensationToken> currentCompensationToken;
|
||||
|
||||
public CompensationParticipant(Variable<long> compensationId)
|
||||
: base()
|
||||
{
|
||||
this.compensationId = compensationId;
|
||||
|
||||
this.currentCompensationToken = new Variable<CompensationToken>();
|
||||
|
||||
DefaultCompensation = new DefaultCompensation()
|
||||
{
|
||||
Target = new InArgument<CompensationToken>(this.currentCompensationToken),
|
||||
};
|
||||
|
||||
DefaultConfirmation = new DefaultConfirmation()
|
||||
{
|
||||
Target = new InArgument<CompensationToken>(this.currentCompensationToken),
|
||||
};
|
||||
}
|
||||
|
||||
public Activity CompensationHandler
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public Activity ConfirmationHandler
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public Activity CancellationHandler
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
Activity DefaultCompensation
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
Activity DefaultConfirmation
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
protected override bool CanInduceIdle
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnCreateDynamicUpdateMap(NativeActivityUpdateMapMetadata metadata, Activity originalActivity)
|
||||
{
|
||||
metadata.AllowUpdateInsideThisActivity();
|
||||
}
|
||||
|
||||
protected override void CacheMetadata(NativeActivityMetadata metadata)
|
||||
{
|
||||
metadata.SetImplementationVariablesCollection(
|
||||
new Collection<Variable>
|
||||
{
|
||||
this.currentCompensationToken,
|
||||
});
|
||||
|
||||
Collection<Activity> children = new Collection<Activity>();
|
||||
|
||||
if (this.CompensationHandler != null)
|
||||
{
|
||||
children.Add(CompensationHandler);
|
||||
}
|
||||
|
||||
if (this.ConfirmationHandler != null)
|
||||
{
|
||||
children.Add(ConfirmationHandler);
|
||||
}
|
||||
|
||||
if (this.CancellationHandler != null)
|
||||
{
|
||||
children.Add(CancellationHandler);
|
||||
}
|
||||
|
||||
metadata.SetChildrenCollection(children);
|
||||
|
||||
Collection<Activity> implementationChildren = new Collection<Activity>();
|
||||
Fx.Assert(DefaultCompensation != null, "DefaultCompensation must be valid");
|
||||
implementationChildren.Add(DefaultCompensation);
|
||||
|
||||
Fx.Assert(DefaultConfirmation != null, "DefaultConfirmation must be valid");
|
||||
implementationChildren.Add(DefaultConfirmation);
|
||||
|
||||
metadata.SetImplementationChildrenCollection(implementationChildren);
|
||||
|
||||
RuntimeArgument compensationIdArgument = new RuntimeArgument("CompensationId", typeof(long), ArgumentDirection.In);
|
||||
metadata.Bind(this.compensationId, compensationIdArgument);
|
||||
metadata.AddArgument(compensationIdArgument);
|
||||
}
|
||||
|
||||
protected override void Execute(NativeActivityContext context)
|
||||
{
|
||||
CompensationExtension compensationExtension = context.GetExtension<CompensationExtension>();
|
||||
Fx.Assert(compensationExtension != null, "CompensationExtension must be valid");
|
||||
|
||||
long compensationId = this.compensationId.Get(context);
|
||||
Fx.Assert(compensationId != CompensationToken.RootCompensationId, "CompensationId passed to the SecondaryRoot must be valid");
|
||||
|
||||
CompensationTokenData compensationToken = compensationExtension.Get(compensationId);
|
||||
Fx.Assert(compensationToken != null, "CompensationTokenData must be valid");
|
||||
|
||||
CompensationToken token = new CompensationToken(compensationToken);
|
||||
this.currentCompensationToken.Set(context, token);
|
||||
|
||||
compensationToken.IsTokenValidInSecondaryRoot = true;
|
||||
context.Properties.Add(CompensationToken.PropertyName, token);
|
||||
|
||||
Fx.Assert(compensationToken.BookmarkTable[CompensationBookmarkName.OnConfirmation] == null, "Bookmark should not be already initialized in the bookmark table.");
|
||||
compensationToken.BookmarkTable[CompensationBookmarkName.OnConfirmation] = context.CreateBookmark(new BookmarkCallback(OnConfirmation));
|
||||
|
||||
Fx.Assert(compensationToken.BookmarkTable[CompensationBookmarkName.OnCompensation] == null, "Bookmark should not be already initialized in the bookmark table.");
|
||||
compensationToken.BookmarkTable[CompensationBookmarkName.OnCompensation] = context.CreateBookmark(new BookmarkCallback(OnCompensation));
|
||||
|
||||
Fx.Assert(compensationToken.BookmarkTable[CompensationBookmarkName.OnCancellation] == null, "Bookmark should not be already initialized in the bookmark table.");
|
||||
compensationToken.BookmarkTable[CompensationBookmarkName.OnCancellation] = context.CreateBookmark(new BookmarkCallback(OnCancellation));
|
||||
|
||||
Bookmark onSecondaryRootScheduled = compensationToken.BookmarkTable[CompensationBookmarkName.OnSecondaryRootScheduled];
|
||||
Fx.Assert(onSecondaryRootScheduled != null, "onSecondaryRootScheduled bookmark must be already registered.");
|
||||
|
||||
compensationToken.BookmarkTable[CompensationBookmarkName.OnSecondaryRootScheduled] = null;
|
||||
|
||||
context.ResumeBookmark(onSecondaryRootScheduled, compensationId);
|
||||
}
|
||||
|
||||
void OnConfirmation(NativeActivityContext context, Bookmark bookmark, object value)
|
||||
{
|
||||
CompensationExtension compensationExtension = context.GetExtension<CompensationExtension>();
|
||||
Fx.Assert(compensationExtension != null, "CompensationExtension must be valid");
|
||||
|
||||
long compensationId = (long)value;
|
||||
Fx.Assert(compensationId != CompensationToken.RootCompensationId, "CompensationId must be passed when resuming the Completed bookmark");
|
||||
|
||||
CompensationTokenData compensationToken = compensationExtension.Get(compensationId);
|
||||
Fx.Assert(compensationToken != null, "CompensationTokenData must be valid");
|
||||
|
||||
Fx.Assert(compensationToken.CompensationState == CompensationState.Confirming, "CompensationState should be in Confirming state");
|
||||
|
||||
if (TD.CompensationStateIsEnabled())
|
||||
{
|
||||
TD.CompensationState(compensationToken.DisplayName, compensationToken.CompensationState.ToString());
|
||||
}
|
||||
|
||||
compensationToken.RemoveBookmark(context, CompensationBookmarkName.OnCancellation);
|
||||
compensationToken.RemoveBookmark(context, CompensationBookmarkName.OnCompensation);
|
||||
|
||||
if (ConfirmationHandler != null)
|
||||
{
|
||||
context.ScheduleActivity(ConfirmationHandler, new CompletionCallback(OnConfirmationHandlerComplete), new FaultCallback(OnExceptionFromHandler));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.currentCompensationToken.Set(context, new CompensationToken(compensationToken));
|
||||
if (compensationToken.ExecutionTracker.Count > 0)
|
||||
{
|
||||
context.ScheduleActivity(DefaultConfirmation, new CompletionCallback(this.OnConfirmationComplete));
|
||||
}
|
||||
else
|
||||
{
|
||||
compensationExtension.NotifyMessage(context, compensationToken.CompensationId, CompensationBookmarkName.Confirmed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnConfirmationHandlerComplete(NativeActivityContext context, ActivityInstance completedInstance)
|
||||
{
|
||||
Fx.Assert(context != null, "context must be valid");
|
||||
Fx.Assert(completedInstance != null, "completedInstance must be valid");
|
||||
|
||||
CompensationExtension compensationExtension = context.GetExtension<CompensationExtension>();
|
||||
Fx.Assert(compensationExtension != null, "CompensationExtension must be valid");
|
||||
|
||||
CompensationTokenData compensationToken = compensationExtension.Get(this.compensationId.Get(context));
|
||||
Fx.Assert(compensationToken != null, "CompensationTokenData must be valid");
|
||||
|
||||
if (completedInstance.State == ActivityInstanceState.Closed)
|
||||
{
|
||||
Fx.Assert(compensationToken.CompensationState == CompensationState.Confirming, "CompensationParticipant should be in Confirming State");
|
||||
|
||||
this.currentCompensationToken.Set(context, new CompensationToken(compensationToken));
|
||||
if (compensationToken.ExecutionTracker.Count > 0)
|
||||
{
|
||||
context.ScheduleActivity(DefaultConfirmation, new CompletionCallback(this.OnConfirmationComplete));
|
||||
}
|
||||
else
|
||||
{
|
||||
compensationExtension.NotifyMessage(context, compensationToken.CompensationId, CompensationBookmarkName.Confirmed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnConfirmationComplete(NativeActivityContext context, ActivityInstance completedInstance)
|
||||
{
|
||||
Fx.Assert(context != null, "context must be valid");
|
||||
Fx.Assert(completedInstance != null, "completedInstance must be valid");
|
||||
|
||||
CompensationExtension compensationExtension = context.GetExtension<CompensationExtension>();
|
||||
Fx.Assert(compensationExtension != null, "CompensationExtension must be valid");
|
||||
|
||||
CompensationTokenData compensationToken = compensationExtension.Get(this.compensationId.Get(context));
|
||||
Fx.Assert(compensationToken != null, "CompensationTokenData must be valid");
|
||||
|
||||
if (completedInstance.State == ActivityInstanceState.Closed)
|
||||
{
|
||||
compensationExtension.NotifyMessage(context, compensationToken.CompensationId, CompensationBookmarkName.Confirmed);
|
||||
}
|
||||
}
|
||||
|
||||
void OnCompensation(NativeActivityContext context, Bookmark bookmark, object value)
|
||||
{
|
||||
CompensationExtension compensationExtension = context.GetExtension<CompensationExtension>();
|
||||
Fx.Assert(compensationExtension != null, "CompensationExtension must be valid");
|
||||
|
||||
long compensationId = (long)value;
|
||||
Fx.Assert(compensationId != CompensationToken.RootCompensationId, "CompensationId must be passed when resuming the Completed bookmark");
|
||||
|
||||
CompensationTokenData compensationToken = compensationExtension.Get(compensationId);
|
||||
Fx.Assert(compensationToken != null, "CompensationTokenData must be valid");
|
||||
|
||||
Fx.Assert(compensationToken.CompensationState == CompensationState.Compensating, "CompensationState should be in Compensating state");
|
||||
|
||||
if (TD.CompensationStateIsEnabled())
|
||||
{
|
||||
TD.CompensationState(compensationToken.DisplayName, compensationToken.CompensationState.ToString());
|
||||
}
|
||||
|
||||
// Cleanup Bookmarks..
|
||||
compensationToken.RemoveBookmark(context, CompensationBookmarkName.OnCancellation);
|
||||
compensationToken.RemoveBookmark(context, CompensationBookmarkName.OnConfirmation);
|
||||
|
||||
if (CompensationHandler != null)
|
||||
{
|
||||
context.ScheduleActivity(CompensationHandler, new CompletionCallback(this.OnCompensationHandlerComplete), new FaultCallback(OnExceptionFromHandler));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.currentCompensationToken.Set(context, new CompensationToken(compensationToken));
|
||||
if (compensationToken.ExecutionTracker.Count > 0)
|
||||
{
|
||||
context.ScheduleActivity(DefaultCompensation, new CompletionCallback(this.OnCompensationComplete));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.InternalOnCompensationComplete(context, compensationExtension, compensationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnCompensationHandlerComplete(NativeActivityContext context, ActivityInstance completedInstance)
|
||||
{
|
||||
Fx.Assert(context != null, "context must be valid");
|
||||
Fx.Assert(completedInstance != null, "completedInstance must be valid");
|
||||
|
||||
CompensationExtension compensationExtension = context.GetExtension<CompensationExtension>();
|
||||
Fx.Assert(compensationExtension != null, "CompensationExtension must be valid");
|
||||
|
||||
CompensationTokenData compensationToken = compensationExtension.Get(this.compensationId.Get(context));
|
||||
Fx.Assert(compensationToken != null, "CompensationTokenData must be valid");
|
||||
|
||||
if (completedInstance.State == ActivityInstanceState.Closed)
|
||||
{
|
||||
Fx.Assert(compensationToken.CompensationState == CompensationState.Compensating, "CompensationParticipant should be in Compensating State");
|
||||
|
||||
this.currentCompensationToken.Set(context, new CompensationToken(compensationToken));
|
||||
if (compensationToken.ExecutionTracker.Count > 0)
|
||||
{
|
||||
context.ScheduleActivity(DefaultConfirmation, new CompletionCallback(this.OnCompensationComplete));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.InternalOnCompensationComplete(context, compensationExtension, compensationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnCancellation(NativeActivityContext context, Bookmark bookmark, object value)
|
||||
{
|
||||
CompensationExtension compensationExtension = context.GetExtension<CompensationExtension>();
|
||||
Fx.Assert(compensationExtension != null, "CompensationExtension must be valid");
|
||||
|
||||
long compensationId = (long)value;
|
||||
Fx.Assert(compensationId != CompensationToken.RootCompensationId, "CompensationId must be passed when resuming the Completed bookmark");
|
||||
|
||||
CompensationTokenData compensationToken = compensationExtension.Get(compensationId);
|
||||
Fx.Assert(compensationToken != null, "CompensationTokenData must be valid");
|
||||
|
||||
Fx.Assert(compensationToken.CompensationState == CompensationState.Canceling, "CompensationState should be in Canceling state");
|
||||
|
||||
if (TD.CompensationStateIsEnabled())
|
||||
{
|
||||
TD.CompensationState(compensationToken.DisplayName, compensationToken.CompensationState.ToString());
|
||||
}
|
||||
|
||||
// remove bookmarks.
|
||||
compensationToken.RemoveBookmark(context, CompensationBookmarkName.OnCompensation);
|
||||
compensationToken.RemoveBookmark(context, CompensationBookmarkName.OnConfirmation);
|
||||
|
||||
this.currentCompensationToken.Set(context, new CompensationToken(compensationToken));
|
||||
if (CancellationHandler != null)
|
||||
{
|
||||
context.ScheduleActivity(CancellationHandler, new CompletionCallback(this.OnCancellationHandlerComplete), new FaultCallback(OnExceptionFromHandler));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (compensationToken.ExecutionTracker.Count > 0)
|
||||
{
|
||||
context.ScheduleActivity(DefaultCompensation, new CompletionCallback(this.OnCompensationComplete));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.InternalOnCompensationComplete(context, compensationExtension, compensationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnCancellationHandlerComplete(NativeActivityContext context, ActivityInstance completedInstance)
|
||||
{
|
||||
CompensationExtension compensationExtension = context.GetExtension<CompensationExtension>();
|
||||
Fx.Assert(compensationExtension != null, "CompensationExtension must be valid");
|
||||
|
||||
CompensationTokenData compensationToken = compensationExtension.Get(this.compensationId.Get(context));
|
||||
Fx.Assert(compensationToken != null, "CompensationTokenData must be valid");
|
||||
|
||||
if (completedInstance.State == ActivityInstanceState.Closed)
|
||||
{
|
||||
Fx.Assert(compensationToken.CompensationState == CompensationState.Canceling, "CompensationParticipant should be in Canceling State");
|
||||
|
||||
this.currentCompensationToken.Set(context, new CompensationToken(compensationToken));
|
||||
if (compensationToken.ExecutionTracker.Count > 0)
|
||||
{
|
||||
context.ScheduleActivity(DefaultConfirmation, new CompletionCallback(this.OnCompensationComplete));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.InternalOnCompensationComplete(context, compensationExtension, compensationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnCompensationComplete(NativeActivityContext context, ActivityInstance completedInstance)
|
||||
{
|
||||
CompensationExtension compensationExtension = context.GetExtension<CompensationExtension>();
|
||||
Fx.Assert(compensationExtension != null, "CompensationExtension must be valid");
|
||||
|
||||
CompensationTokenData compensationToken = compensationExtension.Get(this.compensationId.Get(context));
|
||||
Fx.Assert(compensationToken != null, "CompensationTokenData must be valid");
|
||||
|
||||
InternalOnCompensationComplete(context, compensationExtension, compensationToken);
|
||||
}
|
||||
|
||||
void InternalOnCompensationComplete(NativeActivityContext context, CompensationExtension compensationExtension, CompensationTokenData compensationToken)
|
||||
{
|
||||
switch (compensationToken.CompensationState)
|
||||
{
|
||||
case CompensationState.Canceling:
|
||||
compensationExtension.NotifyMessage(context, compensationToken.CompensationId, CompensationBookmarkName.Canceled);
|
||||
break;
|
||||
case CompensationState.Compensating:
|
||||
compensationExtension.NotifyMessage(context, compensationToken.CompensationId, CompensationBookmarkName.Compensated);
|
||||
break;
|
||||
default:
|
||||
Fx.Assert(false, "CompensationState is in unexpected state!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnExceptionFromHandler(NativeActivityFaultContext context, Exception propagatedException, ActivityInstance propagatedFrom)
|
||||
{
|
||||
CompensationExtension compensationExtension = context.GetExtension<CompensationExtension>();
|
||||
Fx.Assert(compensationExtension != null, "CompensationExtension must be valid");
|
||||
|
||||
CompensationTokenData compensationToken = compensationExtension.Get(this.compensationId.Get(context));
|
||||
Fx.Assert(compensationToken != null, "CompensationTokenData must be valid");
|
||||
|
||||
InvalidOperationException exception = null;
|
||||
|
||||
switch (compensationToken.CompensationState)
|
||||
{
|
||||
case CompensationState.Confirming:
|
||||
exception = new InvalidOperationException(SR.ConfirmationHandlerFatalException(compensationToken.DisplayName), propagatedException);
|
||||
break;
|
||||
case CompensationState.Compensating:
|
||||
exception = new InvalidOperationException(SR.CompensationHandlerFatalException(compensationToken.DisplayName), propagatedException);
|
||||
break;
|
||||
case CompensationState.Canceling:
|
||||
exception = new InvalidOperationException(SR.CancellationHandlerFatalException(compensationToken.DisplayName), propagatedException);
|
||||
break;
|
||||
default:
|
||||
Fx.Assert(false, "CompensationState is in unexpected state!");
|
||||
break;
|
||||
}
|
||||
|
||||
context.Abort(exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
namespace System.Activities.Statements
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
[DataContract]
|
||||
enum CompensationState
|
||||
{
|
||||
[EnumMember]
|
||||
Creating,
|
||||
|
||||
[EnumMember]
|
||||
Active,
|
||||
|
||||
[EnumMember]
|
||||
Completed,
|
||||
|
||||
[EnumMember]
|
||||
Confirming,
|
||||
|
||||
[EnumMember]
|
||||
Confirmed,
|
||||
|
||||
[EnumMember]
|
||||
Compensating,
|
||||
|
||||
[EnumMember]
|
||||
Compensated,
|
||||
|
||||
[EnumMember]
|
||||
Canceling,
|
||||
|
||||
[EnumMember]
|
||||
Canceled,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
namespace System.Activities.Statements
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.ComponentModel;
|
||||
|
||||
[Fx.Tag.XamlVisible(false)]
|
||||
[DataContract]
|
||||
public sealed class CompensationToken
|
||||
{
|
||||
internal const string PropertyName = "System.Compensation.CompensationToken";
|
||||
internal const long RootCompensationId = 0;
|
||||
|
||||
internal CompensationToken(CompensationTokenData tokenData)
|
||||
{
|
||||
this.CompensationId = tokenData.CompensationId;
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
internal long CompensationId
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
internal bool CompensateCalled
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
internal bool ConfirmCalled
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace System.Activities.Statements
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.ComponentModel;
|
||||
|
||||
[Fx.Tag.XamlVisible(false)]
|
||||
[DataContract]
|
||||
class CompensationTokenData
|
||||
{
|
||||
internal CompensationTokenData(long compensationId, long parentCompensationId)
|
||||
{
|
||||
this.CompensationId = compensationId;
|
||||
this.ParentCompensationId = parentCompensationId;
|
||||
this.BookmarkTable = new BookmarkTable();
|
||||
this.ExecutionTracker = new ExecutionTracker();
|
||||
this.CompensationState = CompensationState.Creating;
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
internal long CompensationId
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
internal long ParentCompensationId
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
internal BookmarkTable BookmarkTable
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
internal ExecutionTracker ExecutionTracker
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[DefaultValue(CompensationState.Active)]
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
internal CompensationState CompensationState
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
internal string DisplayName
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
internal bool IsTokenValidInSecondaryRoot
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
internal void RemoveBookmark(NativeActivityContext context, CompensationBookmarkName bookmarkName)
|
||||
{
|
||||
Bookmark bookmark = this.BookmarkTable[bookmarkName];
|
||||
|
||||
if (bookmark != null)
|
||||
{
|
||||
context.RemoveBookmark(bookmark);
|
||||
this.BookmarkTable[bookmarkName] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
namespace System.Activities.Statements
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime;
|
||||
using System.Activities.Validation;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Activities.Expressions;
|
||||
|
||||
public sealed class Confirm : NativeActivity
|
||||
{
|
||||
static Constraint confirmWithNoTarget = Confirm.ConfirmWithNoTarget();
|
||||
|
||||
InternalConfirm internalConfirm;
|
||||
DefaultConfirmation defaultConfirmation;
|
||||
|
||||
Variable<CompensationToken> currentCompensationToken;
|
||||
|
||||
public Confirm()
|
||||
: base()
|
||||
{
|
||||
this.currentCompensationToken = new Variable<CompensationToken>();
|
||||
}
|
||||
|
||||
public InArgument<CompensationToken> Target
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
DefaultConfirmation DefaultConfirmation
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.defaultConfirmation == null)
|
||||
{
|
||||
this.defaultConfirmation = new DefaultConfirmation()
|
||||
{
|
||||
Target = new InArgument<CompensationToken>(this.currentCompensationToken),
|
||||
};
|
||||
}
|
||||
|
||||
return this.defaultConfirmation;
|
||||
}
|
||||
}
|
||||
|
||||
InternalConfirm InternalConfirm
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.internalConfirm == null)
|
||||
{
|
||||
this.internalConfirm = new InternalConfirm()
|
||||
{
|
||||
Target = new InArgument<CompensationToken>(new ArgumentValue<CompensationToken> { ArgumentName = "Target" }),
|
||||
};
|
||||
}
|
||||
|
||||
return this.internalConfirm;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void CacheMetadata(NativeActivityMetadata metadata)
|
||||
{
|
||||
RuntimeArgument targetArgument = new RuntimeArgument("Target", typeof(CompensationToken), ArgumentDirection.In);
|
||||
metadata.Bind(this.Target, targetArgument);
|
||||
|
||||
metadata.SetArgumentsCollection(
|
||||
new Collection<RuntimeArgument>
|
||||
{
|
||||
targetArgument
|
||||
});
|
||||
|
||||
metadata.SetImplementationVariablesCollection(
|
||||
new Collection<Variable>
|
||||
{
|
||||
this.currentCompensationToken
|
||||
});
|
||||
|
||||
Fx.Assert(DefaultConfirmation != null, "DefaultConfirmation must be valid");
|
||||
Fx.Assert(InternalConfirm != null, "InternalConfirm must be valid");
|
||||
metadata.SetImplementationChildrenCollection(
|
||||
new Collection<Activity>
|
||||
{
|
||||
DefaultConfirmation,
|
||||
InternalConfirm
|
||||
});
|
||||
}
|
||||
|
||||
internal override IList<Constraint> InternalGetConstraints()
|
||||
{
|
||||
return new List<Constraint>(1) { confirmWithNoTarget };
|
||||
}
|
||||
|
||||
static Constraint ConfirmWithNoTarget()
|
||||
{
|
||||
DelegateInArgument<Confirm> element = new DelegateInArgument<Confirm> { Name = "element" };
|
||||
DelegateInArgument<ValidationContext> validationContext = new DelegateInArgument<ValidationContext> { Name = "validationContext" };
|
||||
Variable<bool> assertFlag = new Variable<bool> { Name = "assertFlag" };
|
||||
Variable<IEnumerable<Activity>> elements = new Variable<IEnumerable<Activity>>() { Name = "elements" };
|
||||
Variable<int> index = new Variable<int>() { Name = "index" };
|
||||
|
||||
return new Constraint<Confirm>
|
||||
{
|
||||
Body = new ActivityAction<Confirm, ValidationContext>
|
||||
{
|
||||
Argument1 = element,
|
||||
Argument2 = validationContext,
|
||||
Handler = new Sequence
|
||||
{
|
||||
Variables =
|
||||
{
|
||||
assertFlag,
|
||||
elements,
|
||||
index
|
||||
},
|
||||
Activities =
|
||||
{
|
||||
new If
|
||||
{
|
||||
Condition = new InArgument<bool>((env) => element.Get(env).Target != null),
|
||||
Then = new Assign<bool>
|
||||
{
|
||||
To = assertFlag,
|
||||
Value = true
|
||||
},
|
||||
Else = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new Assign<IEnumerable<Activity>>
|
||||
{
|
||||
To = elements,
|
||||
Value = new GetParentChain
|
||||
{
|
||||
ValidationContext = validationContext,
|
||||
},
|
||||
},
|
||||
new While(env => (assertFlag.Get(env) != true) &&
|
||||
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<bool>
|
||||
{
|
||||
To = assertFlag,
|
||||
Value = true
|
||||
},
|
||||
},
|
||||
new Assign<int>
|
||||
{
|
||||
To = index,
|
||||
Value = new InArgument<int>(env => index.Get(env) + 1)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new AssertValidation
|
||||
{
|
||||
Assertion = new InArgument<bool>(assertFlag),
|
||||
Message = new InArgument<string>(SR.ConfirmWithNoTargetConstraint)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void Execute(NativeActivityContext context)
|
||||
{
|
||||
CompensationExtension compensationExtension = context.GetExtension<CompensationExtension>();
|
||||
if (compensationExtension == null)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.ConfirmWithoutCompensableActivity(this.DisplayName)));
|
||||
}
|
||||
|
||||
if (Target.IsEmpty)
|
||||
{
|
||||
CompensationToken ambientCompensationToken = (CompensationToken)context.Properties.Find(CompensationToken.PropertyName);
|
||||
CompensationTokenData ambientTokenData = ambientCompensationToken == null ? null : compensationExtension.Get(ambientCompensationToken.CompensationId);
|
||||
|
||||
if (ambientTokenData != null && ambientTokenData.IsTokenValidInSecondaryRoot)
|
||||
{
|
||||
this.currentCompensationToken.Set(context, ambientCompensationToken);
|
||||
if (ambientTokenData.ExecutionTracker.Count > 0)
|
||||
{
|
||||
context.ScheduleActivity(DefaultConfirmation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.InvalidConfirmActivityUsage(this.DisplayName)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CompensationToken compensationToken = Target.Get(context);
|
||||
CompensationTokenData tokenData = compensationToken == null ? null : compensationExtension.Get(compensationToken.CompensationId);
|
||||
|
||||
if (compensationToken == null)
|
||||
{
|
||||
throw FxTrace.Exception.Argument("Target", SR.InvalidCompensationToken(this.DisplayName));
|
||||
}
|
||||
|
||||
if (compensationToken.ConfirmCalled)
|
||||
{
|
||||
// No-Op
|
||||
return;
|
||||
}
|
||||
|
||||
if (tokenData == null || tokenData.CompensationState != CompensationState.Completed)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CompensableActivityAlreadyConfirmedOrCompensated));
|
||||
}
|
||||
|
||||
// A valid in-arg was passed...
|
||||
tokenData.CompensationState = CompensationState.Confirming;
|
||||
compensationToken.ConfirmCalled = true;
|
||||
context.ScheduleActivity(InternalConfirm);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Cancel(NativeActivityContext context)
|
||||
{
|
||||
// Suppress Cancel
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace System.Activities.Statements
|
||||
{
|
||||
using System;
|
||||
using System.Activities;
|
||||
using System.Runtime;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public sealed class CreateBookmarkScope : NativeActivity<BookmarkScope>
|
||||
{
|
||||
public CreateBookmarkScope()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void CacheMetadata(NativeActivityMetadata metadata)
|
||||
{
|
||||
// NoOp - we override this to suppress reflection. The base class
|
||||
// takes care of adding the Result argument.
|
||||
}
|
||||
|
||||
protected override void Execute(NativeActivityContext context)
|
||||
{
|
||||
context.SetValue(this.Result, context.CreateBookmarkScope());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
namespace System.Activities.Statements
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime;
|
||||
using System.Collections.ObjectModel;
|
||||
using SA = System.Activities;
|
||||
|
||||
sealed class DefaultCompensation : NativeActivity
|
||||
{
|
||||
Activity body;
|
||||
|
||||
Variable<CompensationToken> toCompensateToken;
|
||||
|
||||
CompletionCallback onChildCompensated;
|
||||
|
||||
public DefaultCompensation()
|
||||
: base()
|
||||
{
|
||||
this.toCompensateToken = new Variable<CompensationToken>();
|
||||
|
||||
this.body = new InternalCompensate()
|
||||
{
|
||||
Target = new InArgument<CompensationToken>(toCompensateToken),
|
||||
};
|
||||
}
|
||||
|
||||
public InArgument<CompensationToken> Target
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
Activity Body
|
||||
{
|
||||
get { return this.body; }
|
||||
}
|
||||
|
||||
protected override void CacheMetadata(NativeActivityMetadata metadata)
|
||||
{
|
||||
RuntimeArgument targetArgument = new RuntimeArgument("Target", typeof(CompensationToken), ArgumentDirection.In);
|
||||
metadata.Bind(this.Target, targetArgument);
|
||||
|
||||
metadata.SetArgumentsCollection(new Collection<RuntimeArgument> { targetArgument });
|
||||
|
||||
metadata.SetImplementationVariablesCollection(new Collection<Variable> { this.toCompensateToken });
|
||||
|
||||
Fx.Assert(this.Body != null, "Body must be valid");
|
||||
metadata.SetImplementationChildrenCollection(new Collection<Activity> { this.Body });
|
||||
}
|
||||
|
||||
protected override void Execute(NativeActivityContext context)
|
||||
{
|
||||
InternalExecute(context, null);
|
||||
}
|
||||
|
||||
void InternalExecute(NativeActivityContext context, ActivityInstance completedInstance)
|
||||
{
|
||||
CompensationExtension compensationExtension = context.GetExtension<CompensationExtension>();
|
||||
if (compensationExtension == null)
|
||||
{
|
||||
throw SA.FxTrace.Exception.AsError(new InvalidOperationException(SA.SR.CompensateWithoutCompensableActivity(this.DisplayName)));
|
||||
}
|
||||
|
||||
CompensationToken token = Target.Get(context);
|
||||
CompensationTokenData tokenData = token == null ? null : compensationExtension.Get(token.CompensationId);
|
||||
|
||||
Fx.Assert(tokenData != null, "CompensationTokenData must be valid");
|
||||
|
||||
if (tokenData.ExecutionTracker.Count > 0)
|
||||
{
|
||||
if (this.onChildCompensated == null)
|
||||
{
|
||||
this.onChildCompensated = new CompletionCallback(InternalExecute);
|
||||
}
|
||||
|
||||
this.toCompensateToken.Set(context, new CompensationToken(tokenData.ExecutionTracker.Get()));
|
||||
|
||||
Fx.Assert(Body != null, "Body must be valid");
|
||||
context.ScheduleActivity(Body, this.onChildCompensated);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Cancel(NativeActivityContext context)
|
||||
{
|
||||
// Suppress Cancel
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
namespace System.Activities.Statements
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Runtime;
|
||||
|
||||
sealed class DefaultConfirmation : NativeActivity
|
||||
{
|
||||
Activity body;
|
||||
Variable<CompensationToken> toConfirmToken;
|
||||
CompletionCallback onChildConfirmed;
|
||||
|
||||
public DefaultConfirmation()
|
||||
: base()
|
||||
{
|
||||
this.toConfirmToken = new Variable<CompensationToken>();
|
||||
|
||||
this.body = new InternalConfirm()
|
||||
{
|
||||
Target = new InArgument<CompensationToken>(toConfirmToken),
|
||||
};
|
||||
}
|
||||
|
||||
public InArgument<CompensationToken> Target
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
Activity Body
|
||||
{
|
||||
get { return this.body; }
|
||||
}
|
||||
|
||||
protected override void CacheMetadata(NativeActivityMetadata metadata)
|
||||
{
|
||||
RuntimeArgument targetArgument = new RuntimeArgument("Target", typeof(CompensationToken), ArgumentDirection.In);
|
||||
metadata.Bind(this.Target, targetArgument);
|
||||
metadata.SetArgumentsCollection(new Collection<RuntimeArgument> { targetArgument });
|
||||
|
||||
metadata.SetImplementationVariablesCollection(new Collection<Variable> { this.toConfirmToken });
|
||||
|
||||
Fx.Assert(this.Body != null, "Body must be valid");
|
||||
metadata.SetImplementationChildrenCollection(new Collection<Activity> { this.Body });
|
||||
}
|
||||
|
||||
protected override void Execute(NativeActivityContext context)
|
||||
{
|
||||
InternalExecute(context, null);
|
||||
}
|
||||
|
||||
void InternalExecute(NativeActivityContext context, ActivityInstance completedInstance)
|
||||
{
|
||||
CompensationExtension compensationExtension = context.GetExtension<CompensationExtension>();
|
||||
if (compensationExtension == null)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.ConfirmWithoutCompensableActivity(this.DisplayName)));
|
||||
}
|
||||
|
||||
CompensationToken token = Target.Get(context);
|
||||
CompensationTokenData tokenData = token == null ? null : compensationExtension.Get(token.CompensationId);
|
||||
|
||||
Fx.Assert(tokenData != null, "CompensationTokenData must be valid");
|
||||
|
||||
if (tokenData.ExecutionTracker.Count > 0)
|
||||
{
|
||||
if (this.onChildConfirmed == null)
|
||||
{
|
||||
this.onChildConfirmed = new CompletionCallback(InternalExecute);
|
||||
}
|
||||
|
||||
this.toConfirmToken.Set(context, new CompensationToken(tokenData.ExecutionTracker.Get()));
|
||||
|
||||
Fx.Assert(Body != null, "Body must be valid");
|
||||
context.ScheduleActivity(Body, this.onChildConfirmed);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Cancel(NativeActivityContext context)
|
||||
{
|
||||
// Suppress Cancel
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace System.Activities.Statements
|
||||
{
|
||||
using System;
|
||||
using System.Activities;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime;
|
||||
using System.Windows.Markup;
|
||||
|
||||
[ContentProperty("Duration")]
|
||||
public sealed class Delay : NativeActivity
|
||||
{
|
||||
static Func<TimerExtension> getDefaultTimerExtension = new Func<TimerExtension>(GetDefaultTimerExtension);
|
||||
Variable<Bookmark> timerBookmark;
|
||||
|
||||
public Delay()
|
||||
: base()
|
||||
{
|
||||
this.timerBookmark = new Variable<Bookmark>();
|
||||
}
|
||||
|
||||
[RequiredArgument]
|
||||
[DefaultValue(null)]
|
||||
public InArgument<TimeSpan> Duration
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
protected override bool CanInduceIdle
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void CacheMetadata(NativeActivityMetadata metadata)
|
||||
{
|
||||
RuntimeArgument durationArgument = new RuntimeArgument("Duration", typeof(TimeSpan), ArgumentDirection.In, true);
|
||||
metadata.Bind(this.Duration, durationArgument);
|
||||
metadata.SetArgumentsCollection(new Collection<RuntimeArgument> { durationArgument });
|
||||
metadata.AddImplementationVariable(this.timerBookmark);
|
||||
metadata.AddDefaultExtensionProvider(getDefaultTimerExtension);
|
||||
}
|
||||
|
||||
static TimerExtension GetDefaultTimerExtension()
|
||||
{
|
||||
return new DurableTimerExtension();
|
||||
}
|
||||
|
||||
protected override void Execute(NativeActivityContext context)
|
||||
{
|
||||
TimeSpan duration = this.Duration.Get(context);
|
||||
if (duration < TimeSpan.Zero)
|
||||
{
|
||||
throw FxTrace.Exception.ArgumentOutOfRange("Duration", duration, SR.DurationIsNegative(this.DisplayName));
|
||||
}
|
||||
|
||||
if (duration == TimeSpan.Zero)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TimerExtension timerExtension = GetTimerExtension(context);
|
||||
Bookmark bookmark = context.CreateBookmark();
|
||||
timerExtension.RegisterTimer(duration, bookmark);
|
||||
this.timerBookmark.Set(context, bookmark);
|
||||
}
|
||||
|
||||
protected override void Cancel(NativeActivityContext context)
|
||||
{
|
||||
Bookmark timerBookmark = this.timerBookmark.Get(context);
|
||||
TimerExtension timerExtension = GetTimerExtension(context);
|
||||
timerExtension.CancelTimer(timerBookmark);
|
||||
context.RemoveBookmark(timerBookmark);
|
||||
context.MarkCanceled();
|
||||
}
|
||||
|
||||
protected override void Abort(NativeActivityAbortContext context)
|
||||
{
|
||||
Bookmark timerBookmark = this.timerBookmark.Get(context);
|
||||
// The bookmark could be null in abort when user passed in a negative delay as a duration
|
||||
if (timerBookmark != null)
|
||||
{
|
||||
TimerExtension timerExtension = GetTimerExtension(context);
|
||||
timerExtension.CancelTimer(timerBookmark);
|
||||
}
|
||||
base.Abort(context);
|
||||
}
|
||||
|
||||
TimerExtension GetTimerExtension(ActivityContext context)
|
||||
{
|
||||
TimerExtension timerExtension = context.GetExtension<TimerExtension>();
|
||||
Fx.Assert(timerExtension != null, "TimerExtension must exist.");
|
||||
return timerExtension;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user