تؤدي أخطاء .NET WCF إلى إنشاء قيم رمز خطأ SOAP 1.1 غير صحيحة

StackOverflow https://stackoverflow.com/questions/65008

  •  09-06-2019
  •  | 
  •  

سؤال

أقوم بتجربة استخدام FaultException وFaultException<T> لتحديد أفضل نمط استخدام في تطبيقاتنا.نحتاج إلى دعم مستهلكي/عملاء الخدمة غير التابعين لـ WCF، بما في ذلك عملاء SOAP 1.1 وSOAP 1.2.

لعِلمِكَ:يؤدي استخدام FaultExceptions مع wsHttpBinding إلى دلالات SOAP 1.2 بينما يؤدي استخدام FaultExceptions مع basicHttpBinding إلى دلالات SOAP 1.1.

أنا أستخدم الكود التالي لرمي FaultException<FaultDetails>:

  throw new FaultException<FaultDetails>(
      new FaultDetails("Throwing FaultException<FaultDetails>."),
      new FaultReason("Testing fault exceptions."),
      FaultCode.CreateSenderFaultCode(new FaultCode("MySubFaultCode"))
      );

فئة FaultDetails هي مجرد فئة اختبار بسيطة تحتوي على خاصية "رسالة" سلسلة كما ترون أدناه.

عند استخدام wsHttpBinding يكون الرد:

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

يبدو هذا صحيحًا وفقًا لمواصفات SOAP 1.2."الرمز" الرئيسي/الجذر هو "المرسل"، والذي يحتوي على "رمز فرعي" لـ "MySubFaultCode".إذا كان مستهلك/عميل الخدمة يستخدم WCF، فإن FaultException من جانب العميل يحاكي أيضًا نفس البنية، حيث يكون الخطأ falseException.Code.Name هو "Sender" وfaultException.Code.SubCode.Name هو "MySubFaultCode".

عند استخدام basicHttpBinding يكون الرد:

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

هذا لا يبدو صحيحا.بالنظر إلى مواصفات SOAP 1.1، كنت أتوقع أن أرى أن "رمز الخطأ" له قيمة "s:Client.MySubFaultCode" عندما أستخدم FaultCode.CreateSenderFaultCode(new FaultCode("MySubFaultCode")).كما يحصل عميل WCF على بنية غير صحيحة.يكون falseException.Code.Name هو "MySubFaultCode" بدلاً من أن يكون "Sender"، ويكون الخطأ falseException.Code.SubCode خاليًا بدلاً من أن يكون falseException.Code.SubCode.Name هو "MySubFaultCode".كما أن الخطأ falseException.Code.IsSenderFault غير صحيح.

مشكلة مماثلة عند استخدام FaultCode.CreateReceiverFaultCode(new FaultCode("MySubFaultCode")):

  • يعمل كما هو متوقع لSOAP 1.2
  • ينشئ "s:MySubFaultCode" بدلاً من "s:Server.MySubFaultCode" ويكون الخطأ falseException.Code.IsReceiverFault خطأً بالنسبة لـ SOAP 1.1

تم نشر هذا العنصر أيضًا بواسطة شخص آخر على http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=669420&SiteID=1 في عام 2006 ولم يجب عليه أحد.أجد أنه من الصعب جدًا تصديق أنه لم يسبق لأحد أن واجه هذا الأمر حتى الآن.

وهنا شخص آخر لديه مشكلة مماثلة: http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=3883110&SiteID=1&mode=1

خطأ اتصال Microsoft: 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؟

هل كانت مفيدة؟

المحلول

هذا هو الحل الحالي الخاص بي:

    /// <summary>
    /// 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->SubCode->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.
    /// </summary>
    /// <remarks>
    /// See http://stackoverflow.com/questions/65008/net-wcf-faults-generating-incorrect-soap-11-faultcode-values
    /// for more details.
    /// </remarks>
    public static class FaultCodeFactory
    {
        private const string _ns = "http://schemas.microsoft.com/ws/2005/05/envelope/none";

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

        /// <summary>
        /// Creates a receiver fault code.
        /// </summary>
        /// <returns>A FaultCode object.</returns>
        /// <remarks>Does not support subcodes due to a WCF bug.</remarks>
        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.

نصائح أخرى

الرد من مايكروسوفت:

كما نوقش في http://msdn.microsoft.com/en-us/library/ms789039.aspx, هناك طريقتان موضحتان في مواصفات Soap 1.1 لرموز الأخطاء المخصصة:

(1) استخدام علامة "النقطة" كما تصفها

(2) تحديد رموز خطأ جديدة تمامًا

لسوء الحظ، يجب تجنب تدوين "النقطة"، حيث لا يُنصح باستخدامه في مواصفات ملف التعريف الأساسي WS-I.هذا يعني بشكل أساسي أنه لا يوجد مكافئ حقيقي للرمز الفرعي لخطأ Soap 1.2 عند استخدام Soap 1.1.

لذلك، عند إنشاء الأخطاء، يجب أن تكون على دراية بـMessageVersion المحدد في الربط، وأن تقوم بإنشاء رموز الأخطاء وفقًا لذلك.

نظرًا لأن "المرسل" و"المتلقي" ليسا رموز خطأ صالحة لـ Soap 1.1، ولا يوجد مكافئ حقيقي لرمز فرعي للخطأ، فلا يجب عليك استخدام أساليب CreateSenderFaultCode وCreateReceiverFaultCode عند إنشاء رموز خطأ مخصصة لـ Soap 1.1.

بدلاً من ذلك، ستحتاج إلى تحديد رمز الخطأ الخاص بك، باستخدام مساحة الاسم والاسم الخاصين بك:

FaultCode customFaultCode = new FaultCode(localName, errorNamespace);

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top