在自定义WF4活动中访问Receive实现子活动的OutArgument值

时间:2013-01-22 08:32:40

标签: workflow-foundation-4

使用VS2012 / .NET 4.5我正在创建一个实现Receive子活动的自定义活动(作为实现子进程)。以下示例中的参数仅固定为一个:Guid类型的OutValue。

我真的很想在ReceiveDone中访问传入参数值的值,因为我需要使用它并在从活动返回之前对其进行转换。请忽略我当前正在使用Guid,它仍然无法使用和InvalidOperationException访问该值:

一个Activity只能获取它拥有的参数的位置。活动'TestActivity'试图获取参数'OutValue'的位置,该参数由活动'等待'拥有 工作流程启动请求[TestActivity的内部]'

我已经尝试了我能想到的一切,但我感到很惊讶。必须有办法做到这一点非常简单吗?

public class TestActivity : NativeActivity<Guid>
{
    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
        var content = ReceiveParametersContent.Create(new Dictionary<string, OutArgument>()
            {
                // How to access the runtime value of this inside TestActivity?
                {"OutValue", new OutArgument<Guid>()}
            });

        startReceiver = new Receive()
        {
            DisplayName = string.Format("Wait for workflow start request [Internal for {0}]", this.DisplayName),
            CanCreateInstance = true,
            ServiceContractName = XName.Get("IStartService", Namespace),
            OperationName = "Start",
            Content = content
        };

        foreach (KeyValuePair<string, OutArgument> keyValuePair in content.Parameters)
        {
            metadata.AddImportedChild(keyValuePair.Value.Expression);
        }

        metadata.AddImplementationChild(startReceiver);
    }

    protected override void Execute(NativeActivityContext context)
    {
        context.ScheduleActivity(startReceiver, ReceiveDone);
    }

    private void ReceiveDone(NativeActivityContext context, ActivityInstance completedInstance)
    {
        var receive = completedInstance.Activity as Receive;
        ReceiveParametersContent content = receive.Content as ReceiveParametersContent;

        try
        {
            // This causes InvalidOperationException.
            // An Activity can only get the location of arguments which it owns.  
            // Activity 'TestActivity' is trying to get the location of argument 'OutValue' 
            // which is owned by activity 'Wait for workflow start request [Internal for TestActivity]'
            var parmValue = content.Parameters["OutValue"].Get(context);
        }
        catch (Exception)
        { }
    }

    private Receive startReceiver;
    private const string Namespace = "http://company.namespace";
}

3 个答案:

答案 0 :(得分:0)

您需要使用OutArgument并将它们用于变量。请参阅带有documentation的代码示例。

答案 1 :(得分:0)

使用内部变量在内部活动之间传递值。

虽然与您的代码没有直接关系,但请参阅下面的示例,它可以为您提供这个想法:

public sealed class CustomNativeActivity : NativeActivity<int>
{
    private Variable<int> internalVar;
    private Assign<int> internalAssign; 

    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
        base.CacheMetadata(metadata);

        internalVar = new Variable<int>("intInternalVar", 10);

        metadata.AddImplementationVariable(internalVar);

        internalAssign = new Assign<int>
            {
                To = internalVar,
                Value = 12345
            };

        metadata.AddImplementationChild(internalAssign);
    }

    protected override void Execute(NativeActivityContext context)
    {
        context.ScheduleActivity(internalAssign, (activityContext, instance) =>
        {
            // Use internalVar value, which was seted by previous activity
            var value = internalVar.Get(activityContext);

            Result.Set(activityContext, value);
        });
    }
}

调用上述活动:

WorkflowInvoker.Invoke<int>(new CustomNativeActivity());

将输出:

12345

修改

在您的情况下,您的 OutArgument 将是 internalVar

new OutArgument<int>(internalVar);

答案 2 :(得分:0)

我可能已经尝试过我想到的一切,但我很顽固,拒绝放弃,所以我继续思考;)

我在这里改变了我的例子,使用Data类作为参数(它本身不会改变任何东西,但我在现实世界的例子中需要它)。

下面的代码现在是一个关于如何访问传入数据的工作示例。使用实现变量是关键:

runtimeVariable = new Variable<Data>();
metadata.AddImplementationVariable(runtimeVariable);

OutArgument:

new OutArgument<Data>(runtimeVariable)

然后我可以通过以下方式访问该值:

// Here dataValue will get the incoming value.
var dataValue = runtimeVariable.Get(context);

我没有在其他地方看到过这样的例子。希望除了我以外,对任何人都有用。

代码:

[DataContract]
public class Data
{
    [DataMember]
    Guid Property1 { get; set; }

    [DataMember]
    int Property2 { get; set; }
}

public class TestActivity : NativeActivity<Guid>
{
    public ReceiveContent Content { get; set; }

    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
        runtimeVariable = new Variable<Data>();
        metadata.AddImplementationVariable(runtimeVariable);

        Content = ReceiveParametersContent.Create(new Dictionary<string, OutArgument>()
            {
                {"OutValue", new OutArgument<Data> (runtimeVariable)}
            });

        startReceiver = new Receive()
        {
            DisplayName = string.Format("Wait for workflow start request [Internal for {0}]", this.DisplayName),
            CanCreateInstance = true,
            ServiceContractName = XName.Get("IStartService", Namespace),
            OperationName = "Start",
            Content = Content
        };

        metadata.AddImplementationChild(startReceiver);
    }

    protected override void Execute(NativeActivityContext context)
    {
        context.ScheduleActivity(startReceiver, ReceiveDone);
    }

    private void ReceiveDone(NativeActivityContext context, ActivityInstance completedInstance)
    {
        // Here dataValue will get the incoming value.
        var dataValue = runtimeVariable.Get(context);
    }

    private Receive startReceiver;
    private Variable<Data> runtimeVariable;
    private const string Namespace = "http://company.namespace";
}