2

私は、何年も何十年も続く可能性がある大規模なワークフローの更新プロセスの実装に取り​​組んでいます。私は、以前の開発者が中断したところを取り上げています。既存のコード (Microsoft が提供するにほとんど基づいている) を機能させるために 1 週​​間を費やした後、それを破棄し、独自の WorkflowVersioning ユーティリティを構築しました。永続化されたインスタンスを新しいバージョンに正常に更新できましたが、テストでは、さまざまな変更により、更新プロセス中および影響を受けるワークフローの再開時に例外が発生する可能性があることがわかりました. 私たちのワークフローは複雑であるため、やるべきことはまだあると思いますが、現時点では攻撃の計画はありません。

私が直面している 2 つの特定の問題と、コードの重要な部分をリストしました。コードの他の部分を提供する必要がある場合は、お知らせください。さらに、同様の状況で DynamicUpdate を実装したことがある場合、または役立つリソース、コード例、またはその他のドキュメントを知っている場合は、これで得られるあらゆる支援を歓迎します! WF (および一般的な専門能力開発) は初めてなので、これはかなりの学習プロセスであり、WF4.5 に固有のリソースを見つけるのに苦労しました。

バックグラウンド

現在開発中の 3 つの主要なビジネス プロセスは、それぞれが複数の子フローを持つ大きなフローで構成されており、それ自体が多くのカスタム アクティビティから構築されています。各プロセス内の主要なステップ (「タスク」と呼びます) は、NativeActivity と、Xaml デザイン サーフェイスにドラッグされたいくつかの CodeActivity で構成されます。(デザイナーの動作にも問題がありますが、別の質問のために保存します)。

特定の問題

1) フローを変更するときに、引数を追加または削除すると、更新の適用時に例外が発生します。

Exception thrown: 'System.Activities.DynamicUpdate.InstanceUpdateException' in System.Activities.dll ("In order for an implementation map to be directly applied to a workflow instance, the implementation map must indicate that there is no change to arguments. The implementation map indicates that arguments of the activity definition have changed."

MSDN によると (3 番目のリンクを投稿することはできません。コメントに追加します)、引数を追加および削除できるはずです。これを説明するためにさらにコードが必要ですか? 控えめに言っても、Google の検索結果は薄いものでした。ただし、生成された DynamicUpdateMap を分析すると、New および Old 引数が追跡されていることがわかります。

2) メイン フローに変数を追加すると、タスクの再開時に例外が発生しました。

Message=Unable to locate the ICompiledExpressionRoot for compiled location 'flowData'.  Make sure that the definition for the activity containing this expression has been compiled.

私が見つけた唯一の結果は、IIS に関するこの投稿でしたが、Visual Studio からデスクトップ アプリケーションを実行しているだけなのに、なぜこのエラーが発生するのでしょうか? この方向に私を向ける他の結果を見つけることができないようです..

WorkflowVersioning ユーティリティ プロジェクト

免責事項: このコードの多くは、Matt Milner の WF4.5pluralsight course のおかげです。実際の DynamicUpdate プロセスの例をもっと見たいと思っていますが、今のところ:

更新のためのフローの準備

まず、メイン プロセス (親ワークフロー) の .xaml から ActivityBuilder を取得します。

    private static ActivityBuilder GetBuilderFromFile(string sourcePath)
    {
        // Create the XamlXmlReaderSettings.
        Console.WriteLine("Creating Xaml Reader...");
        XamlXmlReaderSettings readerSettings = new XamlXmlReaderSettings()
        {
            LocalAssembly = Assembly.LoadFile(
                Path.GetFullPath(assemblyVersionsPath))
        };

        XamlXmlReader xamlReader = new XamlXmlReader(sourcePath, readerSettings);

        ActivityBuilder activity = XamlServices.Load(ActivityXamlServices.CreateBuilderReader(xamlReader)) as ActivityBuilder;

        return activity;
    }

次に、PrepareForUpdate を呼び出します。

DynamicUpdateServices.PrepareForUpdate(activityBuilder);

次に、追加された DynamicUpdate メタデータを使用して、ActivityBuilder をファイルに保存し直します。

    private static void SaveBuilderToFile(ActivityBuilder builder, string filePath)
    {
        // Make sure the activity builder has the right information about the c# expressions (even though its visual basic)
        VisualBasic.SetSettings(builder, VisualBasic.GetSettings(builder));

        // Set c# as the language
        System.Activities.Presentation.Expressions.ExpressionActivityEditor.SetExpressionActivityEditor(builder, "C#");

        WorkflowViewState.SetViewStateManager(
            builder.Implementation, WorkflowViewState.GetViewStateManager(builder.Implementation));

        string fullPath = Path.GetFullPath(filePath);

        using (FileStream file = File.Create(fullPath))
        {
            using (XmlWriter xmlWriter = XmlWriter.Create(file, new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true }))
            {
                using (XamlWriter xamlWriter = ActivityXamlServices.CreateBuilderWriter( new XamlXmlWriter(xmlWriter, new XamlSchemaContext())))
                {
                    XamlServices.Save(xamlWriter, builder);
                }
            }
        }
    }

更新プロセスの準備を実行した後、デザイナーを使用してワークフローを変更するか、引数/変数/アクティビティを追加/削除して NativeActivities を変更します。

DynamicUpdateMap の作成

ワークフローに必要な変更を加えた後、動的更新マップを生成します。

    public static void CreateUpdateMap(string processToMap, string sourceActivityXaml, Version targetIdentityVersion)
    {
        ActivityBuilder builder = GetBuilderFromFile(sourceActivityXaml);
        DynamicUpdateMap map = DynamicUpdateServices.CreateUpdateMap(builder);

        // save the update map
        string updateDirectory = @"..\..\UpdateMaps";
        string fileName = Path.Combine(updateDirectory, processToMap + ".map");
        // ToDo: If a .map already exists here, either delete or rename it, or prompt the user to decide.  Otherwise it mixes with the new one.
        using (FileStream fileStream = File.OpenWrite(fileName))
        {
            DataContractSerializer serializer = new DataContractSerializer(typeof(DynamicUpdateMap));
            serializer.WriteObject(fileStream, map);
        }

        // save builder back to source file, with the dynamicupdate info removed.
        SaveBuilderToFile(builder, sourceActivityXaml);
    }

影響を受けるインスタンスに更新マップを適用する

最後に、各インスタンスを永続的に繰り返し処理し、更新を適用します。

foreach (Guid id in GetIds())
        {
            // Get a proxy to the instance
            WorkflowApplicationInstance instance = WorkflowApplication.GetInstance(id, store);

            Console.WriteLine("Inspecting: {0}", instance.DefinitionIdentity);

            if (instance.DefinitionIdentity != null &&
                instance.DefinitionIdentity.Name == processToUpdate.ToString() &&
                instance.DefinitionIdentity.Version.Equals(previousVersion))
            {
                Tuple<WorkflowIdentity, DynamicUpdateMap> mapInfo = manager.GetMap(instance.DefinitionIdentity);
                DynamicUpdateMap map = mapInfo.Item2;
                WorkflowIdentity newIdentity = mapInfo.Item1;

                // get the application, loading, and applying the map
                //WorkflowApplication wfApp = GetWorkflowApplication( manager[newIdentity], instance, newIdentity, map);

                Activity wf = manager[newIdentity];

                WorkflowApplication wfApp = new WorkflowApplication(wf, newIdentity);

                wfApp.Load(instance, map);

                wfApp.Unload();

            }
            else
            {
                instance.Abandon();
                Console.WriteLine("Instance {0} is not updatable", instance.InstanceId);
            }
        }
4

0 に答える 0