다음을 통해 공유


작업 1: 클라이언트와 호스트 간의 통신 설정

이 작업에서는 WCF 계약을 사용하여 클라이언트와 호스트 간의 통신을 설정합니다. 호스트 응용 프로그램은 클라이언트 워크플로를 시작하고 시작 값을 사용하여 초기화하도록 디자인된 한 작업을 클라이언트에서 호출합니다.

또한 이 작업에서는 새 인터페이스를 통해 또 다른 WCF 계약을 만드는 대신 워크플로 중심 방법을 통해 WCF 계약을 프로그래밍 방식으로 만드는 방법을 살펴봅니다.

참고

Visual Studio Workflow Designer를 사용하여 워크플로 서비스를 만들거나 관리할 경우 의사 유효성 검사 오류가 발생할 수 있습니다. 프로젝트를 성공적으로 빌드할 수 있으면 유효성 검사 오류를 무시해도 됩니다.

절차

로컬 호스트 통신 계약을 만들려면

  1. 참고   Visual Studio Workflow Designer를 사용하여 워크플로 서비스를 만들거나 관리할 경우 의사 유효성 검사 오류가 발생할 수 있습니다. 프로젝트를 성공적으로 빌드할 수 있으면 유효성 검사 오류를 무시해도 됩니다.

  2. WorkflowServiceTutorial 솔루션을 엽니다.

  3. WorkflowServiceClient 프로젝트 노드에서 해당 프로젝트의 Workflow Designer를 엽니다.

  4. ReceiveActivity 활동을 디자이너로 끌고 첫 번째 SendActivity 활동 위에 배치하여 ReceiveActivity 활동이 워크플로에서 가장 먼저 실행되도록 합니다.

    이 활동은 로컬 호스트 통신 계약에 정의된 작업을 구현합니다.

  5. ReceiveActivity 활동을 선택하고 속성 창의 ServiceOperationInfo 아래에서 줄임표를 클릭하여 작업 선택 대화 상자를 엽니다.

  6. 워크플로 중심 제작 스타일을 사용하여 새 계약을 정의할 것이므로 오른쪽 위 모퉁이에서 계약 추가를 클릭하고 Contract1을 강조 표시합니다.

  7. 계약 이름 텍스트 상자에서 계약의 이름을 ILocalHostContract로 지정합니다.

  8. ILocalHostContract 아래에서 첫 번째 작업을 강조 표시하고 이름을 StartClientWorkflow로 바꿉니다.

  9. 매개 변수 탭에서 더하기 기호를 클릭하고 방향이 In인 Int32 형식의 initialValue라는 새 매개 변수를 추가한 다음 확인을 클릭합니다.

  10. ReceiveActivity 활동을 선택하고 속성 창 아래에서 initialValue를 전역 변수 inputValue에 바인딩합니다.

  11. 또한 속성 창 아래에서 CanCreateInstance 속성을 True로 설정합니다.

    ILocalHostContract라는 새 계약이 이제 프로그래밍 방식으로 정의되었지만 이 계약을 사용하여 워크플로 서비스와 상호 작용하려면 몇 가지 파일을 변경해야 합니다.

  12. WorkflowServiceClient 프로젝트에서 App.config를 엽니다.

  13. 다음 구성 코드를 추가합니다.

          <services>
            <service name="WorkflowServiceClient.ClientWorkflow" behaviorConfiguration="WorkflowServiceClient.ClientWorkflowBehavior">
              <host>
                <baseAddresses>
                  <add baseAddress="https://localhost:8090/ClientWorkflow" />
                </baseAddresses>
              </host>
              <endpoint address=""
                        binding="wsHttpContextBinding"
                        contract="ILocalHostContract" />
              <endpoint address="mex"
                        binding="mexHttpBinding"
                        contract="IMetadataExchange" />
            </service>
          </services>
          <behaviors>
            <serviceBehaviors>
              <behavior name="WorkflowServiceClient.ClientWorkflowBehavior"  >
                <serviceMetadata httpGetEnabled="true" />
                <serviceDebug includeExceptionDetailInFaults="true" />
                <serviceCredentials>
                  <windowsAuthentication
                      allowAnonymousLogons="false"
                      includeWindowsGroups="true" />
                </serviceCredentials>
              </behavior>
            </serviceBehaviors>
          </behaviors>
    

    이제 로컬 호스트 통신 계약에 끝점 주소를 정의했습니다. 이 자습서 전반에서 사용한 클라이언트는 이 새 계약도 구현합니다.

로컬 호스트 통신을 설정하려면

  1. Program.cs를 열고 다음 using 문을 파일 맨 위에 추가합니다.

    using System.ServiceModel;
    using System.ServiceModel.Description;
    

    Visual Basic 솔루션을 만든 경우 WorkflowServiceClient 프로젝트 노드를 마우스 오른쪽 단추로 클릭하고 속성을 선택합니다. 참조 탭을 선택하고 가져온 네임스페이스 아래에서 System.ServiceModelSystem.ServiceModel.Description의 확인란을 클릭합니다.

  2. WorkflowServiceHost를 사용하여 로컬 호스트 통신을 설정하고 워크플로 서비스를 사용하여 클라이언트 워크플로 작업 호출을 실행할 것이므로 콘솔 호스트 응용 프로그램이 워크플로 서비스 클라이언트와 통신할 수 있도록 Main 메서드를 수정해야 합니다. 다음 코드에서는 로컬 호스트 통신을 용이하게 하기 위해 Main의 구현을 변경해야 하는 방법을 보여 줍니다.

    Shared Sub Main()
        ' Create a WorkflowServiceHost object to listen for operation invocations.
        Using ConsoleHost As New WorkflowServiceHost(GetType(ClientWorkflow))
            Dim waitHandle As New AutoResetEvent(False)
    
            ' Add ChannelManagerService to the list of services used 
            ' by the WorkflowRuntime.
            Dim cms As New ChannelManagerService()
            ConsoleHost.Description.Behaviors.Find(Of WorkflowRuntimeBehavior)().WorkflowRuntime.AddService(cms)
            AddHandler ConsoleHost.Description.Behaviors.Find(Of WorkflowRuntimeBehavior)().WorkflowRuntime.WorkflowCompleted, AddressOf OnWorkflowCompleted
            AddHandler ConsoleHost.Description.Behaviors.Find(Of WorkflowRuntimeBehavior)().WorkflowRuntime.WorkflowTerminated, AddressOf OnWorkflowTerminated
            AddHandler ConsoleHost.Closed, AddressOf OnConsoleClosed
    
            ' Call Open to start receiving messages.
            ConsoleHost.Open()
    
            ' After the client workflow is started, block until receiving waitHandle.Set is called
            ' so that the console application does not exit before the client workflow has completed
            ' and ConsoleHost.Close is called.
            waitHandle.WaitOne()
        End Using
    End Sub
    
    Shared Sub OnWorkflowCompleted(ByVal sender As Object, ByVal e As WorkflowCompletedEventArgs)
        Console.WriteLine("The client workflow has completed." + vbLf + "Press <Enter> to exit the client application.")
        Console.ReadLine()
        WaitHandle.Set()
    End Sub
    
    Shared Sub OnWorkflowTerminated(ByVal sender As Object, ByVal e As WorkflowTerminatedEventArgs)
        Console.WriteLine(e.Exception.Message)
        WaitHandle.Set()
    End Sub
    
    ' After the WorkflowServiceHost transitions to the closed state, allow the console 
    ' application to exit by signaling to the AutoResetEvent object that it is okay to unblock 
    ' the main thread.
    Shared Sub OnConsoleClosed(ByVal sender As Object, ByVal e As EventArgs)
        WaitHandle.Set()
    End Sub
    
    static void Main(string[] args)
    {
        // Create a WorkflowServiceHost object to listen for operation invocations.
        using (WorkflowServiceHost ConsoleHost = new WorkflowServiceHost(typeof(ClientWorkflow)))
        {
            AutoResetEvent waitHandle = new AutoResetEvent(false);
    
            // Add ChannelManagerService to the list of services used 
            // by the WorkflowRuntime.
            ChannelManagerService cms = new ChannelManagerService();
            ConsoleHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime.AddService(cms);
    
            ConsoleHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) 
            { 
                Console.WriteLine("The client workflow has completed. \nPress <Enter> to exit the client application."); 
                Console.ReadLine();
                ConsoleHost.Close();
            };
    
            ConsoleHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
            {
                Console.WriteLine(e.Exception.Message);
                waitHandle.Set();
            };
    
            // After the WorkflowServiceHost transitions to the closed state, allow the console 
            // application to exit by signaling to the AutoResetEvent object that it is okay to unblock 
            // the main thread.
            ConsoleHost.Closed += delegate(object sender, EventArgs e)
            {
                waitHandle.Set();
            };
    
            // Call Open to start receiving messages.
            ConsoleHost.Open();
    
            // After the client workflow is started, block until receiving waitHandle.Set is called
            // so that the console application does not exit before the client workflow has completed
            // and ConsoleHost.Close is called.
            waitHandle.WaitOne();
        }
    }
    
  3. 클라이언트 서비스를 빌드하고 실행합니다.

  4. SvcUtil.exe를 사용하여 로컬 호스트 통신 작업과 상호 작용하는 데 필요한 프록시 코드와 구성 코드를 생성합니다.

    SvcUtil.exe 사용

    SvcUtil.exe를 사용하려면 ServiceModel Metadata Utility Tool를 참조하십시오.

    프록시 코드와 구성 파일을 생성한 후 다음을 수행하여 해당 파일을 WorkflowServiceClient 프로젝트에 추가합니다.

    1. 솔루션 탐색기 창으로 이동합니다.
    2. WorkflowServiceClient 프로젝트 노드를 마우스 오른쪽 단추로 클릭합니다.
    3. 추가를 강조 표시하고 기존 항목을 선택합니다.
    4. SvcUtil.exe에서 구성 및 프록시 코드 파일을 생성한 폴더로 이동합니다.
    5. 파일을 선택하고 확인을 클릭합니다.
  5. 프록시 코드와 구성 파일을 생성한 경우 로컬 호스트 통신을 용이하게 하는 데 사용되는 새 클라이언트 끝점이 호스트 응용 프로그램에서 인식되도록 App.config에서 구성 코드를 수정합니다. 또한 원하는 경우, 워크플로 서비스와 통신하기 위해 현재 사용되는 것과 동일한 바인딩 구성 정보를 사용할 수 있습니다. 다음 코드 예제에서는 App.Config 파일에 추가할 코드를 보여 줍니다.

        <bindings>
        ...
        </bindings>
        <client>
            <endpoint address="https://localhost:8080/ServerWorkflow" binding="wsHttpContextBinding"
                    bindingConfiguration="WSHttpContextBinding_IWorkflow1" contract="IWorkflow1"
                    name="WSHttpContextBinding_IWorkflow1">
                <identity>
                    <userPrincipalName value="someone@example.com" />
                </identity>
            </endpoint>
            <endpoint address="https://localhost:8090/ClientWorkflow" binding="wsHttpContextBinding"
                    bindingConfiguration="WSHttpContextBinding_IWorkflow1"
                    contract="ILocalHostContract" name="WSHttpContextBinding_ILocalHostContract">
                <identity>
                    <userPrincipalName value="someone@example.com" />
                </identity>
            </endpoint>
        </client>
        <services>
        ...
        </services>
        <behaviors>
        ...
        </behaviors>
    
  6. 이제 호스트와 워크플로 서비스 클라이언트 간의 통신을 위한 프록시 클라이언트 코드를 생성했으므로 클라이언트 워크플로에서 LocalHostContractClient.StartClientWorkflow 작업을 호출하는 코드를 추가해야 합니다. 이렇게 하려면 Program.cs(또는 Visual Basic 솔루션을 만든 경우 Module1.vb)를 열고 다음 코드를 추가합니다.

    Class Program
    
        Shared WaitHandle As New AutoResetEvent(False)
    
        Shared Sub Main()
            ' Create a WorkflowServiceHost object to listen for operation invocations.
            Using ConsoleHost As New WorkflowServiceHost(GetType(WorkflowServiceClient.ClientWorkflow))
                Dim waitHandle As New AutoResetEvent(False)
    
                ' Create a client that is used by the host application to communicate with the workflow service client.            Dim LCSClient As New WorkflowServiceClient.LocalHostContractClient("WSHttpContextBinding_ILocalHostContract")
    
                ' Add ChannelManagerService to the list of services used 
                ' by the WorkflowRuntime.
                Dim cms As New ChannelManagerService()
                ConsoleHost.Description.Behaviors.Find(Of WorkflowRuntimeBehavior)().WorkflowRuntime.AddService(cms)
                AddHandler ConsoleHost.Description.Behaviors.Find(Of WorkflowRuntimeBehavior)().WorkflowRuntime.WorkflowCompleted, AddressOf OnWorkflowCompleted
                AddHandler ConsoleHost.Description.Behaviors.Find(Of WorkflowRuntimeBehavior)().WorkflowRuntime.WorkflowTerminated, AddressOf OnWorkflowTerminated
                AddHandler ConsoleHost.Closed, AddressOf OnConsoleClosed
    
                ' Call Open to start receiving messages.
                 ConsoleHost.Open()
    
                Console.WriteLine("Client host service is ready.")            Console.WriteLine("Enter a starting value: ")            ' Read in a number from the user and use it as the initial number in the arithmetic operation calls.            LCSClient.StartClientWorkflow(Int32.Parse(Console.ReadLine()))
    
                ' After the client workflow is started, block until receiving waitHandle.Set is called
                ' so that the console application does not exit before the client workflow has completed
                ' and ConsoleHost.Close is called.
                waitHandle.WaitOne()
            End Using
        End Sub
    
        Shared Sub OnWorkflowCompleted(ByVal sender As Object, ByVal e As WorkflowCompletedEventArgs)
            Console.WriteLine("The client workflow has completed." + vbLf + "Press <Enter> to exit the client application.")
            Console.ReadLine()
            WaitHandle.Set()
        End Sub
    
        Shared Sub OnWorkflowTerminated(ByVal sender As Object, ByVal e As WorkflowTerminatedEventArgs)
            Console.WriteLine(e.Exception.Message)
            WaitHandle.Set()
        End Sub
    
        ' After the WorkflowServiceHost transitions to the closed state, allow the console 
        ' application to exit by signaling to the AutoResetEvent object that it is okay to unblock 
        ' the main thread.
        Shared Sub OnConsoleClosed(ByVal sender As Object, ByVal e As EventArgs)
            WaitHandle.Set()
        End Sub
    End Class
    
    static void Main(string[] args)
    {
        // Create a WorkflowServiceHost object to listen for operation invocations.
        using (WorkflowServiceHost ConsoleHost = new WorkflowServiceHost(typeof(ClientWorkflow)))
        {
            AutoResetEvent waitHandle = new AutoResetEvent(false);
    
            // Create a client that is used by the host application to communicate with the workflow service client.        LocalHostContractClient LCSClient = new LocalHostContractClient("WSHttpContextBinding_ILocalHostContract");
    
            // Add ChannelManagerService to the list of services used 
            // by the WorkflowRuntime.
            ChannelManagerService cms = new ChannelManagerService();
            ConsoleHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime.AddService(cms);
    
            ConsoleHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) 
            { 
                Console.WriteLine("The client workflow has completed. \nPress <Enter> to exit the client application."); 
                Console.ReadLine();
                ConsoleHost.Close();
            };
    
            ConsoleHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
            {
                Console.WriteLine(e.Exception.Message);
                waitHandle.Set();
            };
    
            // After the WorkflowServiceHost transitions to the closed state, allow the console 
            // application to exit by signaling to the AutoResetEvent object that it is okay to unblock 
            // the main thread.
            ConsoleHost.Closed += delegate(object sender, EventArgs e)
            {
                waitHandle.Set();
            };
    
            // Call Open to start receiving messages.
            ConsoleHost.Open();
    
            Console.WriteLine("Client host service is ready.");        Console.WriteLine("Enter a starting value: ");        // Read in a number from the user and use it as the initial number in the arithmetic operation calls.        LCSClient.StartClientWorkflow(Int32.Parse(Console.ReadLine()));
    
            // After the client workflow is started, block until receiving waitHandle.Set is called
            // so that the console application does not exit before the client workflow has completed and 
            // ConsoleHost.Close is called.
            waitHandle.WaitOne();
        }
    }
    

    이 작업을 구현하는 ReceiveActivityCanCreateInstanceTrue로 설정되어 있기 때문에 새 워크플로 인스턴스가 만들어지고 워크플로의 나머지 부분이 이전 연습과 마찬가지로 실행됩니다. 또한 명령 프롬프트를 통해 입력되는 값은 워크플로 서비스에 대해 산술 연산의 나머지를 호출할 때 초기 시드 값이 됩니다.

  7. Workflow1.cs(또는 Visual Basic 솔루션을 만든 경우 Workflow1.vb)를 열고 sendActivity2_BeforeSend 메서드 구현에서 숫자 1을 inputValue 변수에 할당하는 코드 줄을 제거하여 사용자가 명령 프롬프트에서 값을 입력할 때 해당 값이 워크플로 서비스에 대한 모든 작업 호출의 초기 시드 값으로 사용되도록 합니다. 다음 코드 예제에서는 수정된 이벤트 처리기 메서드 구현을 보여 줍니다.

    Private Sub sendActivity2_BeforeSend(ByVal sender As System.Object, ByVal e As System.Workflow.Activities.SendActivityEventArgs)
        Console.WriteLine("The initial input value is {0}", inputValue)
    End Sub
    
    private void sendActivity2_BeforeSend(object sender, SendActivityEventArgs e)
    {
        Console.WriteLine("The initial input value is {0}", inputValue);
    }
    
  8. WorkflowServiceTutorial 솔루션을 빌드하고 실행합니다. 콘솔 호스트 응용 프로그램에서 다음과 유사한 출력이 표시됩니다.

    Client host service is ready.
    Enter a starting value:
    7
    A service instance has successfully been created.
    The initial input value is 7
    The value after invoking the Add operation is 7
    The new input value is 2
    The value after invoking the Subtract operation is 5
    The new input value is 6
    The value after invoking the Multiply operation is 30
    The new input value is 3
    The value after invoking the Divide operation is 10
    The workflow service instance has successfully shutdown.
    The client workflow has completed.
    Press <Enter> to exit the client application.
    

참고 항목

참조

작업 1: 클라이언트와 호스트 간의 통신 설정

Copyright © 2007 by Microsoft Corporation. All rights reserved.