共用方式為


WCF 疑難排解快速入門

這個主題使用問答的格式來描述一些最常發生的問題、您可以如何解決,以及在何處尋找與問題有關的資訊。

問題

問題:如果我的用戶端在第一個要求之後閒置一陣子,有時我會在第二個要求收到 MessageSecurityException。這是為什麼?

第二個要求會失敗的主要原因有兩個:(1) 工作階段已逾時或 (2) 主控服務的 Web 伺服器已回收。第一種情況中,在服務逾時之前工作階段都是有效的。當服務未在服務繫結中指定的時間內收到來自用戶端的要求時 (ReceiveTimeout),服務會終止安全性工作階段。後續的用戶端訊息會造成 MessageSecurityException。用戶端必須以此服務重新建立安全工作階段,以傳送未來的訊息或使用可設定狀態的安全性內容權杖。可設定狀態的安全性內容權杖也允許安全工作階段存留已回收的 Web 伺服器。如需 在安全工作階段中使用可設定狀態的安全性內容權杖,請參閱 HOW TO:為安全工作階段建立可設定狀態的安全性內容權杖。或者,您可以停用安全工作階段。當您使用 WsHttpBinding 繫結時,可以將 establishSecurityContext 屬性設定為 false 以停用安全工作階段。如果要為其他繫結停用安全工作階段,必須建立自訂繫結。如需有關建立自訂繫結的詳細資料,請參閱 HOW TO:使用 SecurityBindingElement 建立自訂繫結。在您套用其中任何一種選項之前,必須瞭解您應用程式的安全性需求。

問題:我的服務在與大約 10 個用戶端互動之後,開始拒絕新的用戶端。這是為什麼?

根據預設,服務同時只能有 10 個工作階段。因此,如果服務繫結使用工作階段,服務會接受新用戶端連線直到到達該數目,然後拒絕新用戶端連線,直到其中一個目前工作階段結束為止。您可以使用許多種方法來支援多個用戶端。如果您的服務不需要工作階段,請勿使用工作階段繫結 (如需詳細資訊,請參閱 使用工作階段)。另一種選擇是將 MaxConcurrentSessions 屬性的值變更為適合您情況的數目,以增加工作階段限制。

問題:我可以從 WCF 應用程式的組態檔以外的地方載入我的服務組態嗎?

可以,不過您必須建立覆寫 ApplyConfiguration 方法的自訂 ServiceHost 類別。在該方法中,您可以呼叫基底先載入組態 (如果您也想要載入標準組態資訊),但您也可以完全取代組態載入系統。請注意,如果您要從與應用程式組態檔不同的組態檔載入組態,必須自行剖析組態檔並載入組態。

下列程式碼範例將示範如何覆寫 ApplyConfiguration 方法,以及直接設定端點。

public class MyServiceHost : ServiceHost
{
  public MyServiceHost(Type serviceType, params Uri[] baseAddresses)  
    : base(serviceType, baseAddresses)
  { Console.WriteLine("MyServiceHost Constructor"); }

  protected override void ApplyConfiguration()
  {
    string straddress = GetAddress();
    Uri address = new Uri(straddress);
    Binding binding = GetBinding();
    base.AddServiceEndpoint(typeof(IData), binding, address);
  }

  string GetAddress()
  { return "http://MyMachine:7777/MyEndpointAddress/"; }

  Binding GetBinding()
  {
    WSHttpBinding binding = new WSHttpBinding();
    binding.Security.Mode = SecurityMode.None;
    return binding;
  }
}

問題:我的服務和用戶端運作良好,但是當用戶端在另一台電腦上時,它們就無法運作。結果如何呢?

根據例外狀況,可能有幾個問題:

  • 您可能需要將用戶端端點位址變更為主機名稱而非 "localhost"。
  • 您可能需要對應用程式開放連接埠。如需詳細資料,請參閱 SDK 範例的Firewall Instructions
  • 有關其他可能的問題,請參閱範例主題Running the Samples in a Workgroup and Across Machines
  • 如果您的用戶端是使用 Windows 認證,且例外狀況為 SecurityNegotiationException,請設定 Kerberos 如下。
    1. 將身分識別認證新增至用戶端的 App.config 檔案中的端點項目:

      <endpoint 
        address="http://MyServer:8000/MyService/" 
        binding="wsHttpBinding" 
        bindingConfiguration="WSHttpBinding_IServiceExample" 
        contract="IServiceExample" 
        behaviorConfiguration="ClientCredBehavior" 
        name="WSHttpBinding_IServiceExample">
        <identity>
          <userPrincipalName value="name@corp.contoso.com"/>
        </identity>
      </endpoint>
      
    2. 在 System 或 NetworkService 帳戶下執行自我主控的服務。您可以執行這個命令,在 System 帳戶下建立命令視窗:

      at 12:36  /interactive "cmd.exe"
      
    3. 在網際網路資訊服務 (IIS) 下主控服務,根據預設,它會使用服務主要名稱 (SPN) 帳戶。

    4. 使用 SetSPN 向網域註冊新的 SPN。請注意,您必須是網域系統管理員才能執行這項操作。

如需 Kerberos 通訊協定,請參閱用於 WCF 的安全性概念及:

問題:當我擲回型別為例外狀況的 FaultException<Exception> 時,總是在用戶端上收到一般的 FaultException 型別而非泛型型別。結果如何呢?

強烈建議您建議自己的自訂錯誤資料型別,並宣告為您的錯誤合約中的詳細型別。原因是使用系統提供的例外狀況類型:

  • 建立類型依存性,移除服務導向應用程式的其中一個最大的強度。
  • 無法依存以標準方式序列化的例外狀況。有些 (例如 SecurityException) 可能完全不能序列化。
  • 對用戶端公開內部實作詳細資料。如需詳細資訊,請參閱 指定與處理合約和服務中的錯誤

然而,如果您是對應用程式進行偵錯,可以使用 ServiceDebugBehavior 類別來序列化例外狀況資訊,並傳回用戶端。

問題:當回覆未包含任何資料時,單向和要求與回覆作業似乎會以大約相同的速度傳回。這是為什麼?

將作業指定為單向只是表示作業合約接受輸入訊息,而沒有傳回輸出訊息。在 WCF 中,當傳出資料已寫入網路或擲回例外狀況時,所有用戶端叫用都會傳回。單向作業的運作方式相同,如果找不到服務可以擲回,或如果服務尚未準備好從網路接受資料便會封鎖。通常在 WCF 中,這會造成單向呼叫比要求與回覆更快傳回用戶端;但是任何減慢傳出資料在網路上的傳送速度的情況都會減慢單向作業以及要求與回覆作業。如需詳細資訊,請參閱 單向服務使用用戶端存取服務

問題:我使用 X.509 憑證搭配我的服務,然後得到 System.Security.Cryptography.CryptographicException。結果如何呢?

這常常發生在變更用來執行 IIS 背景工作處理序的使用者帳戶之後。例如,在 Windows XP 中,如果您將用於執行 Aspnet_wp.exe 的預設使用者帳戶從 ASPNET 變更為自訂使用者帳戶,您可能會看到這個錯誤。如果使用私密金鑰,使用它的處理序將會需要有權限才能存取儲存該金鑰的檔案。

如果是這種情況,您必須提供存取權限給處理序的帳戶,檔案才能包含私密金鑰。例如,如果 IIS 背景工作處理序正在 Bob 帳戶下執行,則您會需要為 Bob 提供含有私密金鑰的檔案的讀取權。

如需 如何提供正確的使用者帳戶存取權給含有特定 X.509 憑證的私密金鑰的檔案,請參閱 HOW TO:讓 WCF 能夠存取 X.509 憑證

問題:我將作業的第一個參數從大寫變更為小寫;現在我的用戶端擲回了例外狀況。這是為什麼?

作業簽章中參數名稱的值是合約的一部分,而且必須區分大小寫。當您需要區分本機參數名稱和描述用戶端應用程式的作業的中繼資料時,請使用 System.ServiceModel.MessageParameterAttribute 屬性。

問題:我正在使用我的其中一種追蹤工具,而我得到 EndpointNotFoundException。結果如何呢?

如果您使用的追蹤工具不是系統提供的 WCF 追蹤機制,且收到 EndpointNotFoundException 指出有位址篩選不符的情況,則您需要使用 ClientViaBehavior 類別將訊息導向追蹤公用程式,然後讓公用程式將這些訊息重新導向至服務位址。ClientViaBehavior 類別會變更 Via 位址標頭,以指定與最終接收者不同的下一個網路位址,由 To 位址標頭指示。然而,執行這項操作時,請勿變更端點位址,它是用於建立 To 值的。

下列程式碼範例顯示用戶端組態檔範例。

<endpoint 
  address=https://localhost:8000/MyServer/
  binding="wsHttpBinding"
  bindingConfiguration="WSHttpBinding_IMyContract"
  behaviorConfiguration="MyClient" 
  contract="IMyContract" 
  name="WSHttpBinding_IMyContract">
</endpoint>
<behaviors>
  <endpointBehaviors>
    <behavior name="MyClient">
      <clientVia viaUri="https://localhost:8001/MyServer/"/>
    </behavior>
  </endpointBehaviors>
</behaviors>

問題:什麼是基底位址?它與端點位址如何產生關聯?

基底位址是 ServiceHost 類別的根位址。根據預設,如果您將 ServiceMetadataBehavior 類別新增至服務組態中,會從 HTTP 基底位址擷取主機發行的所有端點的 Web 服務描述語言 (WSDL),加上提供給中繼資料行為的相對位址,加上 "?wsdl"。如果您熟悉 ASP.NET 和 IIS,基底位址就等同虛擬目錄。

問題:我要如何為一個服務公開多個端點?

您執行這項操作的方法是將 <endpoint> 項目新增至應用程式組態檔中的 <service> 項目,或以程式設計方式執行相等的步驟。如需詳細資訊,請參閱 指定端點位址HOW TO:在組態中建立服務端點HOW TO:在程式碼中建立服務端點

問題:我如何得知哪些繫結支援不同的行為?

如需 系統提供的繫結及所支援的功能,請參閱系統提供的繫結

問題:我要如何為屬性使用不同的值來設定標準繫結?

如需詳細資訊,請參閱設定 Windows Communication Foundation 服務的繫結

問題:如果我要使用 HTTP 做為傳輸,需要將我的服務部署到 HTTP 伺服器嗎?

不需要。系統提供的繫結包括在從主控應用程式類型使用時,數種支援 HTTP 傳輸的繫結。如需 系統提供的繫結及所支援的功能的詳細資訊,請參閱系統提供的繫結

問題:使用標準繫結的服務的預設行為是什麼?

這要視所選擇的標準繫結而定。一般而言,使用工作階段的繫結的預設行為是為各個新用戶端建立新的服務執行個體,而來自特定用戶端的後續呼叫會傳送至有關聯的服務執行個體。如需 系統提供的繫結及所支援的功能的詳細資訊,請參閱系統提供的繫結

問題:有沒有簡單的方法可以看到功能與繫結的對應?例如,我如何能夠分辨哪些繫結支援交易、安全性等等?

是。請參閱系統提供的繫結

問題:我要如何將自訂資料型別從服務傳遞到用戶端?

在兩個端點之間傳遞的資料型別必須是可序列化的,而對服務來說,最簡單且最能夠互通的序列化機制就是使用 DataContractAttributeDataMemberAttribute 類別。如需 這個和其他支援的序列化機制的詳細資訊,請參閱指定服務合約中的資料傳輸

問題:我何時應該使用組態檔來進行設定,而何時應該使用程式碼來設定?

由於應用程式組態檔可讓開發人員針對部署者的執行階段組態做出決定,因此部署者絕對不會做出的決定十分適合使用產品程式碼的組態。開發人員可以是在自己的電腦上安裝程式的個人,或是使用企業群組原則來修改電腦組態檔以及針對本機修改進行鎖定的企業系統管理員。如需後者的範例,請參閱 HOW TO:鎖定企業的端點

問題:關於設計正常執行的服務,我應該知道些什麼?

請參閱設計與實作服務

問題:這一切在產生的用戶端程式碼中是什麼?

如果要找出您處理產生的用戶端程式碼的方式,請參閱瞭解產生的用戶端程式碼。如需 用戶端架構的詳細資訊,請參閱用戶端架構

問題:我為什麼應該在 WCF 用戶端物件上呼叫 Close 方法?

在 WCF 用戶端物件上呼叫 Close 可讓用戶端和服務正常結束對話,並回收與它有關聯的資源。此外,如果您是使用工作階段,呼叫 Close 可能是判斷工作階段自上次呼叫開始是否有錯誤的最快方法,該案例可以對您的用戶端應用程式有意義。如需詳細資訊,請參閱 使用 WCF 用戶端存取服務和範例Expected Exceptions

問題:為什麼雖然程式碼看起來沒有問題,但是我的服務的運作不如預期?

如果您的服務應用程式是使用應用程式組態檔來設定的,應檢查該檔案以判斷是否有某些組態項目或屬性正以未預期的方式改變執行行為。特別是,執行行為相當依賴在端點中實作合約的繫結。請確認組態檔中的繫結以您預期的方式支援您想要的功能。

如果組態檔看起來沒問題,就可以使用診斷功能 (例如記錄和追蹤) 來繼續檢查您應用程式的執行階段行為。如需詳細資訊,請參閱 管理與診斷

問題:告知用戶端服務上有問題的最佳方式是什麼?

執行這項操作的最佳方式是將使用自訂可序列化錯誤資料型別的 FaultContractAttribute 類別新增至您的作業。然而,當您的作業遇到可以偵測的錯誤狀況時,它會擲回新的 FaultException,其中型別參數是可序列化的錯誤類型。如需詳細資訊,請參閱 指定與處理合約和服務中的錯誤

問題:何種資訊可以傳回用戶端?

請只傳回您服務的用戶端需要知道的資訊。身為服務的設計人員,您應該只提供該資訊量,以免將內部實作詳細資料公開給未經授權的用戶端。這就是強烈建議您不要傳回您 SOAP 錯誤中 Exception 物件的原因。如需詳細資訊,請參閱 指定與處理合約和服務中的錯誤

問題:我的用戶端應用程式如何偵測與服務的連線已關閉?

您可以處理用戶端通道的 CommunicationObject 狀態變更事件;然而,何時通知您通道關閉或錯誤要視通道實作而定。例如,NetTcpBinding 類別很快就會通知您,由於工作階段的存留時間與基礎通訊端的存留時間有關聯,因此通道關閉或錯誤。

然而,設計用於保護應用程式不受小型網路干擾的工作階段繫結 (例如由 ReliableSessionBindingElement 類別提供的工作階段) 在嘗試重新建立工作階段時,可能不會立刻通知您。由於情況如此,因此建議您不要嘗試直接偵測中斷連線。

相反地,請將工作階段視為對話。如果您開啟通道,執行幾個作業呼叫並成功關閉通道,則可以假設通道沒有意外關閉。如需 用戶端和工作階段的詳細資訊,請參閱使用工作階段。如需 處理用戶端上的通道相關例外狀況的詳細資訊,請參閱使用用戶端存取服務。如需有關例外狀況一般處理的資訊,請參閱指定與處理合約和服務中的錯誤

問題:我要如何設定 WCF 服務安全性的 Secure Sockets Layer 憑證?

請參閱 HOW TO:使用 SSL 憑證設定連接埠

問題:我要如何使用訊息偵測器來記錄或修改訊息?

請參閱下列主題:

問題:我要如何新增有額外資訊的端點位址?

當您想要以程式設計方式附加複雜的端點位址時 (例如,如果您需要以程式設計方式指定含有特定標頭或身分識別的 EndpointAddress 類別),必須執行如下,其中 relativeOrAbsoluteAddress 是相對或絕對的統一資源識別元 (URI):

// Do this:
ServiceEndpoint e = myServiceHost.AddServiceEndpoint(c,b,"relativeOrAbsoluteAddress");
e.Address = new EndpointAddress(e.Address.Uri, /*other info like headers */);

問題:我一直試著建置 Web 主控的範例,但建置都因為無法產生目錄、或執行複製或刪除命令而失敗。為什麼會發生這種問題?

在建置的過程中,有些 Web 主控的範例會嘗試將編譯後的 WCF 服務二進位碼檔案複製到 %SystemDrive%\inetpub\wwwroot\ServiceModelSamples 資料夾中。這個動作可有效的在 IIS 中部署服務。如果執行 SDK 命令提示字元或 Visual Studio 所在的帳戶沒有修改資料夾的權限,建置就會中斷。若要更正這個問題,您可以執行下列其中一項工作

  • 將修改 %SystemDrive%\inetpub\wwwroot 的權限,授與您要用來建置範例的帳戶。
  • 以系統管理員身分執行 SDK 命令提示字元或 Visual Studio。

請參閱

概念

偵錯 Windows 驗證錯誤