WCF 疑難排解快速入門
本主題列出客戶在開發 WCF 用戶端和服務時會碰到的幾個已知問題。 如果您遇到的問題不在此清單中,建議您為您的服務設定追蹤。 這會產生一個追蹤檔案,您可以使用追蹤檔案檢視器檢視這個檔案,並取得服務中可能會發生之例外狀況的詳細資訊。 如需設定追蹤的詳細資訊,請參閱: Configuring Tracing。 如需追蹤檔案檢視器的詳細資訊,請參閱: Service Trace Viewer Tool (SvcTraceViewer.exe)。
在安裝 Windows 7 和 IIS 後,如果嘗試瀏覽至 WCF 服務,我會收到下列錯誤訊息:HTTP 錯誤 404.3 - 找不到。
HTTP 錯誤 404.3 – 找不到。由於延伸組態的緣故,無法提供您要求的網頁。 若網頁是指令碼,請加入處理常式。 如應下載檔案,請加入 MIME 對應。 詳細的錯誤 InformationModule StaticFileModule。
如果我的用戶端在第一個要求之後閒置一陣子,有時我會在第二個要求收到 MessageSecurityException。 這是為什麼?
當我擲回型別為例外狀況的 FaultException <例外狀況>時,總是在用戶端上收到一般的 FaultException 型別而非泛型型別。 發生什麼事?
我使用 X.509 憑證搭配我的服務,然後得到 System.Security.Cryptography.CryptographicException。 發生什麼事?
在安裝 Windows 7 和 IIS 後,如果嘗試瀏覽至 WCF 服務,我會收到下列錯誤訊息:HTTP 錯誤 404.3 - 找不到。
完整的錯誤訊息是:
HTTP 錯誤 404.3 – 找不到。由於延伸組態的緣故,無法提供您要求的網頁。 若網頁是指令碼,請加入處理常式。 如應下載檔案,請加入 MIME 對應。 詳細的錯誤 InformationModule StaticFileModule。
如果沒有在控制台明確設定 [Windows Communication Foundation HTTP 啟動],就會出現這個錯誤訊息。 若要進行設定,請前往 [控制台],按一下視窗左下角的 [程式]。 按一下 [開啟或關閉 Windows 功能]。 展開 [Microsoft .NET Framework 3.5.1],並選取 [Windows Communication Foundation Http 啟動]。
如果我的用戶端在第一個要求之後閒置一陣子,有時我會在第二個要求收到 MessageSecurityException。 這是為什麼?
第二個要求會失敗的主要原因有兩個:(1) 工作階段已逾時或 (2) 主控服務的 Web 伺服器已回收。 第一種情況中,在服務逾時之前工作階段都是有效的。當服務未在服務繫結中指定的時間內收到來自用戶端的要求時 (ReceiveTimeout),服務會終止安全性工作階段。 後續的用戶端訊息會造成 MessageSecurityException。 用戶端必須以此服務重新建立安全工作階段,以傳送未來的訊息或使用可設定狀態的安全性內容權杖。 可設定狀態的安全性內容權杖也允許安全工作階段存留已回收的 Web 伺服器。 如需詳細了解如何在安全工作階段使用具狀態的安全性內容權杖,請參閱作法:為安全工作階段建立安全性內容權杖。 或者,您可以停用安全工作階段。 使用 <wsHttpBinding> 繫結時,可以將 establishSecurityContext
屬性設定為 false
以停用安全工作階段。 如果要為其他繫結停用安全工作階段,必須建立自訂繫結。 如需有關建立自訂繫結的詳細資料,請參閱 How to: Create a Custom Binding Using the SecurityBindingElement。 在您套用其中任何一種選項之前,必須瞭解您應用程式的安全性需求。
我的服務在與大約 10 個用戶端互動之後,開始拒絕新的用戶端。 這是為什麼?
根據預設,服務同時只能有 10 個工作階段。 因此,如果服務繫結使用工作階段,服務會接受新用戶端連線直到到達該數目,然後拒絕新用戶端連線,直到其中一個目前工作階段結束為止。 您可以使用許多種方法來支援多個用戶端。 如果您的服務不需要工作階段,請勿使用工作階段繫結 (如需詳細資訊,請參閱使用工作階段 (部分機器翻譯))。另一種選擇是將 MaxConcurrentSessions 屬性的值變更為適合您情況的數目,以增加工作階段限制。
我可以從 WCF 應用程式的組態檔以外的地方載入我的服務組態嗎?
可以,不過您必須建立覆寫 ServiceHost 方法的自訂 ApplyConfiguration 類別。 在該方法中,您可以呼叫基底先載入組態 (如果您也想要載入標準組態資訊),但您也可以完全取代組態載入系統。 如果要從不同於應用程式組態檔的檔案載入組態,必須自行剖析並載入組態。
下列程式碼範例將示範如何覆寫 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 。
如有其他相關問題,請參閱執行 Windows Communication Foundation 範例主題。
如果您的用戶端是使用 Windows 認證,且例外狀況為 SecurityNegotiationException,請設定 Kerberos 如下。
將身分識別認證新增至用戶端的 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>
在 System 或 NetworkService 帳戶下執行自我主控的服務。 您可以執行這個命令,在 System 帳戶下建立命令視窗:
at 12:36 /interactive "cmd.exe"
在網際網路資訊服務 (IIS) 下主控服務,根據預設,它會使用服務主要名稱 (SPN) 帳戶。
使用 SetSPN 向網域註冊新的 SPN。 必須是網域管理員才能執行這項操作。
如需 Kerberos 通訊協定詳細資訊,請參閱用於 WCF 的安全性概念及:
當我擲回型別為例外狀況的 FaultException <例外狀況>時,總是在用戶端上收到一般的 FaultException 型別而非泛型型別。 發生什麼事?
強烈建議您建議自己的自訂錯誤資料型別,並宣告為您的錯誤合約中的詳細型別。 原因是使用系統提供的例外狀況類型:
建立類型依存性,移除服務導向應用程式的其中一個最大的強度。
無法依存以標準方式序列化的例外狀況。 有些 (例如 SecurityException) 可能完全不能序列化。
對用戶端公開內部實作詳細資料。 如需詳細資訊,請參閱指定與處理合約和服務中的錯誤。
然而,如果您是對應用程式進行偵錯,可以使用 ServiceDebugBehavior 類別來序列化例外狀況資訊,並傳回用戶端。
當回覆未包含任何資料時,單向和要求與回覆作業似乎會以大約相同的速度傳回。 發生了什麼事?
將作業指定為單向只是表示作業合約接受輸入訊息,而沒有傳回輸出訊息。 在 WCF 中,當傳出資料已寫入網路或擲回例外狀況時,所有用戶端叫用都會傳回。 單向作業的運作方式相同,如果找不到服務可以擲回,或如果服務尚未準備好從網路接受資料便會封鎖。 通常在 WCF 中,這會造成單向呼叫比要求-回覆更快傳回用戶端,但是任何減慢資料網路傳出速度的情況,都會減慢單向作業以及要求-回覆作業。 如需詳細資訊,請參閱單向服務和使用用戶端存取服務。
我使用 X.509 憑證搭配我的服務,然後得到 System.Security.Cryptography.CryptographicException。 發生什麼事?
這常常發生在變更用來執行 IIS 背景工作處理序的使用者帳戶之後。 例如,在 Windows XP 中,如果將執行 Aspnet_wp.exe 的預設使用者帳戶從 ASPNET 變更為自訂使用者帳戶,可能會看到這個錯誤。 如果使用私密金鑰,使用它的處理序將會需要有權限才能存取儲存該金鑰的檔案。
如果是這種情況,您必須提供存取權限給處理序的帳戶,檔案才能包含私密金鑰。 例如,如果 IIS 背景工作處理序正在 Bob 帳戶下執行,則您會需要為 Bob 提供含有私密金鑰的檔案的讀取權。
如需更多資訊,了解如何提供正確的使用者帳戶存取權給含有特定 X.509 憑證的私密金鑰檔案,請參閱作法:讓 WCF 能夠存取 X.509 憑證。
我將作業的第一個參數從大寫變更為小寫;現在我的用戶端擲回了例外狀況。 發生了什麼事?
作業特徵標記中參數名稱的值是合約的一部分,而且必須區分大小寫。 當您需要區分本機參數名稱和描述用戶端應用程式的作業的中繼資料時,請使用 System.ServiceModel.MessageParameterAttribute 屬性。
我正在使用我的其中一種追蹤工具,而我得到 EndpointNotFoundException。 發生什麼事?
如果使用的追蹤工具不是系統提供的 WCF 追蹤機制,且收到 EndpointNotFoundException 指出位址篩選不符,則需要使用 ClientViaBehavior 類別將訊息導向追蹤公用程式,然後讓公用程式將這些訊息重新導向至服務位址。 ClientViaBehavior 類別會變更 Via
位址標頭,以指定與最終接收者不同的下一個網路位址,由 To
位址標頭指示。 然而,執行這項操作時,請勿變更端點位址,它是用於建立 To
值的。
下列程式碼範例顯示用戶端組態檔範例。
<endpoint
address="http://localhost:8000/MyServer/"
binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IMyContract"
behaviorConfiguration="MyClient"
contract="IMyContract"
name="WSHttpBinding_IMyContract">
</endpoint>
<behaviors>
<endpointBehaviors>
<behavior name="MyClient">
<clientVia viaUri="http://localhost:8001/MyServer/"/>
</behavior>
</endpointBehaviors>
</behaviors>
什麼是基底位址? 它與端點位址如何產生關聯?
基底位址是 ServiceHost 類別的根位址。 根據預設,如果您將 ServiceMetadataBehavior 類別新增至服務組態中,會從 HTTP 基底位址擷取主機發行的所有端點的 Web 服務描述語言 (WSDL),加上提供給中繼資料行為的相對位址,加上 "?wsdl"。 如果您熟悉 ASP.NET 和 IIS,基底位址就等同虛擬目錄。
使用 NetTcpBinding 在服務端點與 MEX 端點之間共用通訊埠
如果您將服務的基底位址指定為 net.tcp://MyServer:8080/MyService,並且加入下列端點:
<services>
<service name="Microsoft.Samples.NetTcp.CalculatorService">
<endpoint address="calcsvc" binding ="netTcpBinding" contract="Microsoft.Samples.NetTcp.ICalculator"/>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
</service>
</services>
而且,如果您修改其中一個 NetTcpBinding 設定,如下列組態片段所示:
<bindings>
<netTcpBinding>
<binding closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="11" maxReceivedMessageSize="65536">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
<security mode="Transport">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/>
</security>
</binding>
</netTcpBinding>
</bindings>
您將看見類似下面的錯誤:未處理的例外狀況:System.ServiceModel.AddressAlreadyInUseException: IP 端點 0.0.0.0:9000 已有接聽項。您可以使用 MEX 端點的不同通訊埠來指定完整 URL,藉以解決這個錯誤,如下列組態片段所示:
<services>
<service name="Microsoft.Samples.NetTcp.CalculatorService">
<endpoint address="calcsvc" binding ="netTcpBinding" contract="Microsoft.Samples.NetTcp.ICalculator"/>
<endpoint address="net.tcp://localhost:9001/servicemodelsamples/mex" binding="mexTcpBinding" contract="IMetadataExchange" />
</service>
</services>
從 WCF SOAP 應用程式呼叫 WCF Web HTTP 應用程式時,服務傳回下列錯誤:405 不允許的方法。
從 WCF 服務呼叫 WCF Web HTTP 應用程式 (使用 WebHttpBinding 和 WebHttpBehavior 的服務),可能會產生下列例外狀況:Unhandled Exception: System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]: The remote server returned an unexpected response: (405) Method Not Allowed.
發生此例外是因為 WCF 會以傳入的 OperationContext 覆寫傳出的 OperationContext。 若要解決這個問題,請在 WCF Web HTTP 服務作業中建立 OperationContextScope。 例如:
public string Echo(string input)
{
using (new OperationContextScope(this.InnerChannel))
{
return base.Channel.Echo(input);
}
}