代码之家  ›  专栏  ›  技术社区  ›  Ruurd Keizer

破损的WF4工作流补水

  •  2
  • Ruurd Keizer  · 技术社区  · 11 年前

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

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

    但是,在此更改之前启动的工作流无法重新激活(在发布时,servicehost抛出UnknownMessageReceived异常)。 由于WF在告诉您为什么它不能重新激活工作流(错误的版本、找不到实例、锁定等)时不会过于冗长,因此我们在数据库中附加了一个SQL探查器。

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

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

    1 回复  |  直到 11 年前
        1
  •  3
  •   Ruurd Keizer    11 年前

    最后,我反编译了System.Activities.DableInstancing。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,它的localname等于servicefile,namespace等于[sitename]/[path]/。

    最后,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));
    

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

    推荐文章