방법: 실행 중인 워크플로 인스턴스의 정의 업데이트

동적 업데이트는 워크플로 애플리케이션 개발자가 지속형 워크플로 인스턴스의 워크플로 정의를 업데이트하기 위한 메커니즘을 제공합니다. 필요한 변경을 통해 버그 수정 또는 새 요구 사항을 구현하거나 예기치 않은 변경 내용을 수용할 수 있습니다. 자습서의 이 단계에서는 방법: 여러 버전의 워크플로를 함께 호스팅에서 소개한 새 기능과 일치하도록 동적 업데이트를 사용하여 v1 숫자 추측 워크플로의 지속형 인스턴스를 수정하는 방법을 보여 줍니다.

이 항목의 내용

CreateUpdateMaps 프로젝트를 만들려면

  1. 솔루션 탐색기에서 WF45GettingStartedTutorial을 마우스 오른쪽 단추로 클릭하고 추가, 새 프로젝트를 차례로 선택합니다.

  2. 설치됨 노드에서 Visual C#, Windows(또는 Visual Basic, Windows)를 차례로 선택합니다.

    참고 항목

    설치됨 노드의 다른 언어 노드 아래에는 Visual Studio에서 기본 언어로 구성된 프로그래밍 언어에 따라 Visual C# 또는 Visual Basic 노드가 표시될 수 있습니다.

    .NET Framework 버전 드롭다운 목록에서 .NET Framework 4.5 가 선택되어 있는지 확인합니다. Windows 목록에서 콘솔 애플리케이션을 선택합니다. 이름 상자에 CreateUpdateMaps를 입력하고 확인을 클릭합니다.

  3. 솔루션 탐색기에서 CreateUpdateMaps를 마우스 오른쪽 단추로 클릭하고 참조 추가를 선택합니다.

  4. 참조 추가 목록의 어셈블리 노드에서 프레임워크를 선택합니다. 어셈블리 검색 상자에 System.Activities를 입력하여 어셈블리를 필터링하면 원하는 참조를 손쉽게 선택할 수 있습니다.

  5. 검색 결과 목록에서 System.Activities 옆의 확인란을 선택합니다.

  6. 어셈블리 검색 상자에 Serialization을 입력하고 검색 결과 목록에서 System.Runtime.Serialization 옆의 확인란을 선택합니다.

  7. 어셈블리 검색 상자에 System.Xaml을 입력하고 검색 결과 목록에서 System.Xaml 옆의 확인란을 선택합니다.

  8. 확인을 클릭하여 참조 관리자를 닫고 참조를 추가합니다.

  9. 다음 using(또는 Imports) 문을 파일의 맨 위에 다른 using(또는 Imports) 문과 함께 추가합니다.

    Imports System.Activities
    Imports System.Activities.Statements
    Imports System.Xaml
    Imports System.Reflection
    Imports System.IO
    Imports System.Activities.XamlIntegration
    Imports System.Activities.DynamicUpdate
    Imports System.Runtime.Serialization
    Imports Microsoft.VisualBasic.Activities
    
    using System.Activities;
    using System.Activities.Statements;
    using System.IO;
    using System.Xaml;
    using System.Reflection;
    using System.Activities.XamlIntegration;
    using System.Activities.DynamicUpdate;
    using System.Runtime.Serialization;
    using Microsoft.CSharp.Activities;
    
  10. Program(또는 Module1) 클래스에 다음 두 개의 문자열 멤버를 추가합니다.

    Const mapPath = "..\..\..\PreviousVersions"
    Const definitionPath = "..\..\..\NumberGuessWorkflowActivities_du"
    
    const string mapPath = @"..\..\..\PreviousVersions";
    const string definitionPath = @"..\..\..\NumberGuessWorkflowActivities_du";
    
  11. StartUpdate(또는 Program) 클래스에 다음 Module1 메서드를 추가합니다. 이 메서드는 지정된 xaml 워크플로 정의를 ActivityBuilder에 로드한 다음 DynamicUpdate.PrepareForUpdate를 호출합니다. PrepareForUpdateActivityBuilder 내에 워크플로 정의의 복사본을 만듭니다. 워크플로 정의가 수정되면 이 복사본이 수정된 워크플로 정의와 함께 사용되어 업데이트 맵을 만듭니다.

    Private Function StartUpdate(name As String) As ActivityBuilder
        'Create the XamlXmlReaderSettings.
        Dim readerSettings As XamlReaderSettings = New XamlXmlReaderSettings()
        'In the XAML the "local" namespace refers to artifacts that come from
        'the same project as the XAML. When loading XAML if the currently executing
        'assembly is not the same assembly that was referred to as "local" in the XAML
        'LocalAssembly must be set to the assembly containing the artifacts.
        'Assembly.LoadFile requires an absolute path so convert this relative path
        'to an absolute path.
        readerSettings.LocalAssembly = Assembly.LoadFile(
            Path.GetFullPath(Path.Combine(mapPath, "NumberGuessWorkflowActivities_v1.dll")))
    
        Dim fullPath As String = Path.Combine(definitionPath, name)
        Dim xamlReader As XamlXmlReader = New XamlXmlReader(fullPath, readerSettings)
    
        'Load the workflow definition into an ActivityBuilder.
        Dim wf As ActivityBuilder = XamlServices.Load(
            ActivityXamlServices.CreateBuilderReader(xamlReader))
    
        'PrepareForUpdate makes a copy of the workflow definition in the
        'ActivityBuilder that is used for comparison when the update
        'map is created.
        DynamicUpdateServices.PrepareForUpdate(wf)
    
        Return wf
    End Function
    
    private static ActivityBuilder StartUpdate(string name)
    {
        // Create the XamlXmlReaderSettings.
        XamlXmlReaderSettings readerSettings = new XamlXmlReaderSettings()
        {
            // In the XAML the "local" namespace refers to artifacts that come from
            // the same project as the XAML. When loading XAML if the currently executing
            // assembly is not the same assembly that was referred to as "local" in the XAML
            // LocalAssembly must be set to the assembly containing the artifacts.
            // Assembly.LoadFile requires an absolute path so convert this relative path
            // to an absolute path.
            LocalAssembly = Assembly.LoadFile(
                Path.GetFullPath(Path.Combine(mapPath, "NumberGuessWorkflowActivities_v1.dll")))
        };
    
        string path = Path.Combine(definitionPath, name);
        XamlXmlReader xamlReader = new XamlXmlReader(path, readerSettings);
    
        // Load the workflow definition into an ActivityBuilder.
        ActivityBuilder wf = XamlServices.Load(
            ActivityXamlServices.CreateBuilderReader(xamlReader))
            as ActivityBuilder;
    
        // PrepareForUpdate makes a copy of the workflow definition in the
        // ActivityBuilder that is used for comparison when the update
        // map is created.
        DynamicUpdateServices.PrepareForUpdate(wf);
    
        return wf;
    }
    
  12. 다음에는 CreateUpdateMethod(또는 Program) 클래스에 다음 Module1를 추가합니다. 그러면 DynamicUpdateServices.CreateUpdateMap을 호출하여 동적 업데이트 맵이 만들어지고 지정된 이름을 사용하여 업데이트 맵이 저장됩니다. 이 업데이트 맵에는 ActivityBuilder에 포함된 원래 워크플로 정의를 사용하여 시작된 지속형 워크플로 인스턴스가 업데이트된 워크플로 정의를 사용하여 완료될 수 있도록 워크플로 런타임이 이 인스턴스를 업데이트하는 데 필요한 정보가 포함되어 있습니다.

    Private Sub CreateUpdateMaps(wf As ActivityBuilder, name As String)
        'Create the UpdateMap.
        Dim map As DynamicUpdateMap =
            DynamicUpdateServices.CreateUpdateMap(wf)
    
        'Serialize it to a file.
        Dim mapFullPath As String = Path.Combine(mapPath, name)
        Dim sz As DataContractSerializer = New DataContractSerializer(GetType(DynamicUpdateMap))
        Using fs As FileStream = File.Open(mapFullPath, FileMode.Create)
            sz.WriteObject(fs, map)
        End Using
    End Sub
    
    private static void CreateUpdateMaps(ActivityBuilder wf, string name)
    {
        // Create the UpdateMap.
        DynamicUpdateMap map =
            DynamicUpdateServices.CreateUpdateMap(wf);
    
        // Serialize it to a file.
        string path = Path.Combine(mapPath, name);
        DataContractSerializer sz = new DataContractSerializer(typeof(DynamicUpdateMap));
        using (FileStream fs = System.IO.File.Open(path, FileMode.Create))
        {
            sz.WriteObject(fs, map);
        }
    }
    
  13. SaveUpdatedDefinition(또는 Program) 클래스에 다음 Module1 메서드를 추가합니다. 이 메서드는 업데이트 맵이 만들어진 후 업데이트된 워크플로 정의를 저장합니다.

    Private Sub SaveUpdatedDefinition(wf As ActivityBuilder, name As String)
        Dim xamlPath As String = Path.Combine(definitionPath, name)
        Dim sw As StreamWriter = File.CreateText(xamlPath)
        Dim xw As XamlWriter = ActivityXamlServices.CreateBuilderWriter(
            New XamlXmlWriter(sw, New XamlSchemaContext()))
        XamlServices.Save(xw, wf)
        sw.Close()
    End Sub
    
    private static void SaveUpdatedDefinition(ActivityBuilder wf, string name)
    {
        string xamlPath = Path.Combine(definitionPath, name);
        StreamWriter sw = File.CreateText(xamlPath);
        XamlWriter xw = ActivityXamlServices.CreateBuilderWriter(
            new XamlXmlWriter(sw, new XamlSchemaContext()));
        XamlServices.Save(xw, wf);
        sw.Close();
    }
    

StateMachineNumberGuessWorkflow를 업데이트하려면

  1. CreateStateMachineUpdateMap(또는 Program) 클래스에 Module1을 추가합니다.

    Private Sub CreateStateMachineUpdateMap()
    
    End Sub
    
    private static void CreateStateMachineUpdateMap()
    {
    }
    
  2. StartUpdate를 호출하고 워크플로의 루트 StateMachine 활동에 대한 참조를 가져옵니다.

    Dim wf As ActivityBuilder = StartUpdate("StateMachineNumberGuessWorkflow.xaml")
    
    'Get a reference to the root StateMachine activity.
    Dim sm As StateMachine = wf.Implementation
    
    ActivityBuilder wf = StartUpdate("StateMachineNumberGuessWorkflow.xaml");
    
    // Get a reference to the root StateMachine activity.
    StateMachine sm = wf.Implementation as StateMachine;
    
  3. 그런 다음 사용자의 추측 값이 너무 높은지 또는 너무 낮은지를 표시하는 두 WriteLine 작업의 식을 방법: 여러 버전의 워크플로를 함께 호스팅에서 업데이트한 내용과 일치하도록 업데이트합니다.

    'Update the Text of the two WriteLine activities that write the
    'results of the user's guess. They are contained in the workflow as the
    'Then and Else action of the If activity in sm.States[1].Transitions[1].Action.
    Dim guessLow As Statements.If = sm.States(1).Transitions(1).Action
    
    'Update the "too low" message.
    Dim tooLow As WriteLine = guessLow.Then
    tooLow.Text = New VisualBasicValue(Of String)("Guess.ToString() & "" is too low.""")
    
    'Update the "too high" message.
    Dim tooHigh As WriteLine = guessLow.Else
    tooHigh.Text = New VisualBasicValue(Of String)("Guess.ToString() & "" is too high.""")
    
    // Update the Text of the two WriteLine activities that write the
    // results of the user's guess. They are contained in the workflow as the
    // Then and Else action of the If activity in sm.States[1].Transitions[1].Action.
    If guessLow = sm.States[1].Transitions[1].Action as If;
    
    // Update the "too low" message.
    WriteLine tooLow = guessLow.Then as WriteLine;
    tooLow.Text = new CSharpValue<string>("Guess.ToString() + \" is too low.\"");
    
    // Update the "too high" message.
    WriteLine tooHigh = guessLow.Else as WriteLine;
    tooHigh.Text = new CSharpValue<string>("Guess.ToString() + \" is too high.\"");
    
  4. 그런 다음 닫기 메시지를 표시하는 새 WriteLine 활동을 추가합니다.

    'Create the new WriteLine that displays the closing message.
    Dim wl As New WriteLine() With
    {
        .Text = New VisualBasicValue(Of String) _
            ("Guess.ToString() + "" is correct. You guessed it in "" & Turns.ToString() & "" turns.""")
    }
    
    'Add it as the Action for the Guess Correct transition. The Guess Correct
    'transition is the first transition of States[1]. The transitions are listed
    'at the bottom of the State activity designer.
    sm.States(1).Transitions(0).Action = wl
    
    // Create the new WriteLine that displays the closing message.
    WriteLine wl = new WriteLine
    {
        Text = new CSharpValue<string>("Guess.ToString() + \" is correct. You guessed it in \" + Turns.ToString() + \" turns.\"")
    };
    
    // Add it as the Action for the Guess Correct transition. The Guess Correct
    // transition is the first transition of States[1]. The transitions are listed
    // at the bottom of the State activity designer.
    sm.States[1].Transitions[0].Action = wl;
    
  5. 워크플로가 업데이트된 후 CreateUpdateMapsSaveUpdatedDefinition을 호출합니다. CreateUpdateMapsDynamicUpdateMap을 만들고 저장하며, SaveUpdatedDefinition은 업데이트된 워크플로 정의를 저장합니다.

    'Create the update map.
    CreateUpdateMaps(wf, "StateMachineNumberGuessWorkflow.map")
    
    'Save the updated workflow definition.
    SaveUpdatedDefinition(wf, "StateMachineNumberGuessWorkflow_du.xaml")
    
    // Create the update map.
    CreateUpdateMaps(wf, "StateMachineNumberGuessWorkflow.map");
    
    // Save the updated workflow definition.
    SaveUpdatedDefinition(wf, "StateMachineNumberGuessWorkflow_du.xaml");
    

    다음 예제는 전체 CreateStateMachineUpdateMap 메서드입니다.

    Private Sub CreateStateMachineUpdateMap()
        Dim wf As ActivityBuilder = StartUpdate("StateMachineNumberGuessWorkflow.xaml")
    
        'Get a reference to the root StateMachine activity.
        Dim sm As StateMachine = wf.Implementation
    
        'Update the Text of the two WriteLine activities that write the
        'results of the user's guess. They are contained in the workflow as the
        'Then and Else action of the If activity in sm.States[1].Transitions[1].Action.
        Dim guessLow As Statements.If = sm.States(1).Transitions(1).Action
    
        'Update the "too low" message.
        Dim tooLow As WriteLine = guessLow.Then
        tooLow.Text = New VisualBasicValue(Of String)("Guess.ToString() & "" is too low.""")
    
        'Update the "too high" message.
        Dim tooHigh As WriteLine = guessLow.Else
        tooHigh.Text = New VisualBasicValue(Of String)("Guess.ToString() & "" is too high.""")
    
        'Create the new WriteLine that displays the closing message.
        Dim wl As New WriteLine() With
        {
            .Text = New VisualBasicValue(Of String) _
                ("Guess.ToString() + "" is correct. You guessed it in "" & Turns.ToString() & "" turns.""")
        }
    
        'Add it as the Action for the Guess Correct transition. The Guess Correct
        'transition is the first transition of States[1]. The transitions are listed
        'at the bottom of the State activity designer.
        sm.States(1).Transitions(0).Action = wl
    
        'Create the update map.
        CreateUpdateMaps(wf, "StateMachineNumberGuessWorkflow.map")
    
        'Save the updated workflow definition.
        SaveUpdatedDefinition(wf, "StateMachineNumberGuessWorkflow_du.xaml")
    End Sub
    
    private static void CreateStateMachineUpdateMap()
    {
        ActivityBuilder wf = StartUpdate("StateMachineNumberGuessWorkflow.xaml");
    
        // Get a reference to the root StateMachine activity.
        StateMachine sm = wf.Implementation as StateMachine;
    
        // Update the Text of the two WriteLine activities that write the
        // results of the user's guess. They are contained in the workflow as the
        // Then and Else action of the If activity in sm.States[1].Transitions[1].Action.
        If guessLow = sm.States[1].Transitions[1].Action as If;
    
        // Update the "too low" message.
        WriteLine tooLow = guessLow.Then as WriteLine;
        tooLow.Text = new CSharpValue<string>("Guess.ToString() + \" is too low.\"");
    
        // Update the "too high" message.
        WriteLine tooHigh = guessLow.Else as WriteLine;
        tooHigh.Text = new CSharpValue<string>("Guess.ToString() + \" is too high.\"");
    
        // Create the new WriteLine that displays the closing message.
        WriteLine wl = new WriteLine
        {
            Text = new CSharpValue<string>("Guess.ToString() + \" is correct. You guessed it in \" + Turns.ToString() + \" turns.\"")
        };
    
        // Add it as the Action for the Guess Correct transition. The Guess Correct
        // transition is the first transition of States[1]. The transitions are listed
        // at the bottom of the State activity designer.
        sm.States[1].Transitions[0].Action = wl;
    
        // Create the update map.
        CreateUpdateMaps(wf, "StateMachineNumberGuessWorkflow.map");
    
        // Save the updated workflow definition.
        SaveUpdatedDefinition(wf, "StateMachineNumberGuessWorkflow_du.xaml");
    }
    

FlowchartNumberGuessWorkflow를 업데이트하려면

  1. CreateFlowchartUpdateMethod(또는 Program) 클래스에 다음 Module1를 추가합니다. 이 메서드는 CreateStateMachineUpdateMap과 비슷합니다. 이 메서드는 먼저 StartUpdate를 호출하고 순서도 워크플로 정의를 업데이트한 다음 업데이트 맵과 업데이트된 워크플로 정의를 저장하는 것으로 작업을 완료합니다.

    Private Sub CreateFlowchartUpdateMap()
        Dim wf As ActivityBuilder = StartUpdate("FlowchartNumberGuessWorkflow.xaml")
    
        'Get a reference to the root Flowchart activity.
        Dim fc As Flowchart = wf.Implementation
    
        'Update the Text of the two WriteLine activities that write the
        'results of the user's guess. They are contained in the workflow as the
        'True and False action of the "Guess < Target" FlowDecision, which is
        'Nodes[4].
        Dim guessLow As FlowDecision = fc.Nodes(4)
    
        'Update the "too low" message.
        Dim trueStep As FlowStep = guessLow.True
        Dim tooLow As WriteLine = trueStep.Action
        tooLow.Text = New VisualBasicValue(Of String)("Guess.ToString() & "" is too low.""")
    
        'Update the "too high" message.
        Dim falseStep As FlowStep = guessLow.False
        Dim tooHigh As WriteLine = falseStep.Action
        tooHigh.Text = New VisualBasicValue(Of String)("Guess.ToString() & "" is too high.""")
    
        'Create the new WriteLine that displays the closing message.
        Dim wl As New WriteLine() With
        {
            .Text = New VisualBasicValue(Of String) _
                ("Guess.ToString() + "" is correct. You guessed it in "" & Turns.ToString() & "" turns.""")
        }
    
        'Create a FlowStep to hold the WriteLine.
        Dim closingStep As New FlowStep() With
        {
            .Action = wl
        }
    
        'Add this new FlowStep to the True action of the
        '"Guess = Guess" FlowDecision
        Dim guessCorrect As FlowDecision = fc.Nodes(3)
        guessCorrect.True = closingStep
    
        'Add the new FlowStep to the Nodes collection.
        'If closingStep was replacing an existing node then
        'we would need to remove that Step from the collection.
        'In this example there was no existing True step to remove.
        fc.Nodes.Add(closingStep)
    
        'Create the update map.
        CreateUpdateMaps(wf, "FlowchartNumberGuessWorkflow.map")
    
        'Save the updated workflow definition.
        SaveUpdatedDefinition(wf, "FlowchartNumberGuessWorkflow_du.xaml")
    End Sub
    
    private static void CreateFlowchartUpdateMap()
    {
        ActivityBuilder wf = StartUpdate("FlowchartNumberGuessWorkflow.xaml");
    
        // Get a reference to the root Flowchart activity.
        Flowchart fc = wf.Implementation as Flowchart;
    
        // Update the Text of the two WriteLine activities that write the
        // results of the user's guess. They are contained in the workflow as the
        // True and False action of the "Guess < Target" FlowDecision, which is
        // Nodes[4].
        FlowDecision guessLow = fc.Nodes[4] as FlowDecision;
    
        // Update the "too low" message.
        FlowStep trueStep = guessLow.True as FlowStep;
        WriteLine tooLow = trueStep.Action as WriteLine;
        tooLow.Text = new CSharpValue<string>("Guess.ToString() + \" is too low.\"");
    
        // Update the "too high" message.
        FlowStep falseStep = guessLow.False as FlowStep;
        WriteLine tooHigh = falseStep.Action as WriteLine;
        tooHigh.Text = new CSharpValue<string>("Guess.ToString() + \" is too high.\"");
    
        // Add the new WriteLine that displays the closing message.
        WriteLine wl = new WriteLine
        {
            Text = new CSharpValue<string>("Guess.ToString() + \" is correct. You guessed it in \" + Turns.ToString() + \" turns.\"")
        };
    
        // Create a FlowStep to hold the WriteLine.
        FlowStep closingStep = new FlowStep
        {
            Action = wl
        };
    
        // Add this new FlowStep to the True action of the
        // "Guess == Guess" FlowDecision
        FlowDecision guessCorrect = fc.Nodes[3] as FlowDecision;
        guessCorrect.True = closingStep;
    
        // Add the new FlowStep to the Nodes collection.
        // If closingStep was replacing an existing node then
        // we would need to remove that Step from the collection.
        // In this example there was no existing True step to remove.
        fc.Nodes.Add(closingStep);
    
        // Create the update map.
        CreateUpdateMaps(wf, "FlowchartNumberGuessWorkflow.map");
    
        //  Save the updated workflow definition.
        SaveUpdatedDefinition(wf, "FlowchartNumberGuessWorkflow_du.xaml");
    }
    

SequentialNumberGuessWorkflow를 업데이트하려면

  1. CreateSequentialUpdateMethod(또는 Program) 클래스에 다음 Module1를 추가합니다. 이 메서드는 다른 두 개의 메서드와 비슷합니다. 이 메서드는 먼저 StartUpdate를 호출하고 순차 워크플로 정의를 업데이트한 다음 업데이트 맵과 업데이트된 워크플로 정의를 저장하는 것으로 작업을 완료합니다.

    Private Sub CreateSequentialUpdateMap()
        Dim wf As ActivityBuilder = StartUpdate("SequentialNumberGuessWorkflow.xaml")
    
        'Get a reference to the root activity in the workflow.
        Dim rootSequence As Sequence = wf.Implementation
    
        'Update the Text of the two WriteLine activities that write the
        'results of the user's guess. They are contained in the workflow as the
        'Then and Else action of the "Guess < Target" If activity.
        'Sequence[1]->DoWhile->Body->Sequence[2]->If->Then->If
        Dim gameLoop As Statements.DoWhile = rootSequence.Activities(1)
        Dim gameBody As Sequence = gameLoop.Body
        Dim guessCorrect As Statements.If = gameBody.Activities(2)
        Dim guessLow As Statements.If = guessCorrect.Then
        Dim tooLow As WriteLine = guessLow.Then
        tooLow.Text = New VisualBasicValue(Of String)("Guess.ToString() & "" is too low.""")
        Dim tooHigh As WriteLine = guessLow.Else
        tooHigh.Text = New VisualBasicValue(Of String)("Guess.ToString() & "" is too high.""")
    
        'Create the new WriteLine that displays the closing message.
        Dim wl As New WriteLine() With
        {
            .Text = New VisualBasicValue(Of String) _
                ("Guess.ToString() + "" is correct. You guessed it in "" & Turns.ToString() & "" turns.""")
        }
    
        'Insert it as the third activity in the root sequence
        rootSequence.Activities.Insert(2, wl)
    
        'Create the update map.
        CreateUpdateMaps(wf, "SequentialNumberGuessWorkflow.map")
    
        'Save the updated workflow definition.
        SaveUpdatedDefinition(wf, "SequentialNumberGuessWorkflow_du.xaml")
    End Sub
    
    private static void CreateSequentialUpdateMap()
    {
        ActivityBuilder wf = StartUpdate("SequentialNumberGuessWorkflow.xaml");
    
        // Get a reference to the root activity in the workflow.
        Sequence rootSequence = wf.Implementation as Sequence;
    
        // Update the Text of the two WriteLine activities that write the
        // results of the user's guess. They are contained in the workflow as the
        // Then and Else action of the "Guess < Target" If activity.
        // Sequence[1]->DoWhile->Body->Sequence[2]->If->Then->If
        DoWhile gameLoop = rootSequence.Activities[1] as DoWhile;
        Sequence gameBody = gameLoop.Body as Sequence;
        If guessCorrect = gameBody.Activities[2] as If;
        If guessLow = guessCorrect.Then as If;
        WriteLine tooLow = guessLow.Then as WriteLine;
        tooLow.Text = new CSharpValue<string>("Guess.ToString() + \" is too low.\"");
        WriteLine tooHigh = guessLow.Else as WriteLine;
        tooHigh.Text = new CSharpValue<string>("Guess.ToString() + \" is too high.\"");
    
        // Add the new WriteLine that displays the closing message.
        WriteLine wl = new WriteLine
        {
            Text = new CSharpValue<string>("Guess.ToString() + \" is correct. You guessed it in \" + Turns.ToString() + \" turns.\"")
        };
    
        // Insert it as the third activity in the root sequence
        rootSequence.Activities.Insert(2, wl);
    
        // Create the update map.
        CreateUpdateMaps(wf, "SequentialNumberGuessWorkflow.map");
    
        // Save the updated workflow definition.
        SaveUpdatedDefinition(wf, "SequentialNumberGuessWorkflow_du.xaml");
    }
    

CreateUpdateMaps 애플리케이션을 빌드하고 실행하려면

  1. Main 메서드를 업데이트하고 다음 세 개의 메서드 호출을 추가합니다. 이러한 메서드는 다음 단원에서 추가됩니다. 각 메서드는 해당 숫자 추측 워크플로를 업데이트하고 업데이트를 설명하는 DynamicUpdateMap을 만듭니다.

    Sub Main()
        'Create the update maps for the changes needed to the v1 activities
        'so they match the v2 activities.
        CreateSequentialUpdateMap()
        CreateFlowchartUpdateMap()
        CreateStateMachineUpdateMap()
    End Sub
    
    static void Main(string[] args)
    {
        // Create the update maps for the changes needed to the v1 activities
        // so they match the v2 activities.
        CreateSequentialUpdateMap();
        CreateFlowchartUpdateMap();
        CreateStateMachineUpdateMap();
    }
    
  2. 솔루션 탐색기에서 CreateUpdateMaps를 마우스 오른쪽 단추로 클릭하고 시작 프로젝트로 설정을 선택합니다.

  3. Ctrl+Shift+B를 눌러 솔루션을 빌드하고 Ctrl+F5를 눌러 CreateUpdateMaps 애플리케이션을 실행합니다.

    참고 항목

    CreateUpdateMaps 애플리케이션에서는 실행 중인 동안 어떠한 상태 정보도 표시하지 않지만 NumberGuessWorkflowActivities_du 폴더와 PreviousVersions 폴더를 확인하면 업데이트된 워크플로 정의 파일과 업데이트 맵을 볼 수 있습니다.

    업데이트 맵이 만들어지고 워크플로 정의가 업데이트된 후 다음 단계는 업데이트된 정의를 포함하는 업데이트된 워크플로 어셈블리를 빌드하는 것입니다.

업데이트된 워크플로 어셈블리를 빌드하려면

  1. Visual Studio 2012의 두 번째 인스턴스를 엽니다.

  2. 파일 메뉴에서 열기, 프로젝트/솔루션을 차례로 선택합니다.

  3. 방법: 여러 버전의 워크플로를 함께 호스팅에서 만든 NumberGuessWorkflowActivities_du 폴더로 이동하고, NumberGuessWorkflowActivities.csproj(또는 vbproj)를 선택한 다음, 열기를 클릭합니다.

  4. 솔루션 탐색기에서 SequentialNumberGuessWorkflow.xaml을 마우스 오른쪽 단추로 클릭하고 프로젝트에서 제외를 선택합니다. FlowchartNumberGuessWorkflow.xamlStateMachineNumberGuessWorkflow.xaml에 대해 동일한 작업을 수행합니다. 이 단계에서는 프로젝트에서 이전 버전의 워크플로 정의를 제거합니다.

  5. 프로젝트 메뉴에서 기존 항목 추가를 선택합니다.

  6. 방법: 여러 버전의 워크플로를 함께 호스팅에서 만든 NumberGuessWorkflowActivities_du 폴더로 이동합니다.

  7. 파일 형식 드롭다운 목록에서 XAML 파일(*.xaml;*.xoml)을 선택합니다.

  8. SequentialNumberGuessWorkflow_du.xaml, FlowchartNumberGuessWorkflow_du.xaml, StateMachineNumberGuessWorkflow_du.xaml을 선택하고 추가를 클릭합니다.

    참고 항목

    한 번에 여러 개의 항목을 선택하려면 Ctrl 키를 누른 상태로 클릭하세요.

    이 단계에서는 프로젝트에 업데이트된 버전의 워크플로 정의를 추가합니다.

  9. Ctrl+Shift+B를 눌러 프로젝트를 빌드합니다.

  10. 파일 메뉴에서 솔루션 닫기를 선택합니다. 프로젝트의 솔루션 파일은 필요하지 않으므로 아니요를 클릭하여 솔루션 파일을 저장하지 않고 Visual Studio를 닫습니다. 파일 메뉴에서 끝내기를 선택하여 Visual Studio를 닫습니다.

  11. Windows 탐색기를 열고 NumberGuessWorkflowActivities_du\bin\Debug 폴더(또는 프로젝트 설정에 따라 bin\Release)로 이동합니다.

  12. NumberGuessWorkflowActivities.dll의 이름을 NumberGuessWorkflowActivities_v15.dll로 바꾸고 방법: 방법: 여러 버전의 워크플로를 함께 호스팅에서 만든 PreviousVersions 폴더에 복사합니다.

WorkflowVersionMap을 새 버전으로 업데이트하려면

  1. 다시 Visual Studio 2012의 초기 인스턴스로 전환합니다.

  2. NumberGuessWorkflowHost 프로젝트 아래의 WorkflowVersionMap.cs(또는 WorkflowVersionMap.vb)를 두 번 클릭하여 엽니다.

  3. 여섯 개의 기존 워크플로 ID 선언 바로 아래에 세 개의 새 워크플로 ID를 추가합니다. 이 자습서에서는 1.5.0.0이 동적 업데이트 ID의 WorkflowIdentity.Version으로 사용됩니다. 이러한 새 v15 워크플로 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
    
    'v1.5 (Dynamic Update) identities.
    Public StateMachineNumberGuessIdentity_v15 As WorkflowIdentity
    Public FlowchartNumberGuessIdentity_v15 As WorkflowIdentity
    Public SequentialNumberGuessIdentity_v15 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;
    
    // v1.5 (Dynamic Update) identities.
    static public WorkflowIdentity StateMachineNumberGuessIdentity_v15;
    static public WorkflowIdentity FlowchartNumberGuessIdentity_v15;
    static public WorkflowIdentity SequentialNumberGuessIdentity_v15;
    
  4. 생성자의 끝에 다음 코드를 추가합니다. 이 코드는 동적 업데이트 워크플로 ID를 초기화하고 해당 워크플로 정의를 로드한 후 워크플로 버전 사전에 추가합니다.

    'Initialize the dynamic update workflow identities.
    StateMachineNumberGuessIdentity_v15 = New WorkflowIdentity With
    {
        .Name = "StateMachineNumberGuessWorkflow",
        .Version = New Version(1, 5, 0, 0)
    }
    
    FlowchartNumberGuessIdentity_v15 = New WorkflowIdentity With
    {
        .Name = "FlowchartNumberGuessWorkflow",
        .Version = New Version(1, 5, 0, 0)
    }
    
    SequentialNumberGuessIdentity_v15 = New WorkflowIdentity With
    {
        .Name = "SequentialNumberGuessWorkflow",
        .Version = New Version(1, 5, 0, 0)
    }
    
    'Add the dynamic update workflow identities to the dictionary along with
    'the corresponding workflow definitions loaded from the v15 assembly.
    'Assembly.LoadFile requires an absolute path so convert this relative path
    'to an absolute path.
    Dim v15AssemblyPath As String = "..\..\..\PreviousVersions\NumberGuessWorkflowActivities_v15.dll"
    v15AssemblyPath = Path.GetFullPath(v15AssemblyPath)
    Dim v15Assembly As Assembly = Assembly.LoadFile(v15AssemblyPath)
    
    map.Add(StateMachineNumberGuessIdentity_v15,
        v15Assembly.CreateInstance("NumberGuessWorkflowActivities.StateMachineNumberGuessWorkflow"))
    
    map.Add(SequentialNumberGuessIdentity_v15,
        v15Assembly.CreateInstance("NumberGuessWorkflowActivities.SequentialNumberGuessWorkflow"))
    
    map.Add(FlowchartNumberGuessIdentity_v15,
        v15Assembly.CreateInstance("NumberGuessWorkflowActivities.FlowchartNumberGuessWorkflow"))
    
    // Initialize the dynamic update workflow identities.
    StateMachineNumberGuessIdentity_v15 = new WorkflowIdentity
    {
        Name = "StateMachineNumberGuessWorkflow",
        Version = new Version(1, 5, 0, 0)
    };
    
    FlowchartNumberGuessIdentity_v15 = new WorkflowIdentity
    {
        Name = "FlowchartNumberGuessWorkflow",
        Version = new Version(1, 5, 0, 0)
    };
    
    SequentialNumberGuessIdentity_v15 = new WorkflowIdentity
    {
        Name = "SequentialNumberGuessWorkflow",
        Version = new Version(1, 5, 0, 0)
    };
    
    // Add the dynamic update workflow identities to the dictionary along with
    // the corresponding workflow definitions loaded from the v15 assembly.
    // Assembly.LoadFile requires an absolute path so convert this relative path
    // to an absolute path.
    string v15AssemblyPath = @"..\..\..\PreviousVersions\NumberGuessWorkflowActivities_v15.dll";
    v15AssemblyPath = Path.GetFullPath(v15AssemblyPath);
    Assembly v15Assembly = Assembly.LoadFile(v15AssemblyPath);
    
    map.Add(StateMachineNumberGuessIdentity_v15,
        v15Assembly.CreateInstance("NumberGuessWorkflowActivities.StateMachineNumberGuessWorkflow") as Activity);
    
    map.Add(SequentialNumberGuessIdentity_v15,
        v15Assembly.CreateInstance("NumberGuessWorkflowActivities.SequentialNumberGuessWorkflow") as Activity);
    
    map.Add(FlowchartNumberGuessIdentity_v15,
        v15Assembly.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
    
        'v1.5 (Dynamic Update) identities.
        Public StateMachineNumberGuessIdentity_v15 As WorkflowIdentity
        Public FlowchartNumberGuessIdentity_v15 As WorkflowIdentity
        Public SequentialNumberGuessIdentity_v15 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"))
    
            'Initialize the dynamic update workflow identities.
            StateMachineNumberGuessIdentity_v15 = New WorkflowIdentity With
            {
                .Name = "StateMachineNumberGuessWorkflow",
                .Version = New Version(1, 5, 0, 0)
            }
    
            FlowchartNumberGuessIdentity_v15 = New WorkflowIdentity With
            {
                .Name = "FlowchartNumberGuessWorkflow",
                .Version = New Version(1, 5, 0, 0)
            }
    
            SequentialNumberGuessIdentity_v15 = New WorkflowIdentity With
            {
                .Name = "SequentialNumberGuessWorkflow",
                .Version = New Version(1, 5, 0, 0)
            }
    
            'Add the dynamic update workflow identities to the dictionary along with
            'the corresponding workflow definitions loaded from the v15 assembly.
            'Assembly.LoadFile requires an absolute path so convert this relative path
            'to an absolute path.
            Dim v15AssemblyPath As String = "..\..\..\PreviousVersions\NumberGuessWorkflowActivities_v15.dll"
            v15AssemblyPath = Path.GetFullPath(v15AssemblyPath)
            Dim v15Assembly As Assembly = Assembly.LoadFile(v15AssemblyPath)
    
            map.Add(StateMachineNumberGuessIdentity_v15,
                v15Assembly.CreateInstance("NumberGuessWorkflowActivities.StateMachineNumberGuessWorkflow"))
    
            map.Add(SequentialNumberGuessIdentity_v15,
                v15Assembly.CreateInstance("NumberGuessWorkflowActivities.SequentialNumberGuessWorkflow"))
    
            map.Add(FlowchartNumberGuessIdentity_v15,
                v15Assembly.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;
    
        // v1.5 (Dynamic Update) identities.
        static public WorkflowIdentity StateMachineNumberGuessIdentity_v15;
        static public WorkflowIdentity FlowchartNumberGuessIdentity_v15;
        static public WorkflowIdentity SequentialNumberGuessIdentity_v15;
    
        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);
    
            // Initialize the dynamic update workflow identities.
            StateMachineNumberGuessIdentity_v15 = new WorkflowIdentity
            {
                Name = "StateMachineNumberGuessWorkflow",
                Version = new Version(1, 5, 0, 0)
            };
    
            FlowchartNumberGuessIdentity_v15 = new WorkflowIdentity
            {
                Name = "FlowchartNumberGuessWorkflow",
                Version = new Version(1, 5, 0, 0)
            };
    
            SequentialNumberGuessIdentity_v15 = new WorkflowIdentity
            {
                Name = "SequentialNumberGuessWorkflow",
                Version = new Version(1, 5, 0, 0)
            };
    
            // Add the dynamic update workflow identities to the dictionary along with
            // the corresponding workflow definitions loaded from the v15 assembly.
            // Assembly.LoadFile requires an absolute path so convert this relative path
            // to an absolute path.
            string v15AssemblyPath = @"..\..\..\PreviousVersions\NumberGuessWorkflowActivities_v15.dll";
            v15AssemblyPath = Path.GetFullPath(v15AssemblyPath);
            Assembly v15Assembly = Assembly.LoadFile(v15AssemblyPath);
    
            map.Add(StateMachineNumberGuessIdentity_v15,
                v15Assembly.CreateInstance("NumberGuessWorkflowActivities.StateMachineNumberGuessWorkflow") as Activity);
    
            map.Add(SequentialNumberGuessIdentity_v15,
                v15Assembly.CreateInstance("NumberGuessWorkflowActivities.SequentialNumberGuessWorkflow") as Activity);
    
            map.Add(FlowchartNumberGuessIdentity_v15,
                v15Assembly.CreateInstance("NumberGuessWorkflowActivities.FlowchartNumberGuessWorkflow") as Activity);
        }
    
        public static Activity GetWorkflowDefinition(WorkflowIdentity identity)
        {
            return map[identity];
        }
    
        public static string GetIdentityDescription(WorkflowIdentity identity)
        {
            return identity.ToString();
        }
    }
    
  5. Ctrl+Shift+B를 눌러 프로젝트를 빌드합니다.

동적 업데이트를 적용하려면

  1. 솔루션 탐색기에서 WF45GettingStartedTutorial을 마우스 오른쪽 단추로 클릭하고 추가, 새 프로젝트를 차례로 선택합니다.

  2. 설치됨 노드에서 Visual C#, Windows(또는 Visual Basic, Windows)를 차례로 선택합니다.

    참고 항목

    설치됨 노드의 다른 언어 노드 아래에는 Visual Studio에서 기본 언어로 구성된 프로그래밍 언어에 따라 Visual C# 또는 Visual Basic 노드가 표시될 수 있습니다.

    .NET Framework 버전 드롭다운 목록에서 .NET Framework 4.5 가 선택되어 있는지 확인합니다. Windows 목록에서 콘솔 애플리케이션을 선택합니다. 이름 상자에 ApplyDynamicUpdate를 입력하고 확인을 클릭합니다.

  3. 솔루션 탐색기에서 ApplyDynamicUpdate를 마우스 오른쪽 단추로 클릭하고 참조 추가를 선택합니다.

  4. 솔루션을 클릭하고 NumberGuessWorkflowHost 옆에 있는 상자를 선택합니다. 이 참조는 ApplyDynamicUpdate에서 NumberGuessWorkflowHost.WorkflowVersionMap 클래스를 사용하는 데 필요합니다.

  5. 참조 추가 목록의 어셈블리 노드에서 프레임워크를 선택합니다. 어셈블리 검색 상자에 System.Activities를 입력합니다. 그러면 어셈블리가 필터링되므로 원하는 참조를 손쉽게 선택할 수 있습니다.

  6. 검색 결과 목록에서 System.Activities 옆의 확인란을 선택합니다.

  7. 어셈블리 검색 상자에 Serialization을 입력하고 검색 결과 목록에서 System.Runtime.Serialization 옆의 확인란을 선택합니다.

  8. 어셈블리 검색 상자에 DurableInstancing을 입력하고 검색 결과 목록에서 System.Activities.DurableInstancingSystem.Runtime.DurableInstancing 옆의 확인란을 선택합니다.

  9. 확인을 클릭하여 참조 관리자를 닫고 참조를 추가합니다.

  10. 솔루션 탐색기에서 ApplyDynamicUpdate를 마우스 오른쪽 단추로 클릭하고 추가, 클래스를 차례로 선택합니다. 이름 상자에 DynamicUpdateInfo를 입력하고 추가를 클릭합니다.

  11. DynamicUpdateInfo 클래스에 다음 두 개의 멤버를 추가합니다. 다음 예제는 전체 DynamicUpdateInfo 클래스입니다. 이 클래스에는 워크플로 인스턴스가 업데이트될 때 사용되는 업데이트 맵 및 새 워크플로 ID에 대한 정보가 포함되어 있습니다.

    Public Class DynamicUpdateInfo
        Public updateMap As DynamicUpdateMap
        Public newIdentity As WorkflowIdentity
    End Class
    
    class DynamicUpdateInfo
    {
        public DynamicUpdateMap updateMap;
        public WorkflowIdentity newIdentity;
    }
    
  12. 다음 using(또는 Imports) 문을 파일의 맨 위에 다른 using(또는 Imports) 문과 함께 추가합니다.

    Imports System.Activities
    Imports System.Activities.DynamicUpdate
    
    using System.Activities;
    using System.Activities.DynamicUpdate;
    
  13. 솔루션 탐색기에서 Program.cs(또는 Module1.vb)를 두 번 클릭합니다.

  14. 다음 using(또는 Imports) 문을 파일의 맨 위에 다른 using(또는 Imports) 문과 함께 추가합니다.

    Imports NumberGuessWorkflowHost
    Imports System.Data.SqlClient
    Imports System.Activities.DynamicUpdate
    Imports System.IO
    Imports System.Runtime.Serialization
    Imports System.Activities
    Imports System.Activities.DurableInstancing
    
    using NumberGuessWorkflowHost;
    using System.Data;
    using System.Data.SqlClient;
    using System.Activities;
    using System.Activities.DynamicUpdate;
    using System.IO;
    using System.Runtime.Serialization;
    using System.Activities.DurableInstancing;
    
  15. Program(또는 Module1) 클래스에 다음 연결 문자열 멤버를 추가합니다.

    Const connectionString = "Server=.\SQLEXPRESS;Initial Catalog=WF45GettingStartedTutorial;Integrated Security=SSPI"
    
    const string connectionString = "Server=.\\SQLEXPRESS;Initial Catalog=WF45GettingStartedTutorial;Integrated Security=SSPI";
    

    참고 항목

    SQL Server 에디션에 따라 연결 문자열 서버 이름이 다를 수 있습니다.

  16. GetIDs(또는 Program) 클래스에 다음 Module1 메서드를 추가합니다. 이 메서드는 지속형 워크플로 인스턴스 ID의 목록을 반환합니다.

    Function GetIds() As IList(Of Guid)
        Dim Ids As New List(Of Guid)
        Dim localCmd = _
            String.Format("Select [InstanceId] from [System.Activities.DurableInstancing].[Instances] Order By [CreationTime]")
        Using localCon = New SqlConnection(connectionString)
            Dim cmd As SqlCommand = localCon.CreateCommand()
            cmd.CommandText = localCmd
            localCon.Open()
            Using reader = cmd.ExecuteReader(CommandBehavior.CloseConnection)
                While reader.Read()
                    'Get the InstanceId of the persisted Workflow
                    Dim id As Guid = Guid.Parse(reader(0).ToString())
    
                    'Add it to the list.
                    Ids.Add(id)
                End While
            End Using
        End Using
    
        Return Ids
    End Function
    
    static IList<Guid> GetIds()
    {
        List<Guid> Ids = new List<Guid>();
        string localCmd = string.Format("Select [InstanceId] from [System.Activities.DurableInstancing].[Instances] Order By [CreationTime]");
        using (SqlConnection localCon = new SqlConnection(connectionString))
        {
            SqlCommand cmd = localCon.CreateCommand();
            cmd.CommandText = localCmd;
            localCon.Open();
            using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
            {
                while (reader.Read())
                {
                    // Get the InstanceId of the persisted Workflow
                    Guid id = Guid.Parse(reader[0].ToString());
    
                    // Add it to the list.
                    Ids.Add(id);
                }
            }
        }
    
        return Ids;
    }
    
  17. LoadMap(또는 Program) 클래스에 다음 Module1 메서드를 추가합니다. 이 메서드는 v1 워크플로 ID를 해당 지속형 워크플로 인스턴스를 업데이트하는 데 사용되는 업데이트 맵과 새 워크플로 ID에 매핑하는 사전을 만듭니다.

    Function LoadMap(mapName As String) As DynamicUpdateMap
        Dim mapPath As String = Path.Combine("..\..\..\PreviousVersions", mapName)
    
        Dim map As DynamicUpdateMap
        Using fs As FileStream = File.Open(mapPath, FileMode.Open)
            Dim serializer As DataContractSerializer = New DataContractSerializer(GetType(DynamicUpdateMap))
            Dim updateMap = serializer.ReadObject(fs)
            If updateMap Is Nothing Then
                Throw New ApplicationException("DynamicUpdateMap is null.")
            End If
    
            map = updateMap
        End Using
    
        Return map
    End Function
    
    static DynamicUpdateMap LoadMap(string mapName)
    {
        string path = Path.Combine(@"..\..\..\PreviousVersions", mapName);
    
        DynamicUpdateMap map;
        using (FileStream fs = File.Open(path, FileMode.Open))
        {
            DataContractSerializer serializer = new DataContractSerializer(typeof(DynamicUpdateMap));
            object updateMap = serializer.ReadObject(fs);
            if (updateMap == null)
            {
                throw new ApplicationException("DynamicUpdateMap is null.");
            }
    
            map = updateMap as DynamicUpdateMap;
        }
    
        return map;
    }
    
  18. LoadMaps(또는 Program) 클래스에 다음 Module1 메서드를 추가합니다. 이 메서드는 세 개의 업데이트 맵을 로드하고 v1 워크플로 ID를 업데이트 맵에 매핑하는 사전을 만듭니다.

    Function LoadMaps() As IDictionary(Of WorkflowIdentity, DynamicUpdateInfo)
        'There are 3 update maps to describe the changes to update v1 workflows,
        'one for reach of the 3 workflow types in the tutorial.
        Dim maps = New Dictionary(Of WorkflowIdentity, DynamicUpdateInfo)()
    
        Dim sequentialMap As DynamicUpdateMap = LoadMap("SequentialNumberGuessWorkflow.map")
        Dim sequentialInfo = New DynamicUpdateInfo With
        {
            .updateMap = sequentialMap,
            .newIdentity = WorkflowVersionMap.SequentialNumberGuessIdentity_v15
        }
        maps.Add(WorkflowVersionMap.SequentialNumberGuessIdentity_v1, sequentialInfo)
    
        Dim stateMap As DynamicUpdateMap = LoadMap("StateMachineNumberGuessWorkflow.map")
        Dim stateInfo = New DynamicUpdateInfo With
        {
            .updateMap = stateMap,
            .newIdentity = WorkflowVersionMap.StateMachineNumberGuessIdentity_v15
        }
        maps.Add(WorkflowVersionMap.StateMachineNumberGuessIdentity_v1, stateInfo)
    
        Dim flowchartMap As DynamicUpdateMap = LoadMap("FlowchartNumberGuessWorkflow.map")
        Dim flowchartInfo = New DynamicUpdateInfo With
        {
            .updateMap = flowchartMap,
            .newIdentity = WorkflowVersionMap.FlowchartNumberGuessIdentity_v15
        }
        maps.Add(WorkflowVersionMap.FlowchartNumberGuessIdentity_v1, flowchartInfo)
    
        Return maps
    End Function
    
    static IDictionary<WorkflowIdentity, DynamicUpdateInfo> LoadMaps()
    {
        // There are 3 update maps to describe the changes to update v1 workflows,
        // one for reach of the 3 workflow types in the tutorial.
        Dictionary<WorkflowIdentity, DynamicUpdateInfo> maps =
            new Dictionary<WorkflowIdentity, DynamicUpdateInfo>();
    
        DynamicUpdateMap sequentialMap = LoadMap("SequentialNumberGuessWorkflow.map");
        DynamicUpdateInfo sequentialInfo = new DynamicUpdateInfo
        {
            updateMap = sequentialMap,
            newIdentity = WorkflowVersionMap.SequentialNumberGuessIdentity_v15
        };
        maps.Add(WorkflowVersionMap.SequentialNumberGuessIdentity_v1, sequentialInfo);
    
        DynamicUpdateMap stateMap = LoadMap("StateMachineNumberGuessWorkflow.map");
        DynamicUpdateInfo stateInfo = new DynamicUpdateInfo
        {
            updateMap = stateMap,
            newIdentity = WorkflowVersionMap.StateMachineNumberGuessIdentity_v15
        };
        maps.Add(WorkflowVersionMap.StateMachineNumberGuessIdentity_v1, stateInfo);
    
        DynamicUpdateMap flowchartMap = LoadMap("FlowchartNumberGuessWorkflow.map");
        DynamicUpdateInfo flowchartInfo = new DynamicUpdateInfo
        {
            updateMap = flowchartMap,
            newIdentity = WorkflowVersionMap.FlowchartNumberGuessIdentity_v15
        };
        maps.Add(WorkflowVersionMap.FlowchartNumberGuessIdentity_v1, flowchartInfo);
    
        return maps;
    }
    
  19. 다음 코드를 Main에 추가합니다. 이 코드는 지속형 워크플로 인스턴스를 반복하고 각 WorkflowIdentity를 검사합니다. WorkflowIdentityv1 워크플로 인스턴스에 매핑되면 업데이트된 워크플로 정의와 업데이트된 워크플로 ID로 WorkflowApplication이 구성됩니다. 그런 다음 해당 인스턴스와 업데이트 맵을 사용하여 WorkflowApplication.Load가 호출되고 동적 업데이트 맵이 적용됩니다. 업데이트가 적용된 후 업데이트된 인스턴스는 Unload에 대한 호출을 통해 지속됩니다.

    Dim store = New SqlWorkflowInstanceStore(connectionString)
    WorkflowApplication.CreateDefaultInstanceOwner(store, Nothing, WorkflowIdentityFilter.Any)
    
    Dim updateMaps As IDictionary(Of WorkflowIdentity, DynamicUpdateInfo) = LoadMaps()
    
    For Each id As Guid In GetIds()
        'Get a proxy to the instance.
        Dim instance As WorkflowApplicationInstance = WorkflowApplication.GetInstance(id, store)
    
        Console.WriteLine("Inspecting: {0}", instance.DefinitionIdentity)
    
        'Only update v1 workflows.
        If Not instance.DefinitionIdentity Is Nothing AndAlso _
            instance.DefinitionIdentity.Version.Equals(New Version(1, 0, 0, 0)) Then
    
            Dim info As DynamicUpdateInfo = updateMaps(instance.DefinitionIdentity)
    
            'Associate the persisted WorkflowApplicationInstance with
            'a WorkflowApplication that is configured with the updated
            'definition and updated WorkflowIdentity.
            Dim wf As Activity = WorkflowVersionMap.GetWorkflowDefinition(info.newIdentity)
            Dim wfApp = New WorkflowApplication(wf, info.newIdentity)
    
            'Apply the Dynamic Update.
            wfApp.Load(instance, info.updateMap)
    
            'Persist the updated instance.
            wfApp.Unload()
    
            Console.WriteLine("Updated to: {0}", info.newIdentity)
        Else
            'Not updating this instance, so unload it.
            instance.Abandon()
        End If
    Next
    
    SqlWorkflowInstanceStore store = new SqlWorkflowInstanceStore(connectionString);
    WorkflowApplication.CreateDefaultInstanceOwner(store, null, WorkflowIdentityFilter.Any);
    
    IDictionary<WorkflowIdentity, DynamicUpdateInfo> updateMaps = LoadMaps();
    
    foreach (Guid id in GetIds())
    {
        // Get a proxy to the instance.
        WorkflowApplicationInstance instance =
            WorkflowApplication.GetInstance(id, store);
    
        Console.WriteLine("Inspecting: {0}", instance.DefinitionIdentity);
    
        // Only update v1 workflows.
        if (instance.DefinitionIdentity != null &&
            instance.DefinitionIdentity.Version.Equals(new Version(1, 0, 0, 0)))
        {
            DynamicUpdateInfo info = updateMaps[instance.DefinitionIdentity];
    
            // Associate the persisted WorkflowApplicationInstance with
            // a WorkflowApplication that is configured with the updated
            // definition and updated WorkflowIdentity.
            Activity wf = WorkflowVersionMap.GetWorkflowDefinition(info.newIdentity);
            WorkflowApplication wfApp =
                new WorkflowApplication(wf, info.newIdentity);
    
            // Apply the Dynamic Update.
            wfApp.Load(instance, info.updateMap);
    
            // Persist the updated instance.
            wfApp.Unload();
    
            Console.WriteLine("Updated to: {0}", info.newIdentity);
        }
        else
        {
            // Not updating this instance, so unload it.
            instance.Abandon();
        }
    }
    
  20. 솔루션 탐색기에서 ApplyDynamicUpdate를 마우스 오른쪽 단추로 클릭하고 시작 프로젝트로 설정을 선택합니다.

  21. Ctrl+Shift+B를 눌러 솔루션을 빌드하고 Ctrl+F5를 눌러 ApplyDynamicUpdate 애플리케이션을 실행한 다음 지속형 워크플로 인스턴스를 업데이트합니다. 다음과 비슷한 결과가 표시됩니다. 버전 1.0.0.0 워크플로는 버전 1.5.0.0으로 업데이트되는 반면에 버전 2.0.0.0 워크플로는 업데이트되지 않습니다.

    검사: StateMachineNumberGuessWorkflow; Version=1.0.0.0
    다음으로 업데이트됨: StateMachineNumberGuessWorkflow; Version=1.5.0.0
    검사: StateMachineNumberGuessWorkflow; Version=1.0.0.0
    다음으로 업데이트됨: StateMachineNumberGuessWorkflow; Version=1.5.0.0
    검사: FlowchartNumberGuessWorkflow; Version=1.0.0.0
    다음으로 업데이트됨: FlowchartNumberGuessWorkflow; Version=1.5.0.0
    검사: FlowchartNumberGuessWorkflow; Version=1.0.0.0
    다음으로 업데이트됨: FlowchartNumberGuessWorkflow; Version=1.5.0.0
    검사: SequentialNumberGuessWorkflow; Version=1.0.0.0
    다음으로 업데이트됨: SequentialNumberGuessWorkflow; Version=1.5.0.0
    검사: SequentialNumberGuessWorkflow; Version=1.0.0.0
    다음으로 업데이트됨: SequentialNumberGuessWorkflow; Version=1.5.0.0
    검사: SequentialNumberGuessWorkflow; Version=1.0.0.0
    다음으로 업데이트됨: SequentialNumberGuessWorkflow; Version=1.5.0.0
    검사: StateMachineNumberGuessWorkflow; Version=1.0.0.0
    다음으로 업데이트됨: StateMachineNumberGuessWorkflow; Version=1.5.0.0
    검사: FlowchartNumberGuessWorkflow; Version=1.0.0.0
    다음으로 업데이트됨: FlowchartNumberGuessWorkflow; Version=1.5.0.0
    검사: StateMachineNumberGuessWorkflow; Version=2.0.0.0
    검사: StateMachineNumberGuessWorkflow; Version=2.0.0.0
    검사: FlowchartNumberGuessWorkflow; Version=2.0.0.0
    검사: FlowchartNumberGuessWorkflow; Version=2.0.0.0
    검사: SequentialNumberGuessWorkflow; Version=2.0.0.0
    검사: SequentialNumberGuessWorkflow; Version=2.0.0.0
    계속하려면 아무 키나 누르세요. . .

업데이트된 워크플로를 사용하여 애플리케이션을 실행하려면

  1. 솔루션 탐색기에서 NumberGuessWorkflowHost를 마우스 오른쪽 단추로 클릭하고 시작 프로젝트로 설정을 선택합니다.

  2. Ctrl+F5를 눌러 애플리케이션을 실행합니다.

  3. New Game을 클릭하여 새 워크플로를 시작하고 상태 창 아래에서 해당 워크플로가 v2 워크플로임을 나타내는 버전 정보를 확인합니다.

  4. 방법: 여러 버전의 워크플로를 함께 호스팅 항목의 시작 부분에서 시작한 v1 워크플로 중 하나를 선택합니다. 상태 창 아래에서 해당 워크플로가 버전 1.5.0.0 워크플로임을 나타내는 버전 정보를 확인합니다. 추측 값이 너무 높거나 너무 낮은지 여부 외에도 이전 추측 값에 대해 표시된 정보가 없는지 확인합니다.

    1에서 10 사이의 숫자를 입력하세요.
    추측이 너무 낮습니다.

  5. InstanceId를 적어 두고 워크플로가 완료될 때까지 추측 값을 입력합니다. WriteLine 활동은 동적 업데이트에 의해 업데이트되었으므로 상태 창에는 추측 내용에 대한 정보가 표시됩니다.

    1에서 10 사이의 숫자를 입력하세요.
    추측이 너무 낮습니다.
    1에서 10 사이의 숫자를 입력하세요.
    5는 너무 낮습니다.
    1에서 10 사이의 숫자를 입력하세요.
    7은 너무 높습니다.
    1에서 10 사이의 숫자를 입력하세요.
    축하합니다, 4번 안에 숫자를 맞췄습니다.

  6. Windows 탐색기를 열고 NumberGuessWorkflowHost\bin\debug 폴더(또는 프로젝트 설정에 따라 bin\release)로 이동한 다음, 메모장을 사용하여 완료된 워크플로에 해당하는 추적 파일을 엽니다. InstanceId를 적어 두지 않은 경우 Windows 탐색기에서 수정한 날짜 정보를 사용하여 올바른 추적 파일을 식별할 수 있습니다. 추적 정보의 마지막 줄에는 새로 추가된 WriteLine 활동의 출력이 포함됩니다.

    1에서 10 사이의 숫자를 입력하세요.
    추측이 너무 낮습니다.
    1에서 10 사이의 숫자를 입력하세요.
    5는 너무 낮습니다.
    1에서 10 사이의 숫자를 입력하세요.
    7은 너무 높습니다.
    1에서 10 사이의 숫자를 입력하세요.
    6이 맞습니다. 4번 안에 맞췄습니다.

이전 버전의 워크플로를 시작하도록 설정하려면

업데이트할 워크플로가 모두 실행된 경우 이전 버전의 워크플로를 시작하도록 NumberGuessWorkflowHost 애플리케이션을 수정할 수 있습니다.

  1. 솔루션 탐색기에서 WorkflowHostForm을 두 번 클릭하고 WorkflowType 콤보 상자를 선택합니다.

  2. 속성 창에서 항목 속성을 선택하고 줄임표 단추를 클릭하여 항목 컬렉션을 편집합니다.

  3. 이 컬렉션에 다음 세 가지 항목을 추가합니다.

    StateMachineNumberGuessWorkflow v1
    FlowchartNumberGuessWorkflow v1
    SequentialNumberGuessWorkflow v1
    

    완료된 Items 컬렉션에는 여섯 개의 항목이 포함됩니다.

    StateMachineNumberGuessWorkflow
    FlowchartNumberGuessWorkflow
    SequentialNumberGuessWorkflow
    StateMachineNumberGuessWorkflow v1
    FlowchartNumberGuessWorkflow v1
    SequentialNumberGuessWorkflow v1
    
  4. 솔루션 탐색기에서 WorkflowHostForm을 두 번 클릭하고 코드 보기를 선택합니다.

  5. NewGame_Click 처리기의 switch(또는 Select Case) 문에 세 개의 새 클래스를 추가하여 WorkflowType 콤보 상자의 새 항목을 일치하는 워크플로 ID에 매핑합니다.

    Case "SequentialNumberGuessWorkflow v1"
        identity = WorkflowVersionMap.SequentialNumberGuessIdentity_v1
    
    Case "StateMachineNumberGuessWorkflow v1"
        identity = WorkflowVersionMap.StateMachineNumberGuessIdentity_v1
    
    Case "FlowchartNumberGuessWorkflow v1"
        identity = WorkflowVersionMap.FlowchartNumberGuessIdentity_v1
    
    case "SequentialNumberGuessWorkflow v1":
        identity = WorkflowVersionMap.SequentialNumberGuessIdentity_v1;
        break;
    
    case "StateMachineNumberGuessWorkflow v1":
        identity = WorkflowVersionMap.StateMachineNumberGuessIdentity_v1;
        break;
    
    case "FlowchartNumberGuessWorkflow v1":
        identity = WorkflowVersionMap.FlowchartNumberGuessIdentity_v1;
        break;
    

    다음 예제에는 전체 switch(또는 Select Case) 문이 포함되어 있습니다.

    Select Case WorkflowType.SelectedItem.ToString()
        Case "SequentialNumberGuessWorkflow"
            identity = WorkflowVersionMap.SequentialNumberGuessIdentity
    
        Case "StateMachineNumberGuessWorkflow"
            identity = WorkflowVersionMap.StateMachineNumberGuessIdentity
    
        Case "FlowchartNumberGuessWorkflow"
            identity = WorkflowVersionMap.FlowchartNumberGuessIdentity
    
        Case "SequentialNumberGuessWorkflow v1"
            identity = WorkflowVersionMap.SequentialNumberGuessIdentity_v1
    
        Case "StateMachineNumberGuessWorkflow v1"
            identity = WorkflowVersionMap.StateMachineNumberGuessIdentity_v1
    
        Case "FlowchartNumberGuessWorkflow v1"
            identity = WorkflowVersionMap.FlowchartNumberGuessIdentity_v1
    End Select
    
    switch (WorkflowType.SelectedItem.ToString())
    {
        case "SequentialNumberGuessWorkflow":
            identity = WorkflowVersionMap.SequentialNumberGuessIdentity;
            break;
    
        case "StateMachineNumberGuessWorkflow":
            identity = WorkflowVersionMap.StateMachineNumberGuessIdentity;
            break;
    
        case "FlowchartNumberGuessWorkflow":
            identity = WorkflowVersionMap.FlowchartNumberGuessIdentity;
            break;
    
        case "SequentialNumberGuessWorkflow v1":
            identity = WorkflowVersionMap.SequentialNumberGuessIdentity_v1;
            break;
    
        case "StateMachineNumberGuessWorkflow v1":
            identity = WorkflowVersionMap.StateMachineNumberGuessIdentity_v1;
            break;
    
        case "FlowchartNumberGuessWorkflow v1":
            identity = WorkflowVersionMap.FlowchartNumberGuessIdentity_v1;
            break;
    };
    
  6. Ctrl+F5를 눌러 애플리케이션을 빌드하고 실행합니다. 이제 현재 버전뿐 아니라 v1 버전의 워크플로도 시작할 수 있습니다. 이러한 새 인스턴스를 동적으로 업데이트하려면 ApplyDynamicUpdate 애플리케이션을 실행합니다.