Dot-Net

.NET WCF 錯誤生成不正確的 SOAP 1.1 錯誤程式碼值

  • February 26, 2014

我正在嘗試使用 FaultException 和 FaultException<T> 來確定我們應用程序中的最佳使用模式。我們需要支持 WCF 以及非 WCF 服務消費者/客戶端,包括 SOAP 1.1 和 SOAP 1.2 客戶端。

僅供參考:使用帶有 wsHttpBinding 的 FaultExceptions 會產生 SOAP 1.2 語義,而使用帶有 basicHttpBinding 的 FaultExceptions 會產生 SOAP 1.1 語義。

我正在使用以下程式碼拋出 FaultException<FaultDetails>:

 throw new FaultException&lt;FaultDetails&gt;(
     new FaultDetails("Throwing FaultException&lt;FaultDetails&gt;."),
     new FaultReason("Testing fault exceptions."),
     FaultCode.CreateSenderFaultCode(new FaultCode("MySubFaultCode"))
     );

FaultDetails 類只是一個簡單的測試類,它包含一個字元串“Message”屬性,如下所示。

使用 wsHttpBinding 時,響應為:

&lt;?xml version="1.0" encoding="utf-16"?&gt;
&lt;Fault xmlns="http://www.w3.org/2003/05/soap-envelope"&gt;
&lt;Code&gt;
 &lt;Value&gt;Sender&lt;/Value&gt;
 &lt;Subcode&gt;
   &lt;Value&gt;MySubFaultCode&lt;/Value&gt;
 &lt;/Subcode&gt;
&lt;/Code&gt;
&lt;Reason&gt;
 &lt;Text xml:lang="en-US"&gt;Testing fault exceptions.&lt;/Text&gt;
&lt;/Reason&gt;
&lt;Detail&gt;
 &lt;FaultDetails xmlns="http://schemas.datacontract.org/2004/07/ClassLibrary" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"&gt;
   &lt;Message&gt;Throwing FaultException&lt;FaultDetails&gt;.&lt;/Message&gt;
 &lt;/FaultDetails&gt;
&lt;/Detail&gt;

根據 SOAP 1.2 規範,這看起來是正確的。主/根“程式碼”是“發件人”,其“子程式碼”為“MySubFaultCode”。如果服務使用者/客戶端使用 WCF,客戶端上的 FaultException 也模仿相同的結構,faultException.Code.Name 為“Sender”,faultException.Code.SubCode.Name 為“MySubFaultCode”。

使用 basicHttpBinding 時,響應為:

&lt;?xml version="1.0" encoding="utf-16"?&gt;
&lt;s:Fault xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"&gt;
 &lt;faultcode&gt;s:MySubFaultCode&lt;/faultcode&gt;
 &lt;faultstring xml:lang="en-US"&gt;Testing fault exceptions.&lt;/faultstring&gt;
 &lt;detail&gt;
   &lt;FaultDetails xmlns="http://schemas.datacontract.org/2004/07/ClassLibrary" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"&gt;
     &lt;Message&gt;Throwing FaultException&lt;FaultDetails&gt;.&lt;/Message&gt;
   &lt;/FaultDetails&gt;
 &lt;/detail&gt;
&lt;/s:Fault&gt;

這看起來不對。查看 SOAP 1.1 規範,當我使用 FaultCode.CreateSenderFaultCode(new FaultCode(“MySubFaultCode”)) 時,我希望看到“faultcode”的值為“s:Client.MySubFaultCode”。此外,WCF 客戶端的結構不正確。faultException.Code.Name 是“MySubFaultCode”而不是“Sender”,faultException.Code.SubCode 是 null 而不是 faultException.Code.SubCode.Name 是“MySubFaultCode”。此外,faultException.Code.IsSenderFault 為假。

使用 FaultCode.CreateReceiverFaultCode(new FaultCode(“MySubFaultCode”)) 時的類似問題:

  • 按預期工作於 SOAP 1.2
  • 生成“s:MySubFaultCode”而不是“s:Server.MySubFaultCode”,並且 SOAP 1.1 的 faultException.Code.IsReceiverFault 為 false

這個項目也是2006年別人在http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=669420&SiteID=1上發布的,沒有人回答。我很難相信還沒有人遇到過這種情況。

這是其他人遇到類似問題:http ://forums.microsoft.com/msdn/ShowPost.aspx?PostID=3883110&SiteID=1&mode=1

Microsoft Connect 錯誤:https ://connect.microsoft.com/wcf/feedback/ViewFeedback.aspx?FeedbackID=367963

故障應該如何工作的描述:http: //blogs.msdn.com/drnick/archive/2006/12/19/creating-faults-part-3.aspx

我做錯了什麼還是這真的是 WCF 中的一個錯誤?

這是我目前的解決方法:

   /// &lt;summary&gt;
   /// Replacement for the static methods on FaultCode to generate Sender and Receiver fault codes due
   /// to what seems like bugs in the implementation for basicHttpBinding (SOAP 1.1). wsHttpBinding 
   /// (SOAP 1.2) seems to work just fine.
   /// 
   /// The subCode parameter for FaultCode.CreateReceiverFaultCode and FaultCode.CreateSenderFaultCode
   /// seem to take over the main 'faultcode' value in the SOAP 1.1 response, whereas in SOAP 1.2 the
   /// subCode is correctly put under the 'Code-&gt;SubCode-&gt;Value' value in the XML response.
   /// 
   /// This workaround is to create the FaultCode with Sender/Receiver (SOAP 1.2 terms, but gets
   /// translated by WCF depending on the binding) and an agnostic namespace found by using reflector
   /// on the FaultCode class. When that NS is passed in WCF seems to be able to generate the proper
   /// response with SOAP 1.1 (Client/Server) and SOAP 1.2 (Sender/Receiver) fault codes automatically.
   /// 
   /// This means that it is not possible to create a FaultCode that works in both bindings with
   /// subcodes.
   /// &lt;/summary&gt;
   /// &lt;remarks&gt;
   /// See http://stackoverflow.com/questions/65008/net-wcf-faults-generating-incorrect-soap-11-faultcode-values
   /// for more details.
   /// &lt;/remarks&gt;
   public static class FaultCodeFactory
   {
       private const string _ns = "http://schemas.microsoft.com/ws/2005/05/envelope/none";

       /// &lt;summary&gt;
       /// Creates a sender fault code.
       /// &lt;/summary&gt;
       /// &lt;returns&gt;A FaultCode object.&lt;/returns&gt;
       /// &lt;remarks&gt;Does not support subcodes due to a WCF bug.&lt;/remarks&gt;
       public static FaultCode CreateSenderFaultCode()
       {
           return new FaultCode("Sender", _ns);
       }

       /// &lt;summary&gt;
       /// Creates a receiver fault code.
       /// &lt;/summary&gt;
       /// &lt;returns&gt;A FaultCode object.&lt;/returns&gt;
       /// &lt;remarks&gt;Does not support subcodes due to a WCF bug.&lt;/remarks&gt;
       public static FaultCode CreateReceiverFaultCode()
       {
           return new FaultCode("Receiver", _ns);
       }
   }

遺憾的是,我看不到在不破壞 SOAP 1.1 或 1.2 客戶端的情況下使用子程式碼的方法。

如果您使用 Code.SubCode 語法,您可以創建與 SOAP 1.1 兼容的錯誤程式碼值,但它會破壞 SOAP 1.2。

如果您在 .NET 中使用適當的子程式碼支持(通過靜態 FaultCode 方法或其中一種重載),它會破壞 SOAP 1.1,但在 SOAP 1.2 中有效。

引用自:https://stackoverflow.com/questions/65008