2

考虑一个在 IIS 中运行的 WF4 项目,它具有一个工作流定义 (xamlx) 和一个用于持久性的 SqlInstanceStore。我们不是直接托管 xamlx,而是托管一个 WorkflowServiceHostFactory,它为每个客户在单独的端点上启动一个专用的 WorkflowServiceHost。

这已经运行了一段时间,直到我们需要新版本的工作流定义,所以现在在 Flow.xamlx 之上我有 Flow1.xamlx。由于与工作流服务的所有交互都使用足够智能的业务逻辑来识别所需版本,因此这种自制版本控制适用于新启动的工作流(在 Flow.xamlx 和 Flow1.xamlx 上)。

但是,在此更改之前启动的工作流无法重新激活(在帖子中,服务主机会引发 UnknownMessageReceived 异常)。由于 WF 在告诉您为什么它不能重新激活工作流(错误版本、未找到实例、锁定等)方面并不过分冗长,我们将 SQL 分析器附加到数据库。

事实证明,WorkflowServiceHost 在其查询中使用的“WorkflowServiceType”与存储实例的“WorkflowServiceType”不同。可能这就是它无法检测到持久实例的原因。

因为我很确定我实例化了相同的 xamlx,所以我不明白这个值是从哪里来的。计算此 Guid 的参数有哪些,环境是否重要(站点名称),我可以做些什么来重新激活工作流?

4

1 回答 1

3

最后我反编译了 System.Activities.DurableInstancing。SqlWorkflowInstanceStore 上 WorkflowHostType 的唯一设置器位于 ExtractWorkflowHostType 中:

private void ExtractWorkflowHostType(IDictionary<XName, InstanceValue> commandMetadata)
{
    InstanceValue instanceValue;
    if (commandMetadata.TryGetValue(WorkflowNamespace.WorkflowHostType, out instanceValue))
    {
        XName xName = instanceValue.Value as XName;
        if (xName == null)
        {
            throw FxTrace.Exception.AsError(new InstancePersistenceCommandException(SR.InvalidMetadataValue(WorkflowNamespace.WorkflowHostType, typeof(XName).Name)));
        }
        byte[] bytes = Encoding.Unicode.GetBytes(xName.ToString());
        base.Store.WorkflowHostType = new Guid(HashHelper.ComputeHash(bytes));
        this.fireRunnableInstancesEvent = true;
    }
}

我无法清楚地解开调用代码路径,所以我必须在运行时通过将 WinDbg/SOS 附加到 IIS 并在 HashHelper.ComputeHash 上中断来找出答案。

我能够检索进入哈希计算的 XName,它的本地名称等于服务文件,命名空间等于 [站点名称]/[路径]/。

最后 WorkflowHostType 计算归结为:

var xName = XName.Get("Flow.xamlx.svc", "/examplesite/WorkflowService/1/");
var bytes = Encoding.Unicode.GetBytes(xName.ToString());
var WorkflowHostType = new Guid(HashHelper.ComputeHash(bytes));

底线:显然,只有当服务文件名、站点名和路径与启动时相同(区分大小写)时,才能重新处理工作流

于 2013-08-29T07:42:24.103 回答