Почему не .NET десериализации мой примитивный массив из веб-сервиса?

голоса
4

Помогите! У меня есть веб-сервис компании Axis, которая потребляется в C # приложение. Все работает отлично, за исключением того, что массивы длинных значений всегда попадались, как [0,0,0,0] - нужная длина, но значения не десериализации. Я попытался с другими примитивов (Интс, удваивается), и то же самое происходит. Что я делаю? Я не хочу, чтобы изменить семантику моей службы.

Задан 27/08/2008 в 14:53
источник пользователем
На других языках...                            


3 ответов

голоса
6

Вот что я закончил с. Я никогда не нашел другое решение там для этого, так что если у вас есть что-то лучше, всеми средствами, внести свой вклад.

Во-первых, долгое определение массива в WSDL: области типов:

  <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]));
    }

Это исправление давно специфична, но это, вероятно, может быть обобщена для обработки любого примитивного типа, имеющий эту проблему.

Ответил 27/08/2008 в 14:54
источник пользователем

голоса
3

Вот более или менее копия вставили версия блоге я писал на эту тему.

Краткое содержание: Вы можете изменить способ .NET десериализует набор результатов (см решения Криса выше), или вы можете перенастроить ось сериализовать свои результаты таким образом, который совместит с реализацией .NET SOAP.

Если вы идете последний маршрут, вот как:

... сгенерированные классы выглядят и появляются нормально функционировать, но если вы будете смотреть на десериализованный массив на клиенте (/ WCF .NET) стороны вы увидите, что массив был десериализован неправильно, и все значения в массив равен 0. Вы должны вручную просмотреть ответ SOAP, возвращаемый осью, чтобы выяснить, что случилось; вот ответ образец (опять же, отредактированы для ясности):

<?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 (и, по сообщениям по gSOAP и классические ссылки .NET веб-а).

Это мне потребовалось некоторое время, чтобы найти решение: редактировать серверную config.wsdd файл развертывания компании Axis и найти следующий параметр:

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

Измените его на ложь, а затем перебросить через командную строку, которая выглядит (под Windows) что-то вроде этого:

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

Теперь ответ веб-служба должна быть deserializable вашим клиентом .NET.

Ответил 16/03/2009 в 13:39
источник пользователем

голоса
1

Найдена эта ссылка , которая может предложить лучшую альтернативу: http://www.tomergabel.com/GettingWCFAndApacheAxisToBeFriendly.aspx

Ответил 20/02/2009 в 18:17
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more