共用方式為


工作 1:啟用用戶端與其主機之間的通訊

在這個工作中,您將透過使用 WCF 合約來啟用您的用戶端和其主機之間的通訊。主應用程式將叫用針對啟動用戶端工作流程而設計的用戶端上的一個作業,並且以啟動值將它初始化。

此外,為了替代透過新執行個體建立其他 WCF 合約,在這個工作中,您將學習如何以程式設計的方式,透過工作流程優先的方法來建立 WCF 合約。

Bb924543.note(zh-tw,VS.90).gif注意:
使用 Visual Studio 工作流程設計工具建立或管理工作流程服務時,有時候會產生假性驗證錯誤。如果您能夠成功建置專案,請忽略驗證錯誤。

程序

若要建立本機主機通訊合約

  1. 注意:使用 Visual Studio 工作流程設計工具建立或管理工作流程服務時,有時候會產生假性驗證錯誤。如果您能夠成功建置專案,請忽略驗證錯誤。

  2. 開啟 WorkflowServiceTutorial 方案。

  3. 在 WorkflowServiceClient 專案節點中,開啟該專案的工作流程設計工具。

  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 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 產生與本機主機通訊作業互動所需的 Proxy 程式碼和組態程式碼。

    使用 SvcUtil.exe

    若要使用 SvcUtil.exe,請參閱 ServiceModel Metadata Utility Tool

    在您建立您的 Proxy 程式碼與組態檔之後,執行下列操作以將那些檔案新增至 WorkflowServiceClient 專案中:

    1. 巡覽至 [方案總管] 窗格。
    2. 以滑鼠右鍵按一下 WorkflowServiceClient 專案節點。
    3. 反白顯示 [新增] 並選取 [現有項目]。
    4. 巡覽至 SvcUtil.exe 產生之組態檔和 Proxy 程式碼檔案所在的資料夾。
    5. 選取檔案,然後按一下 [確定]。
  5. 一旦您產生了 Proxy 程式碼和組態檔,請立刻修改 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. 現在,您已經產生在主機和工作流程服務用戶端之間通訊的 Proxy 用戶端程式碼,您必須新增程式碼以叫用用戶端工作流程中的 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();
        }
    }
    

    由於實作此作業的 ReceiveActivity 已經將 CanCreateInstance 設定為 True,因此,將會建立新的工作流程執行個體,而且其餘的工作流程將如同在之前的練習中執行。此外,透過命令提示輸入的值,將是依工作流程服務叫用其餘數學運算時的初始種子值。

  7. 開啟 Workflow1.cs (如果您已建立 Visual Basic 方案,則為 Workflow1.vb),並移除將數字 1 指派至 sendActivity2_BeforeSend 方法中的 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.