在工作流中动态解析端点绑定

时间:2012-09-11 21:02:46

标签: wcf workflow-foundation-4 wcf-endpoint

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

当内部Send活动被一个具有某个enpoint地址的线程调度执行时,这个地址不会被另一个调度具有不同端点地址的相同活动的线程覆盖吗?如果我弄错了,请纠正我,但我认为它会,因为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活动的端点地址?

1 个答案:

答案 0 :(得分:1)

这将如图所示,因为工厂创建了 Send活动,因此在使用CacheMetadata方法设置时Send活动正在为该活动实例正确设置绑定。

包括Content Incase Link Dies

[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. 根据您的属性(如绑定,地址,安全性等),在运行时期间创建用于设置Send.Endpoint属性的自定义本机活动。
  2. 为此SendScope活动创建设计器,类似于CorrelationScope
  3. 创建SendScopeFactory - 请参阅上面的代码段。