我在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
活动的端点地址?
答案 0 :(得分:1)
这将如图所示,因为工厂创建了新 Send
活动,因此在使用CacheMetadata
方法设置时Send
活动正在为该活动实例正确设置绑定。
[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",
}
};
}
}