Контракты WCF — пространства имен и исключения SerializationException

Я использую сторонний веб-сервис, который предлагает следующие вызовы и ответы

http://api.athirdparty.com/rest/foo?apikey=1234

<response>
  <foo>this is a foo</foo>
</response>

и

http://api.athirdparty.com/rest/bar?apikey=1234

<response>
  <bar>this is a bar</bar>
</response>

Это контракт и вспомогательные типы, которые я написал

[ServiceContract]
[XmlSerializerFormat]
public interface IFooBarService
{
    [OperationContract]
    [WebGet(
        BodyStyle = WebMessageBodyStyle.Bare,
        ResponseFormat = WebMessageFormat.Xml,
        UriTemplate = "foo?key={apikey}")]
    FooResponse GetFoo(string apikey);

    [OperationContract]
    [WebGet(
        BodyStyle = WebMessageBodyStyle.Bare,
        ResponseFormat = WebMessageFormat.Xml,
        UriTemplate = "bar?key={apikey}")]
    BarResponse GetBar(string apikey);
}

[XmlRoot("response")]
public class FooResponse
{
    [XmlElement("foo")]
    public string Foo { get; set; }
}

[XmlRoot("response")]
public class BarResponse
{
    [XmlElement("bar")]
    public string Bar { get; set; }
}

и тогда мой клиент выглядит так

static void Main(string[] args)
{
    using (WebChannelFactory<IFooBarService> cf = new WebChannelFactory<IFooBarService>("thirdparty"))
    {
        var channel = cf.CreateChannel();
        FooResponse result = channel.GetFoo("1234");
    }
}

Когда я запускаю это, я получаю следующее исключение

Невозможно десериализовать тело XML с корневым именем «response» и корневым пространством имен «(для операции «GetFoo» и контракта («IFooBarService», «http://tempuri.org/')) с помощью XmlSerializer. Убедитесь, что тип, соответствующий XML, добавлен в коллекцию известных типов службы.

Если я закомментирую операцию GetBar из IFooBarService, она будет работать нормально. Я знаю, что мне не хватает важной концепции здесь - просто не знаю, что искать. Как правильно построить типы контрактов, чтобы их можно было правильно десериализовать?


person kenwarner    schedule 10.03.2010    source источник


Ответы (2)


Я бы сказал, что ваш сторонний сервис сильно сломан. Здесь происходит конфликт пространств имен — есть два элемента с именами response, но с разными типами схемы XML.

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

Вам останется только сделать это вручную. LINQ to XML удобен для этой цели.

person John Saunders    schedule 12.03.2010
comment
поэтому, хотя в моем контракте указано, что GetFoo возвращает FooResponse, он не будет пытаться использовать этот тип? - person kenwarner; 12.03.2010
comment
@qntmfred: следует предположить, что GetBar никогда не вернет FooResponse. Учитывая, что службе достаточно легко возвращать разные элементы для каждого ответа, я не виню .NET за то, что она не сделала такого предположения. - person John Saunders; 12.03.2010

Вы можете попробовать с классом ответа следующим образом:

[XmlRoot("response")]
public class Response
{
    [XmlElement("foo")]
    public string Foo { get; set; }

    [XmlElement("bar")]
    public string Bar { get; set; }
}
person Matej    schedule 09.11.2011