لماذا لا يقوم .NET بإلغاء تسلسل مصفوفتي البدائية من خدمة ويب؟

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

  •  09-06-2019
  •  | 
  •  

سؤال

يساعد!لدي خدمة ويب Axis يتم استهلاكها بواسطة تطبيق C#.كل شيء يعمل بشكل رائع، باستثناء أن صفائف القيم الطويلة تظهر دائمًا على أنها [0,0,0,0] - الطول الصحيح، ولكن لا يتم إلغاء تسلسل القيم.لقد حاولت مع البدائيين الآخرين (ints، doubles) وحدث نفس الشيء.ماذا أفعل؟لا أريد تغيير دلالات خدمتي.

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

المحلول

وهنا ما انتهى بي الأمر.لم أجد حلاً آخر لهذا الأمر، لذا إذا كان لديك شيء أفضل، ساهم بكل الوسائل.

أولاً، تعريف المصفوفة الطويلة في منطقة wsdl:types:

  <xsd:complexType name="ArrayOf_xsd_long">
    <xsd:complexContent mixed="false">
      <xsd:restriction base="soapenc:Array">
        <xsd:attribute wsdl:arrayType="soapenc:long[]" ref="soapenc:arrayType" />
      </xsd:restriction>
    </xsd:complexContent>
  </xsd:complexType>

بعد ذلك، نقوم بإنشاء SoapExtensionAttribute الذي سيقوم بإجراء الإصلاح.يبدو أن المشكلة تكمن في أن .NET لم يكن يتبع معرف multiref للعنصر الذي يحتوي على القيمة المزدوجة.لذلك، نقوم بمعالجة عنصر المصفوفة، ونبحث عن القيمة، ثم ندخلها في العنصر:

[AttributeUsage(AttributeTargets.Method)]
public class LongArrayHelperAttribute : SoapExtensionAttribute
{
    private int priority = 0;

    public override Type ExtensionType
    {
        get { return typeof (LongArrayHelper); }
    }

    public override int Priority
    {
        get { return priority; }
        set { priority = value; }
    }
}

public class LongArrayHelper : SoapExtension
{
    private static ILog log = LogManager.GetLogger(typeof (LongArrayHelper));

    public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
    {
        return null;
    }

    public override object GetInitializer(Type serviceType)
    {
        return null;
    }

    public override void Initialize(object initializer)
    {
    }

    private Stream originalStream;

    private Stream newStream;

    public override void ProcessMessage(SoapMessage m)
    {
        switch (m.Stage)
        {
            case SoapMessageStage.AfterSerialize:
                newStream.Position = 0; //need to reset stream 
                CopyStream(newStream, originalStream);
                break;

            case SoapMessageStage.BeforeDeserialize:
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Indent = false;
                settings.NewLineOnAttributes = false;
                settings.NewLineHandling = NewLineHandling.None;
                settings.NewLineChars = "";
                XmlWriter writer = XmlWriter.Create(newStream, settings);

                XmlDocument xmlDocument = new XmlDocument();
                xmlDocument.Load(originalStream);

                List<XmlElement> longArrayItems = new List<XmlElement>();
                Dictionary<string, XmlElement> multiRefs = new Dictionary<string, XmlElement>();
                FindImportantNodes(xmlDocument.DocumentElement, longArrayItems, multiRefs);
                FixLongArrays(longArrayItems, multiRefs);

                xmlDocument.Save(writer);
                newStream.Position = 0;
                break;
        }
    }

    private static void FindImportantNodes(XmlElement element, List<XmlElement> longArrayItems,
                                           Dictionary<string, XmlElement> multiRefs)
    {
        string val = element.GetAttribute("soapenc:arrayType");
        if (val != null && val.Contains(":long["))
        {
            longArrayItems.Add(element);
        }
        if (element.Name == "multiRef")
        {
            multiRefs[element.GetAttribute("id")] = element;
        }
        foreach (XmlNode node in element.ChildNodes)
        {
            XmlElement child = node as XmlElement;
            if (child != null)
            {
                FindImportantNodes(child, longArrayItems, multiRefs);
            }
        }
    }

    private static void FixLongArrays(List<XmlElement> longArrayItems, Dictionary<string, XmlElement> multiRefs)
    {
        foreach (XmlElement element in longArrayItems)
        {
            foreach (XmlNode node in element.ChildNodes)
            {
                XmlElement child = node as XmlElement;
                if (child != null)
                {
                    string href = child.GetAttribute("href");
                    if (href == null || href.Length == 0)
                    {
                        continue;
                    }
                    if (href.StartsWith("#"))
                    {
                        href = href.Remove(0, 1);
                    }
                    XmlElement multiRef = multiRefs[href];
                    if (multiRef == null)
                    {
                        continue;
                    }
                    child.RemoveAttribute("href");
                    child.InnerXml = multiRef.InnerXml;
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("Replaced multiRef id '" + href + "' with value: " + multiRef.InnerXml);
                    }
                }
            }
        }
    }

    public override Stream ChainStream(Stream s)
    {
        originalStream = s;
        newStream = new MemoryStream();
        return newStream;
    }

    private static void CopyStream(Stream from, Stream to)
    {
        TextReader reader = new StreamReader(from);
        TextWriter writer = new StreamWriter(to);
        writer.WriteLine(reader.ReadToEnd());
        writer.Flush();
    }
}

أخيرًا، قمنا بوضع علامة على جميع الأساليب الموجودة في ملف Reference.cs والتي ستقوم بإلغاء تسلسل مصفوفة طويلة باستخدام السمة الخاصة بنا:

    [SoapRpcMethod("", RequestNamespace="http://some.service.provider",
        ResponseNamespace="http://some.service.provider")]
    [return : SoapElement("getFooReturn")]
    [LongArrayHelper]
    public Foo getFoo()
    {
        object[] results = Invoke("getFoo", new object[0]);
        return ((Foo) (results[0]));
    }

يعد هذا الإصلاح محددًا لفترة طويلة، ولكن من المحتمل أن يتم تعميمه للتعامل مع أي نوع بدائي يواجه هذه المشكلة.

نصائح أخرى

إليك نسخة أكثر أو أقل لصقًا من a مشاركة مدونة لقد كتبت عن هذا الموضوع.

ملخص تنفيذي:يمكنك إما تغيير الطريقة التي يقوم بها .NET بإلغاء تسلسل مجموعة النتائج (راجع حل Chris أعلاه)، أو يمكنك إعادة تكوين Axis لإجراء تسلسل لنتائجه بطريقة متوافقة مع تطبيق .NET SOAP.

إذا سلكت الطريق الأخير، فإليك الطريقة:

...تبدو الفئات التي تم إنشاؤها ويبدو أنها تعمل بشكل طبيعي ، ولكن إذا نظرت إلى الصفيف المنحرف على جانب العميل (.NET/WCF) ، ستجد أن الصفيف قد تم تسويته بشكل غير صحيح ، وجميع القيم في الصفيف 0 .سيكون عليك النظر يدويًا إلى استجابة الصابون التي تم إرجاعها بواسطة Axis لمعرفة الخطأ ؛إليك استجابة عينة (مرة أخرى ، تم تحريرها للتوضيح):

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv=http://schemas.xmlsoap.org/soap/envelope/>
    <soapenv:Body>
        <doSomethingResponse>
          <doSomethingReturn>
            <doSomethingReturn href="#id0"/>
            <doSomethingReturn href="#id1"/>
            <doSomethingReturn href="#id2"/>
            <doSomethingReturn href="#id3"/>
            <doSomethingReturn href="#id4"/>
          </doSomethingReturn>
        </doSomethingResponse>
        <multiRef id="id4">5</multiRef>
        <multiRef id="id3">4</multiRef>
        <multiRef id="id2">3</multiRef>
        <multiRef id="id1">2</multiRef>
        <multiRef id="id0">1</multiRef>
   </soapenv:Body>
</soapenv:Envelope>

ستلاحظ أن المحور لا يولد القيم مباشرة في العنصر الذي تم إرجاعه ، ولكن بدلاً من ذلك يشير إلى العناصر الخارجية للقيم.قد يكون هذا منطقيًا عندما يكون هناك العديد من الإشارات إلى قلة قليلة نسبيًا من القيم المنفصلة ، ولكن بغض النظر عن ذلك ، لا يتم التعامل مع هذا بشكل صحيح بواسطة مزود WCF Basichttpbinding (ويقال إنه من خلال GSO و Classic .NET Web المراجع أيضًا).

استغرق الأمر مني بعض الوقت للعثور على حل:قم بتحرير ملف Server-config.wsdd الخاص بنشر المحور الخاص بك وابحث عن المعلمة التالية:

<parameter name="sendMultiRefs" value="true"/>

قم بتغييره إلى خطأ ، ثم إعادة النشر عبر سطر الأوامر ، والذي يبدو (تحت Windows) شيء من هذا القبيل:

java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient server-config.wsdl 

يجب الآن أن يكون استجابة خدمة الويب غير متزايدة من قبل عميل .NET الخاص بك.

وجدت هذا الرابط الذي قد يقدم بديلاً أفضل: http://www.tomergabel.com/GettingWCFAndApacheAxisToBeFriendly.aspx

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