Возврат сложного типа из его представления XML в веб-сервисе .NET - PullRequest
1 голос
/ 24 апреля 2009

У меня есть XML-документ в базе данных, представляющий собой сериализованное XML-представление экземпляра определенного класса Foo:

<?xml version="1.0" encoding="utf-16"?>
<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  <StringProp>hello</StringProp>
  <IntProp>5</IntProp>
</Foo>

Предположим, теперь я хочу написать метод веб-службы ASP.NET, который возвращает экземпляр Foo, например:

[WebMethod]
public Foo GimmeFoo()
{
}

Вопрос: я хочу вернуть сериализованный Foo, но без предварительной десериализации его в методе GimmeFoo () (Foo в реальной жизни довольно большой, и было бы глупо десериализовать его из БД, чтобы вскоре после этого она автоматически повторно была повторно сериализована феями SOAP.

Есть ли какой-либо атрибут, который я могу присвоить веб-службе (или какой-то код, который я могу написать в его теле), который позволяет мне отправлять экземпляр Foo без предварительной десериализации его?

Ответы [ 3 ]

1 голос
/ 24 апреля 2009

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

На мой взгляд, если это так, то почему бы просто не иметь REST-сервис, который будет передавать данные обратно, поскольку вы не используете веб-сервис правильно, IMO. Например, если я буду использовать GSOAP (на C) или PHP для работы в качестве клиента, будет ли полезен ваш xml-файл, поскольку мне нужно будет его десериализовать самостоятельно.

Десериализация может быть затруднена, а затем повторная инициализация веб-службы, но IMO, опять же, правильный путь, если вам нужно использовать веб-службу.

Кроме того, у вас будет очень сильная связь между клиентом и сервером, если вы вернете этот сериализованный XML-файл, что, опять же, IMO, плохой дизайн.

0 голосов
/ 24 апреля 2009

Я нашел способ, который может быть не самым элегантным, но выполняет свою работу. Идея состоит в том, чтобы делегировать all работу пользовательскому классу, производному от SoapExtension, и фактически ничего не делать в самом WebMethod - WebMethod как конечная точка для вызова:

[WebMethod]
public Foo GimmeFoo()
{
     return null;
}

Но вот волшебство: вы пишете SoapExtension, которое перехватывает весь трафик SOAP, и, когда наступает этап SoapMessageStage.AfterSerialize, вы добавляете туда уже сериализованную полезную нагрузку:

public class SerializationPassThrough : SoapExtension
{
    private Stream oldStream;
    private Stream newStream;

    // Other overrides...

    public override void ProcessMessage(SoapMessage message)
    {
        switch (message.Stage)
        {
            case SoapMessageStage.BeforeSerialize:
                // ...
                break;
            case SoapMessageStage.AfterSerialize:
                string newOutput = ReadPreCookedResponseFromDB();
                RewriteOutput(newOutput);
                break;
            case SoapMessageStage.BeforeDeserialize:
                // ...
                break;
            case SoapMessageStage.AfterDeserialize:
                // ...
                break;
            default:
                throw new Exception("invalid stage");
        }
    }

    private void RewriteOutput(string output)
    {
        newStream.Position = 0;
        StreamWriter sw = new StreamWriter(newStream);
        sw.Write(output);
        sw.Flush();
        newStream.Position = 0;
        Copy(newStream, oldStream);
        newStream.Position = 0;
    }

    private void Copy(Stream from, Stream to)
    {
        TextReader reader = new StreamReader(from);
        TextWriter writer = new StreamWriter(to);
        string toWrite = reader.ReadToEnd();

        writer.WriteLine(toWrite);
        writer.Flush();
    }

}

Последний штрих: вам нужно указать среде выполнения ASP.NET использовать SoapExtension. Вы можете сделать это через атрибут в WebMethod или в web.config (что я и сделал):

<system.web>
  <webServices>
    <soapExtensionTypes>
       <add type="SoapSerializationTest.SerializationPassThrough, SoapSerializationTest" priority="1" />
    </soapExtensionTypes>
  </webServices>
<system.web>

Исходные примеры кода, из которых я получил эти фрагменты, находятся по адресу http://msdn.microsoft.com/en-us/library/7w06t139(VS.85).aspx.

0 голосов
/ 24 апреля 2009

Вы можете вернуть типы XmlElement или XmlDocument из веб-службы. Просто верните ваш сериализованный XML.

...