方法: ワークフローの複数のバージョンを同時にホストする

WorkflowIdentity を使用すると、ワークフロー アプリケーションの開発者は、名前とバージョンをワークフロー定義に関連付け、永続化されたワークフロー インスタンスにこの情報を関連付けることができます。 この ID 情報は、ワークフロー アプリケーションの開発者がワークフロー定義の複数のバージョンの side-by-side 実行などのシナリオを有効にするために使用できます。また、動的更新などの他の機能の基礎となります。 チュートリアルのこの手順では、WorkflowIdentity を使用してワークフローの複数のバージョンを同時にホストする方法について説明します。

このトピックの内容

チュートリアルのこの手順では、追加情報を提供するようにワークフローの WriteLine アクティビティが変更され、新しい WriteLine アクティビティが追加されます。 元のワークフロー アセンブリのコピーが格納され、ホスト アプリケーションは、元のワークフローと更新されたワークフローの両方を同時に実行できるように更新されます。

注意

このトピックの手順を実行する前に、アプリケーションを実行し、各種類のワークフローをいくつか開始して、ワークフローごとに 1 つまたは 2 つの推定値を作成します。 これらの永続化されたワークフローは、この手順と、「方法: 実行中のワークフロー インスタンスの定義を更新する」の手順で使用します。

NumberGuessWorkflowActivities プロジェクトのコピーを作成するには

  1. Visual Studio 2012 で WF45GettingStartedTutorial ソリューションを開きます (まだ開いていない場合)。

  2. Ctrl + Shift + B キーを押して、ソリューションをビルドします。

  3. WF45GettingStartedTutorial ソリューションを閉じます。

  4. エクスプローラーを開き、チュートリアルのソリューション ファイルおよびプロジェクト フォルダーが格納されているフォルダーに移動します。

  5. PreviousVersions という名前の新しいフォルダーを、NumberGuessWorkflowHost および NumberGuessWorkflowActivities と同じフォルダーに作成します。 このフォルダーは、チュートリアルの以降の手順で使用されるワークフローの異なるバージョンを含むアセンブリを格納するために使用されます。

  6. NumberGuessWorkflowActivities\bin\debug フォルダー (プロジェクトの設定によっては bin\release) に移動します。 NumberGuessWorkflowActivities.dll をコピーして、PreviousVersions フォルダーに貼り付けます。

  7. PreviousVersions フォルダー内の NumberGuessWorkflowActivities.dll の名前を NumberGuessWorkflowActivities_v1.dll に変更します。

    注意

    このトピックの手順では、ワークフローの複数のバージョンを格納するためのアセンブリを管理する 1 つの方法を示します。 アセンブリに厳密な名前を付けてグローバル アセンブリ キャッシュに登録するなど、他の方法も使用できます。

  8. NumberGuessWorkflowHostNumberGuessWorkflowActivities、および新しく追加した PreviousVersions フォルダーと同じフォルダー内に NumberGuessWorkflowActivities_du という名前の新しいフォルダーを作成し、NumberGuessWorkflowActivities フォルダーのすべてのファイルとサブフォルダーを新しい NumberGuessWorkflowActivities_du フォルダーにコピーします。 アクティビティの最初のバージョンのプロジェクトのこのバックアップ コピーは、「方法: 実行中のワークフロー インスタンスの定義を更新する」で使用されます。

  9. Visual Studio 2012 で WF45GettingStartedTutorial ソリューションを再度開きます。

ワークフローを更新するには

ここでは、ワークフロー定義が更新されます。 ユーザーの推定値についてフィードバックを返す 2 つの WriteLine アクティビティが更新され、新しい WriteLine アクティビティが追加されます。新しいアクティビティは、数値が推定されるとゲームに関する追加情報を提供します。

StateMachine ワークフローを更新するには

  1. ソリューション エクスプローラーで、NumberGuessWorkflowActivities プロジェクトの下の StateMachineNumberGuessWorkflow.xaml をダブルクリックします。

  2. ステート マシンの Guess Incorrect 遷移をダブルクリックします。

  3. Text アクティビティで、左端の WriteLineIf を更新します。

    Guess & " is too low."
    
    Guess + " is too low."
    
  4. Text アクティビティで、右端の WriteLineIf を更新します。

    Guess & " is too high."
    
    Guess + " is too high."
    
  5. ワークフロー デザイナーの上部にある階層リンク表示の [StateMachine] をクリックして、ワークフロー デザイナーの全体的なステート マシン ビューに戻ります。

  6. ステート マシンの Guess Correct 遷移をダブルクリックします。

  7. ツールボックス[プリミティブ] セクションから WriteLine アクティビティをドラッグし、遷移の [ここに Action アクティビティをドロップします] ラベル上にドロップします。

  8. Text プロパティ ボックスに、次の式を入力します。

    Guess & " is correct. You guessed it in " & Turns & " turns."
    
    Guess + " is correct. You guessed it in " + Turns + " turns."
    

フローチャート ワークフローを更新するには

  1. ソリューション エクスプローラーで、NumberGuessWorkflowActivities プロジェクトの下の FlowchartNumberGuessWorkflow.xaml をダブルクリックします。

  2. 左端の Text アクティビティの WriteLine を更新します。

    Guess & " is too low."
    
    Guess + " is too low."
    
  3. 右端の Text アクティビティの WriteLine を更新します。

    Guess & " is too high."
    
    Guess + " is too high."
    
  4. ツールボックス[プリミティブ] セクションから WriteLine アクティビティをドラッグし、最上位の FlowDecisionTrue アクションのドロップ ポイント上にドロップします。 WriteLine アクティビティがフローチャートに追加され、TrueFlowDecision アクションにリンクされます。

  5. Text プロパティ ボックスに、次の式を入力します。

    Guess & " is correct. You guessed it in " & Turns & " turns."
    
    Guess + " is correct. You guessed it in " + Turns + " turns."
    

シーケンシャル ワークフローを更新するには

  1. ソリューション エクスプローラーで、NumberGuessWorkflowActivities プロジェクトの下の SequentialNumberGuessWorkflow.xaml をダブルクリックします。

  2. Text アクティビティで、左端の WriteLineIf を更新します。

    Guess & " is too low."
    
    Guess + " is too low."
    
  3. Text アクティビティで、右端の WriteLine アクティビティの If を更新します。

    Guess & " is too high."
    
    Guess + " is too high."
    
  4. WriteLine がルートの Sequence アクティビティの最後のアクティビティになるように、ツールボックス[プリミティブ] セクションから WriteLine アクティビティをドラッグし、DoWhile アクティビティの後ろにドロップします。

  5. Text プロパティ ボックスに、次の式を入力します。

    Guess & " is correct. You guessed it in " & Turns & " turns."
    
    Guess + " is correct. You guessed it in " + Turns + " turns."
    

以前のワークフロー バージョンを含むように WorkflowVersionMap を更新するには

  1. NumberGuessWorkflowHost プロジェクトの下の WorkflowVersionMap.cs (または WorkflowVersionMap.vb) をダブルクリックして開きます。

  2. 次の using (または Imports) ステートメントを、他の using (または Imports) ステートメントを含むファイルの先頭に追加します。

    Imports System.Reflection
    Imports System.IO
    
    using System.Reflection;
    using System.IO;
    
  3. 既存の 3 つのワークフロー ID 宣言の直後に、新しいワークフロー ID を 3 つ追加します。 これらの新しい v1 ワークフロー ID は、更新が行われる前に開始されたワークフローに対して正しいワークフロー定義を指定するために使用されます。

    'Current version identities.
    Public StateMachineNumberGuessIdentity As WorkflowIdentity
    Public FlowchartNumberGuessIdentity As WorkflowIdentity
    Public SequentialNumberGuessIdentity As WorkflowIdentity
    
    'v1 Identities.
    Public StateMachineNumberGuessIdentity_v1 As WorkflowIdentity
    Public FlowchartNumberGuessIdentity_v1 As WorkflowIdentity
    Public SequentialNumberGuessIdentity_v1 As WorkflowIdentity
    
    // Current version identities.
    static public WorkflowIdentity StateMachineNumberGuessIdentity;
    static public WorkflowIdentity FlowchartNumberGuessIdentity;
    static public WorkflowIdentity SequentialNumberGuessIdentity;
    
    // v1 identities.
    static public WorkflowIdentity StateMachineNumberGuessIdentity_v1;
    static public WorkflowIdentity FlowchartNumberGuessIdentity_v1;
    static public WorkflowIdentity SequentialNumberGuessIdentity_v1;
    
  4. WorkflowVersionMap コンストラクターで、3 つの現在のワークフロー ID の Version プロパティを 2.0.0.0 に更新します。

    'Add the current workflow version identities.
    StateMachineNumberGuessIdentity = New WorkflowIdentity With
    {
        .Name = "StateMachineNumberGuessWorkflow",
        .Version = New Version(2, 0, 0, 0)
    }
    
    FlowchartNumberGuessIdentity = New WorkflowIdentity With
    {
        .Name = "FlowchartNumberGuessWorkflow",
        .Version = New Version(2, 0, 0, 0)
    }
    
    SequentialNumberGuessIdentity = New WorkflowIdentity With
    {
        .Name = "SequentialNumberGuessWorkflow",
        .Version = New Version(2, 0, 0, 0)
    }
    
    map.Add(StateMachineNumberGuessIdentity, New StateMachineNumberGuessWorkflow())
    map.Add(FlowchartNumberGuessIdentity, New FlowchartNumberGuessWorkflow())
    map.Add(SequentialNumberGuessIdentity, New SequentialNumberGuessWorkflow())
    
    // Add the current workflow version identities.
    StateMachineNumberGuessIdentity = new WorkflowIdentity
    {
        Name = "StateMachineNumberGuessWorkflow",
        // Version = new Version(1, 0, 0, 0),
        Version = new Version(2, 0, 0, 0)
    };
    
    FlowchartNumberGuessIdentity = new WorkflowIdentity
    {
        Name = "FlowchartNumberGuessWorkflow",
        // Version = new Version(1, 0, 0, 0),
        Version = new Version(2, 0, 0, 0)
    };
    
    SequentialNumberGuessIdentity = new WorkflowIdentity
    {
        Name = "SequentialNumberGuessWorkflow",
        // Version = new Version(1, 0, 0, 0),
        Version = new Version(2, 0, 0, 0)
    };
    
    map.Add(StateMachineNumberGuessIdentity, new StateMachineNumberGuessWorkflow());
    map.Add(FlowchartNumberGuessIdentity, new FlowchartNumberGuessWorkflow());
    map.Add(SequentialNumberGuessIdentity, new SequentialNumberGuessWorkflow());
    

    ワークフローの現在のバージョンをディクショナリに追加するコードでは、プロジェクトで参照されている現在のバージョンを使用しているため、ワークフロー定義を初期化するコードを更新する必要はありません。

  5. コンストラクターで、現在のバージョンをディクショナリに追加するコードの直後に、次のコードを追加します。

    'Initialize the previous workflow version identities.
    StateMachineNumberGuessIdentity_v1 = New WorkflowIdentity With
    {
        .Name = "StateMachineNumberGuessWorkflow",
        .Version = New Version(1, 0, 0, 0)
    }
    
    FlowchartNumberGuessIdentity_v1 = New WorkflowIdentity With
    {
        .Name = "FlowchartNumberGuessWorkflow",
        .Version = New Version(1, 0, 0, 0)
    }
    
    SequentialNumberGuessIdentity_v1 = New WorkflowIdentity With
    {
        .Name = "SequentialNumberGuessWorkflow",
        .Version = New Version(1, 0, 0, 0)
    }
    
    // Initialize the previous workflow version identities.
    StateMachineNumberGuessIdentity_v1 = new WorkflowIdentity
    {
        Name = "StateMachineNumberGuessWorkflow",
        Version = new Version(1, 0, 0, 0)
    };
    
    FlowchartNumberGuessIdentity_v1 = new WorkflowIdentity
    {
        Name = "FlowchartNumberGuessWorkflow",
        Version = new Version(1, 0, 0, 0)
    };
    
    SequentialNumberGuessIdentity_v1 = new WorkflowIdentity
    {
        Name = "SequentialNumberGuessWorkflow",
        Version = new Version(1, 0, 0, 0)
    };
    

    これらのワークフロー ID は、対応するワークフロー定義の最初のバージョンに関連付けられます。

  6. 次に、ワークフロー定義の最初のバージョンを含むアセンブリを読み込み、対応するワークフロー定義を作成してそのディクショナリに追加します。

    'Add the previous version workflow identities to the dictionary along with
    'the corresponding workflow definitions loaded from the v1 assembly.
    'Assembly.LoadFile requires an absolute path so convert this relative path
    'to an absolute path.
    Dim v1AssemblyPath As String = "..\..\..\PreviousVersions\NumberGuessWorkflowActivities_v1.dll"
    v1AssemblyPath = Path.GetFullPath(v1AssemblyPath)
    Dim v1Assembly As Assembly = Assembly.LoadFile(v1AssemblyPath)
    
    map.Add(StateMachineNumberGuessIdentity_v1,
        v1Assembly.CreateInstance("NumberGuessWorkflowActivities.StateMachineNumberGuessWorkflow"))
    
    map.Add(SequentialNumberGuessIdentity_v1,
        v1Assembly.CreateInstance("NumberGuessWorkflowActivities.SequentialNumberGuessWorkflow"))
    
    map.Add(FlowchartNumberGuessIdentity_v1,
        v1Assembly.CreateInstance("NumberGuessWorkflowActivities.FlowchartNumberGuessWorkflow"))
    
    // Add the previous version workflow identities to the dictionary along with
    // the corresponding workflow definitions loaded from the v1 assembly.
    // Assembly.LoadFile requires an absolute path so convert this relative path
    // to an absolute path.
    string v1AssemblyPath = @"..\..\..\PreviousVersions\NumberGuessWorkflowActivities_v1.dll";
    v1AssemblyPath = Path.GetFullPath(v1AssemblyPath);
    Assembly v1Assembly = Assembly.LoadFile(v1AssemblyPath);
    
    map.Add(StateMachineNumberGuessIdentity_v1,
        v1Assembly.CreateInstance("NumberGuessWorkflowActivities.StateMachineNumberGuessWorkflow") as Activity);
    
    map.Add(SequentialNumberGuessIdentity_v1,
        v1Assembly.CreateInstance("NumberGuessWorkflowActivities.SequentialNumberGuessWorkflow") as Activity);
    
    map.Add(FlowchartNumberGuessIdentity_v1,
        v1Assembly.CreateInstance("NumberGuessWorkflowActivities.FlowchartNumberGuessWorkflow") as Activity);
    

    次の例では、更新された WorkflowVersionMap クラス全体を示します。

    Public Module WorkflowVersionMap
        Dim map As Dictionary(Of WorkflowIdentity, Activity)
    
        'Current version identities.
        Public StateMachineNumberGuessIdentity As WorkflowIdentity
        Public FlowchartNumberGuessIdentity As WorkflowIdentity
        Public SequentialNumberGuessIdentity As WorkflowIdentity
    
        'v1 Identities.
        Public StateMachineNumberGuessIdentity_v1 As WorkflowIdentity
        Public FlowchartNumberGuessIdentity_v1 As WorkflowIdentity
        Public SequentialNumberGuessIdentity_v1 As WorkflowIdentity
    
        Sub New()
            map = New Dictionary(Of WorkflowIdentity, Activity)
    
            'Add the current workflow version identities.
            StateMachineNumberGuessIdentity = New WorkflowIdentity With
            {
                .Name = "StateMachineNumberGuessWorkflow",
                .Version = New Version(2, 0, 0, 0)
            }
    
            FlowchartNumberGuessIdentity = New WorkflowIdentity With
            {
                .Name = "FlowchartNumberGuessWorkflow",
                .Version = New Version(2, 0, 0, 0)
            }
    
            SequentialNumberGuessIdentity = New WorkflowIdentity With
            {
                .Name = "SequentialNumberGuessWorkflow",
                .Version = New Version(2, 0, 0, 0)
            }
    
            map.Add(StateMachineNumberGuessIdentity, New StateMachineNumberGuessWorkflow())
            map.Add(FlowchartNumberGuessIdentity, New FlowchartNumberGuessWorkflow())
            map.Add(SequentialNumberGuessIdentity, New SequentialNumberGuessWorkflow())
    
            'Initialize the previous workflow version identities.
            StateMachineNumberGuessIdentity_v1 = New WorkflowIdentity With
            {
                .Name = "StateMachineNumberGuessWorkflow",
                .Version = New Version(1, 0, 0, 0)
            }
    
            FlowchartNumberGuessIdentity_v1 = New WorkflowIdentity With
            {
                .Name = "FlowchartNumberGuessWorkflow",
                .Version = New Version(1, 0, 0, 0)
            }
    
            SequentialNumberGuessIdentity_v1 = New WorkflowIdentity With
            {
                .Name = "SequentialNumberGuessWorkflow",
                .Version = New Version(1, 0, 0, 0)
            }
    
            'Add the previous version workflow identities to the dictionary along with
            'the corresponding workflow definitions loaded from the v1 assembly.
            'Assembly.LoadFile requires an absolute path so convert this relative path
            'to an absolute path.
            Dim v1AssemblyPath As String = "..\..\..\PreviousVersions\NumberGuessWorkflowActivities_v1.dll"
            v1AssemblyPath = Path.GetFullPath(v1AssemblyPath)
            Dim v1Assembly As Assembly = Assembly.LoadFile(v1AssemblyPath)
    
            map.Add(StateMachineNumberGuessIdentity_v1,
                v1Assembly.CreateInstance("NumberGuessWorkflowActivities.StateMachineNumberGuessWorkflow"))
    
            map.Add(SequentialNumberGuessIdentity_v1,
                v1Assembly.CreateInstance("NumberGuessWorkflowActivities.SequentialNumberGuessWorkflow"))
    
            map.Add(FlowchartNumberGuessIdentity_v1,
                v1Assembly.CreateInstance("NumberGuessWorkflowActivities.FlowchartNumberGuessWorkflow"))
        End Sub
    
        Public Function GetWorkflowDefinition(identity As WorkflowIdentity) As Activity
            Return map(identity)
        End Function
    
        Public Function GetIdentityDescription(identity As WorkflowIdentity) As String
            Return identity.ToString()
        End Function
    End Module
    
    public static class WorkflowVersionMap
    {
        static Dictionary<WorkflowIdentity, Activity> map;
    
        // Current version identities.
        static public WorkflowIdentity StateMachineNumberGuessIdentity;
        static public WorkflowIdentity FlowchartNumberGuessIdentity;
        static public WorkflowIdentity SequentialNumberGuessIdentity;
    
        // v1 identities.
        static public WorkflowIdentity StateMachineNumberGuessIdentity_v1;
        static public WorkflowIdentity FlowchartNumberGuessIdentity_v1;
        static public WorkflowIdentity SequentialNumberGuessIdentity_v1;
    
        static WorkflowVersionMap()
        {
            map = new Dictionary<WorkflowIdentity, Activity>();
    
            // Add the current workflow version identities.
            StateMachineNumberGuessIdentity = new WorkflowIdentity
            {
                Name = "StateMachineNumberGuessWorkflow",
                // Version = new Version(1, 0, 0, 0),
                Version = new Version(2, 0, 0, 0)
            };
    
            FlowchartNumberGuessIdentity = new WorkflowIdentity
            {
                Name = "FlowchartNumberGuessWorkflow",
                // Version = new Version(1, 0, 0, 0),
                Version = new Version(2, 0, 0, 0)
            };
    
            SequentialNumberGuessIdentity = new WorkflowIdentity
            {
                Name = "SequentialNumberGuessWorkflow",
                // Version = new Version(1, 0, 0, 0),
                Version = new Version(2, 0, 0, 0)
            };
    
            map.Add(StateMachineNumberGuessIdentity, new StateMachineNumberGuessWorkflow());
            map.Add(FlowchartNumberGuessIdentity, new FlowchartNumberGuessWorkflow());
            map.Add(SequentialNumberGuessIdentity, new SequentialNumberGuessWorkflow());
    
            // Initialize the previous workflow version identities.
            StateMachineNumberGuessIdentity_v1 = new WorkflowIdentity
            {
                Name = "StateMachineNumberGuessWorkflow",
                Version = new Version(1, 0, 0, 0)
            };
    
            FlowchartNumberGuessIdentity_v1 = new WorkflowIdentity
            {
                Name = "FlowchartNumberGuessWorkflow",
                Version = new Version(1, 0, 0, 0)
            };
    
            SequentialNumberGuessIdentity_v1 = new WorkflowIdentity
            {
                Name = "SequentialNumberGuessWorkflow",
                Version = new Version(1, 0, 0, 0)
            };
    
            // Add the previous version workflow identities to the dictionary along with
            // the corresponding workflow definitions loaded from the v1 assembly.
            // Assembly.LoadFile requires an absolute path so convert this relative path
            // to an absolute path.
            string v1AssemblyPath = @"..\..\..\PreviousVersions\NumberGuessWorkflowActivities_v1.dll";
            v1AssemblyPath = Path.GetFullPath(v1AssemblyPath);
            Assembly v1Assembly = Assembly.LoadFile(v1AssemblyPath);
    
            map.Add(StateMachineNumberGuessIdentity_v1,
                v1Assembly.CreateInstance("NumberGuessWorkflowActivities.StateMachineNumberGuessWorkflow") as Activity);
    
            map.Add(SequentialNumberGuessIdentity_v1,
                v1Assembly.CreateInstance("NumberGuessWorkflowActivities.SequentialNumberGuessWorkflow") as Activity);
    
            map.Add(FlowchartNumberGuessIdentity_v1,
                v1Assembly.CreateInstance("NumberGuessWorkflowActivities.FlowchartNumberGuessWorkflow") as Activity);
        }
    
        public static Activity GetWorkflowDefinition(WorkflowIdentity identity)
        {
            return map[identity];
        }
    
        public static string GetIdentityDescription(WorkflowIdentity identity)
        {
            return identity.ToString();
        }
    }
    

アプリケーションをビルドして実行するには

  1. Ctrl キーと Shift キーを押しながら B キーを押してアプリケーションをビルドし、Ctrl キーを押しながら F5 キーを押して起動します。

  2. [New Game] をクリックして、新しいワークフローを開始します。 ワークフローのバージョンは、ステータス ウィンドウの下に表示され、関連付けられた WorkflowIdentity から更新後のバージョンを反映します。 完了時にワークフローの追跡ファイルを確認できるように InstanceId を書き留めておき、ゲームが完了するまで推定値を入力します。 WriteLine アクティビティに対する更新に基づき、ステータス ウィンドウに示される情報に、ユーザーの推定値がどのように表示されるかを確認します。

    Please enter a number between 1 and 10
    5 is too high.
    Please enter a number between 1 and 10
    3 is too high.
    Please enter a number between 1 and 10
    1 is too low.
    Please enter a number between 1 and 10
    Congratulations, you guessed the number in 4 turns.
    

    注意

    WriteLine アクティビティから更新されたテキストは表示されますが、このトピックで追加された最後の WriteLine アクティビティの出力は表示されません。 これは、ステータス ウィンドウが PersistableIdle ハンドラーによって更新されるためです。 ワークフローは完了し、最後のアクティビティの後にアイドル状態にならないため、PersistableIdle ハンドラーは呼び出されません。 ただし、Completed ハンドラーによって同様のメッセージがステータス ウィンドウに表示されます。 必要に応じて、コードを Completed ハンドラーに追加し、StringWriter からテキストを抽出してステータス ウィンドウに表示できます。

  3. エクスプローラーを開き、NumberGuessWorkflowHost\bin\debug フォルダー (プロジェクトの設定によっては bin\release) に移動して、完了したワークフローに対応する追跡ファイルをメモ帳を使用して開きます。 InstanceId を書き留めなかった場合は、エクスプローラーの [更新日時] の情報を使用して正しい追跡ファイルを特定できます。

    Please enter a number between 1 and 10
    5 is too high.
    Please enter a number between 1 and 10
    3 is too high.
    Please enter a number between 1 and 10
    1 is too low.
    Please enter a number between 1 and 10
    2 is correct. You guessed it in 4 turns.
    

    更新された WriteLine の出力は、このトピックで追加した WriteLine の出力を含む追跡ファイル内に含まれています。

  4. 数値推測アプリケーションに戻り、更新が行われる前に開始したワークフローのうち 1 つを選択します。 現在選択されているワークフローのバージョンを特定するには、ステータス ウィンドウの下に表示されるバージョン情報を確認します。 いくつかの推定値を入力し、ステータスの更新が前のバージョンからの WriteLine アクティビティの出力と一致しており、ユーザーの推定値が含まれていないことを確認してください。 これらのワークフローでは、WriteLine の更新を含まない以前のワークフロー定義を使用しているためです。

    次のステップ「方法: 実行中のワークフロー インスタンスの定義を更新する」では、実行中の v1 ワークフロー インスタンスを更新して、v2 インスタンスとして新機能が含まれるようにします。