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

Используйте

document.getElementById("file-id").files[0].name; 

вместо

document.getElementById('file-id').value
5
задан Chris Marasti-Georg 27 August 2008 в 17:23
поделиться

3 ответа

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

Во-первых, длинное определение массива в 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]));
    }

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

7
ответ дан 13 December 2019 в 19:40
поделиться

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

1
ответ дан 13 December 2019 в 19:40
поделиться

Вот более или менее вставляемая копией версия сообщения в блоге, которое я записал на предмете.

Резюме: можно или изменить способ, которым.NET десериализовывает набор результатов (см. решение Chris выше), или можно реконфигурировать Ось для сериализации ее результатов способом, это совместимо с реализацией SOAP.NET.

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

... сгенерированные классы смотрят и, кажется, обычно функционируют, но если Вы посмотрите на десериализованный массив на клиенте (.NET/WCF) сторона, Вы найдете, что массив был десериализован неправильно, и все значения в массиве 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 развертывания Оси и найдите следующий параметр:

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

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

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

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

3
ответ дан 13 December 2019 в 19:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: