e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
140 lines
5.8 KiB
C#
140 lines
5.8 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace System.Activities.Statements
|
|
{
|
|
using System.Activities.Runtime;
|
|
using System.Activities.Validation;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
|
|
public sealed class Rethrow : NativeActivity
|
|
{
|
|
public Rethrow()
|
|
{
|
|
DelegateInArgument<Rethrow> element = new DelegateInArgument<Rethrow>() { Name = "constraintArg" };
|
|
DelegateInArgument<ValidationContext> validationContext = new DelegateInArgument<ValidationContext>() { Name = "validationContext" };
|
|
base.Constraints.Add(new Constraint<Rethrow>
|
|
{
|
|
Body = new ActivityAction<Rethrow, ValidationContext>
|
|
{
|
|
Argument1 = element,
|
|
Argument2 = validationContext,
|
|
Handler = new RethrowBuildConstraint
|
|
{
|
|
ParentChain = new GetParentChain
|
|
{
|
|
ValidationContext = validationContext,
|
|
},
|
|
RethrowActivity = element
|
|
},
|
|
}
|
|
});
|
|
}
|
|
|
|
protected override void CacheMetadata(NativeActivityMetadata metadata)
|
|
{
|
|
}
|
|
|
|
protected override void Execute(NativeActivityContext context)
|
|
{
|
|
FaultContext faultContext = context.Properties.Find(TryCatch.FaultContextId) as FaultContext;
|
|
|
|
if (faultContext == null)
|
|
{
|
|
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.FaultContextNotFound(this.DisplayName)));
|
|
}
|
|
|
|
context.RethrowException(faultContext);
|
|
}
|
|
|
|
class RethrowBuildConstraint : NativeActivity<bool>
|
|
{
|
|
[RequiredArgument]
|
|
[DefaultValue(null)]
|
|
public InArgument<IEnumerable<Activity>> ParentChain
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
[RequiredArgument]
|
|
[DefaultValue(null)]
|
|
public InArgument<Rethrow> RethrowActivity
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
protected override void CacheMetadata(NativeActivityMetadata metadata)
|
|
{
|
|
RuntimeArgument parentChainArgument = new RuntimeArgument("ParentChain", typeof(IEnumerable<Activity>), ArgumentDirection.In, true);
|
|
metadata.Bind(this.ParentChain, parentChainArgument);
|
|
metadata.AddArgument(parentChainArgument);
|
|
|
|
RuntimeArgument rethrowActivityArgument = new RuntimeArgument("RethrowActivity", typeof(Rethrow), ArgumentDirection.In, true);
|
|
metadata.Bind(this.RethrowActivity, rethrowActivityArgument);
|
|
metadata.AddArgument(rethrowActivityArgument);
|
|
}
|
|
|
|
protected override void Execute(NativeActivityContext context)
|
|
{
|
|
IEnumerable<Activity> parentChain = this.ParentChain.Get(context);
|
|
Rethrow rethrowActivity = this.RethrowActivity.Get(context);
|
|
Activity previousActivity = rethrowActivity;
|
|
bool privateRethrow = false;
|
|
|
|
// TryCatch with Rethrow is usually authored in the following way:
|
|
//
|
|
// TryCatch
|
|
// {
|
|
// Try = DoWork
|
|
// Catch Handler = Sequence
|
|
// {
|
|
// ProcessException,
|
|
// Rethrow
|
|
// }
|
|
// }
|
|
// Notice that the chain of Activities is TryCatch->Sequence->Rethrow
|
|
// We want to validate that Rethrow is in the catch block of TryCatch
|
|
// We walk up the parent chain until we find TryCatch. Then we check if one the catch handlers points to Sequence(the previous activity in the tree)
|
|
foreach (Activity parent in parentChain)
|
|
{
|
|
// Rethrow is only allowed under the public children of a TryCatch activity.
|
|
// If any of the activities in the tree is a private child, report a constraint violation.
|
|
if (parent.ImplementationChildren.Contains(previousActivity))
|
|
{
|
|
privateRethrow = true;
|
|
}
|
|
|
|
TryCatch tryCatch = parent as TryCatch;
|
|
if (tryCatch != null)
|
|
{
|
|
if (previousActivity != null)
|
|
{
|
|
foreach (Catch catchHandler in tryCatch.Catches)
|
|
{
|
|
ActivityDelegate catchAction = catchHandler.GetAction();
|
|
if (catchAction != null && catchAction.Handler == previousActivity)
|
|
{
|
|
if (privateRethrow)
|
|
{
|
|
Constraint.AddValidationError(context, new ValidationError(SR.RethrowMustBeAPublicChild(rethrowActivity.DisplayName), rethrowActivity));
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
previousActivity = parent;
|
|
}
|
|
|
|
Constraint.AddValidationError(context, new ValidationError(SR.RethrowNotInATryCatch(rethrowActivity.DisplayName), rethrowActivity));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|