使用用戶端存取服務

用戶端應用程式必須建立、設定,以及使用 WCF 用戶端或通道物件來與服務通訊。 WCF 用戶端概觀主題將概要說明在建立基礎用戶端和通道物件時所需要的物件和步驟,以及這些物件的使用方式。

本主題會就用戶端應用程式以及在不同案例下可能有用的用戶端和通道物件,提供一些相關問題的深入資訊。

概觀

本主題將說明下列項目的相關行為和問題:

  • 通道和工作階段存留期 (Lifetime)。

  • 處理例外狀況。

  • 瞭解封鎖問題。

  • 以互動方式初始化通道。

通道和工作階段存留期。

Windows Communication Foundation (WCF) 應用程式包含兩種通道:資料包和工作階段。

「資料包」通道是指其中的所有訊息都各不相關的通道。 使用資料包通道時,如果輸入或輸出作業失敗,下一個作業通常不會受到影響,而且還可以重複使用同一個通道。 基於這點,資料包通道通常不會發生錯誤。

「工作階段」通道則是連線至其他端點的通道。 某一端工作階段中的訊息永遠都會與另一端的相同工作階段相關聯。 此外,工作階段中的參與者雙方都必須同意其對話需求已被滿足,這樣工作階段才能算是成功。 如果它們不同意,工作階段通道可能會發生錯誤。

呼叫第一個作業,便可明確地或隱含地開啟用戶端。

注意

通常嘗試明確地偵測錯的工作階段通道不會有任何效用,因為您收到通知的時間會依工作階段實作而有不同。 例如,由於 System.ServiceModel.NetTcpBinding (已停用可靠工作階段) 會面臨 TCP 連線的工作階段,如果您接聽服務或用戶端上的 ICommunicationObject.Faulted 事件,您就有可能會在發生網路失敗時立刻收到通知。 但可靠工作階段 (透過已啟用 System.ServiceModel.Channels.ReliableSessionBindingElement 的繫結所建立) 是設計用來隔離服務與小型的網路失敗。 如果工作階段可在合理的時間內重新建立,則相同繫結 (針對可靠工作階段所設定) 就可能不會發生錯誤,除非中斷情形持續了更長的一段時間。

根據預設,大部分系統提供的繫結 (會將通道公開至應用程式層) 都會使用工作階段,但 System.ServiceModel.BasicHttpBinding 則不會。 如需詳細資訊,請參閱使用工作階段 (機器翻譯)

工作階段的正確用法

工作階段會提供特定方式來瞭解整個訊息交換是否已經完成,以及兩端是否都認為此工作階段成功。 建議由呼叫應用程式在一個 try 區塊中開啟通道、使用通道,以及關閉通道。 如果工作階段通道已開啟,而呼叫一次 ICommunicationObject.Close 方法後有成功傳回該呼叫,就表示工作階段成功。 在這個案例中所謂的成功,是指所有傳遞可保證已達成指定的繫結程序,而且另一端在呼叫 ICommunicationObject.Abort 之前並沒有呼叫通道上的 Close

下列章節將提供這個用戶端方法的範例。

處理例外狀況

在用戶端應用程式中處理例外狀況是很直接的工作。 如果通道是在 try 區塊中開啟、使用以及關閉,則除非有擲回例外狀況,否則對話就算成功。 一般來說,如果有擲回例外狀況,對話就會中止。

注意

不建議使用 using 陳述式 (Visual Basic 中的 Using)。 這是因為 using 陳述式的結尾可能會引發例外狀況而遮蓋掉您想瞭解的其他例外狀況。 如需詳細資訊,請參閱使用 Close 和 Abort 釋放 WCF 用戶端資源 (機器翻譯)

下列程式碼範例會顯示使用 try/catch 區塊而非 using 陳述式的建議用戶端模式。

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Microsoft.WCF.Documentation;

public class Client
{
  public static void Main()
  {
    // Picks up configuration from the config file.
    SampleServiceClient wcfClient = new SampleServiceClient();
    try
    {
      // Making calls.
      Console.WriteLine("Enter the greeting to send: ");
      string greeting = Console.ReadLine();
      Console.WriteLine("The service responded: " + wcfClient.SampleMethod(greeting));

      Console.WriteLine("Press ENTER to exit:");
      Console.ReadLine();

      // Done with service.
      wcfClient.Close();
      Console.WriteLine("Done!");
    }
    catch (TimeoutException timeProblem)
    {
      Console.WriteLine("The service operation timed out. " + timeProblem.Message);
      Console.ReadLine();
      wcfClient.Abort();
    }
    catch (FaultException<GreetingFault> greetingFault)
    {
      Console.WriteLine(greetingFault.Detail.Message);
      Console.ReadLine();
      wcfClient.Abort();
    }
    catch (FaultException unknownFault)
    {
      Console.WriteLine("An unknown exception was received. " + unknownFault.Message);
      Console.ReadLine();
      wcfClient.Abort();
    }
    catch (CommunicationException commProblem)
    {
      Console.WriteLine("There was a communication problem. " + commProblem.Message + commProblem.StackTrace);
      Console.ReadLine();
      wcfClient.Abort();
    }
  }
}

Imports System.ServiceModel
Imports System.ServiceModel.Channels
Imports Microsoft.WCF.Documentation

Public Class Client
    Public Shared Sub Main()
        ' Picks up configuration from the config file.
        Dim wcfClient As New SampleServiceClient()
        Try
            ' Making calls.
            Console.WriteLine("Enter the greeting to send: ")
            Dim greeting As String = Console.ReadLine()
            Console.WriteLine("The service responded: " & wcfClient.SampleMethod(greeting))

            Console.WriteLine("Press ENTER to exit:")
            Console.ReadLine()

            ' Done with service. 
            wcfClient.Close()
            Console.WriteLine("Done!")
        Catch timeProblem As TimeoutException
            Console.WriteLine("The service operation timed out. " & timeProblem.Message)
            Console.ReadLine()
            wcfClient.Abort()
        Catch greetingFault As FaultException(Of GreetingFault)
            Console.WriteLine(greetingFault.Detail.Message)
            Console.ReadLine()
            wcfClient.Abort()
        Catch unknownFault As FaultException
            Console.WriteLine("An unknown exception was received. " & unknownFault.Message)
            Console.ReadLine()
            wcfClient.Abort()
        Catch commProblem As CommunicationException
            Console.WriteLine("There was a communication problem. " & commProblem.Message + commProblem.StackTrace)
            Console.ReadLine()
            wcfClient.Abort()
        End Try
    End Sub
End Class

注意

檢查 ICommunicationObject.State 屬性的值屬於競爭條件,因此不建議用來判斷是否要重複使用或關閉通道。

即使在關閉時發生例外狀況,資料包通道也絕不會發生錯誤。 此外,無法使用安全對話來進行驗證的非雙工用戶端通常會擲回 System.ServiceModel.Security.MessageSecurityException。 不過,如果使用安全對話的雙工用戶端驗證失敗,則用戶端就會轉而收到 System.TimeoutException

如需在應用程式層級使用錯誤資訊的更完整資訊,請參閱指定與處理合約和服務中的錯誤 (機器翻譯)預期的例外狀況會說明預期的例外狀況,並示範例外狀況的處理方式。 如需如何在開發通道時處理錯誤的詳細資訊,請參閱處理例外狀況和錯誤 (機器翻譯)

用戶端封鎖和效能

當應用程式同步呼叫要求-回覆作業時,除非有收到傳回值或擲回例外狀況 (例如 System.TimeoutException),否則用戶端會封鎖。 這個行為類似本機行為。 當應用程式同步叫用 WCF 用戶端物件或通道上的作業時,除非通道層可以將資料寫入至網路或擲回例外狀況,否則用戶端不會傳回。 雖然單向訊息交換模式 (指定方式是標示作業的 OperationContractAttribute.IsOneWay 設定為 true) 可以讓某些用戶端更能有效回應,但單向作業也會根據繫結程序和已經傳送的訊息來執行封鎖。 單向作業只能進行訊息交換,無法執行其他作業。 如需詳細資訊,請參閱單面服務 (機器翻譯)

不論在何種訊息交換模式下,大型資料區塊都會減慢用戶端的處理速度。 若要了解如何處理這些問題,請參閱大型資料和串流 (機器翻譯)

如果您的應用程式必須在完成作業的同時執行更多工作,則您應該在 WCF 用戶端實作的服務合約介面上建立非同步方法組。 最簡單的方式是在 ServiceModel 中繼資料公用程式工具 (Svcutil.exe) 上使用 /async 參數。 如需範例,請參閱如何:以非同步方式呼叫服務作業 (機器翻譯)

如需提升用戶端效能的詳細資訊,請參閱中介層用戶端應用程式 (機器翻譯)

讓使用者以動態方式選取認證

IInteractiveChannelInitializer 介面可讓應用程式顯示使用者介面,以便使用者選擇要在逾時計時器啟動之前用來建立通道的認證。

應用程式開發人員可以透過兩種方式來使用插入的 IInteractiveChannelInitializer。 用戶端應用程式可以在開啟通道之前呼叫 ClientBase<TChannel>.DisplayInitializationUIIClientChannel.DisplayInitializationUI (或非同步版本) (「明確」方式),或呼叫第一項作業 (「隱含」方式)。

如果使用隱含方式,應用程式就必須在 ClientBase<TChannel>IClientChannel 延伸上呼叫第一項作業。 如果呼叫第一項作業以外的任何作業,就會擲回例外狀況。

如果使用明確方式,應用程式必須依照順序執行下列步驟:

  1. 呼叫 ClientBase<TChannel>.DisplayInitializationUIIClientChannel.DisplayInitializationUI (或非同步版本)。

  2. 當初始設定式已回傳時,在 Open 物件或是 IClientChannel 屬性傳回的 IClientChannel 物件上呼叫 ClientBase<TChannel>.InnerChannel 方法。

  3. 呼叫作業。

建議您採用明確方式來處理使用者介面的實際執行品質應用程式控制。

使用隱含方式的應用程式會叫用使用者介面初始設定式,但若應用程式的使用者無法在繫結的傳送逾時期限之內回應,當使用者介面傳回時就會擲回例外狀況。

另請參閱