2

我在 MSDN 上遇到了与这个问题相同的问题,但我不明白解决方案,因为我仍然不清楚 Roman Kiss 的解决方案是否会在同时执行单个工作流实例时正确替换端点地址。

当内部Send活动被安排由具有特定端点地址的一个线程执行时,该地址不会被另一个调度具有不同端点地址的相同活动的线程覆盖吗?如果我弄错了,请纠正我,但我认为它会,因为它Send.Endpoint是一个常规属性,它反对InArgument<Endpoint>绑定到任何当前工作流执行上下文。

有人可以对此进行更多说明吗?

更新

我测试了 Roman Kiss 提供的解决方案,结果发现它在我的场景中没有按预期工作。我修改Execute方法如下:

protected override void Execute(NativeActivityContext context)
{
    Thread.Sleep(Address.Get(context).EndsWith("1") ? 1000 : 0);

    Body.Endpoint.Binding = GetBinding(Binding.Get(context));
    Body.Endpoint.AddressUri = new Uri(Address.Get(context));

    Thread.Sleep(Address.Get(context).EndsWith("1") ? 0 : 3000);
    var address = Address.Get(context) + " => " + Body.Endpoint.AddressUri;
    Console.WriteLine(address);
    Thread.Sleep(10000); 

    context.ScheduleActivity(Body);
}

跑了这个测试:

static void Main(string[] args)
{
    // Workflow1 is just a SendScope wrapped around by a Sequence with single Address input argument exposed
    var workflow = new Workflow1();
    Task.WaitAll(
        Task.Run(() => WorkflowInvoker.Invoke(workflow, new Dictionary<string, object> { { "Address", @"http://localhost/1" } })),
        Task.Run(() => WorkflowInvoker.Invoke(workflow, new Dictionary<string, object> { { "Address", @"http://localhost/2" } })));

    Console.ReadLine();
}

我得到的结果是:

http://localhost/1 => http://localhost/1

http://localhost/2 => http://localhost/1

问题仍然悬而未决:如何Send在运行时动态分配我的活动的端点地址?

4

1 回答 1

1

这将如图所示工作,因为工厂创建了一个 活动,因此当使用该方法设置该活动时,它正在正确设置该活动实例上的绑定。SendCacheMetadataSend

包括内容 Incase 链接失效

[ContentProperty("Body")]
public class SendScope : NativeActivity
{
    [DefaultValue((string)null)]
    [RequiredArgument]
    public InArgument<string> Binding { get; set; }

    [DefaultValue((string)null)]
    [RequiredArgument]
    public InArgument<string> Address { get; set; }

    [Browsable(false)]
    public Send Body { get; set; }

    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
        if (this.Body == null || this.Body.EndpointAddress != null)
        {
            metadata.AddValidationError("Error ...");
            return;
        }
        this.Body.Endpoint = new Endpoint()
        {
            AddressUri = new Uri("http://localhost/"),
            Binding = new BasicHttpBinding(),
            ServiceContractName = this.Body.ServiceContractName
        };
        metadata.AddChild(this.Body);
        base.CacheMetadata(metadata);
    }

    protected override void Execute(NativeActivityContext context)
    {
        this.Body.Endpoint.Binding = GetBinding(this.Binding.Get(context));
        this.Body.Endpoint.AddressUri = new Uri(this.Address.Get(context));
        context.ScheduleActivity(Body);
    }


    private System.ServiceModel.Channels.Binding GetBinding(string binding)
    {
        if (binding == "basicHttpBinding")
            return new BasicHttpBinding();
        //else ... others bindings
        return null;
    }
}

public class SendScopeFactory : IActivityTemplateFactory
{
    public Activity Create(DependencyObject target)
    {
        return new SendScope()
        {
            DisplayName = "SendScope",
            Body = new Send()
            {
                Action = "*",
                OperationName = "ProcessMessage",
                ServiceContractName = "IGenericContract",
            }
        };
    }
}
  1. 根据您的属性(例如 Binding、Address、Security 等)创建自定义本机活动,用于在运行时设置 Send.Endpoint 属性。
  2. 为此 SendScope 活动创建设计器,类似于 CorrelationScope
  3. 创建 SendScopeFactory - 请参阅上面的代码片段。
于 2012-09-12T11:37:23.907 回答