views:

244

answers:

1

I am using a third party web service that offers the following calls and responses

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

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

and

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

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

This is the contract and supporting types I wrote

[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; }
}

and then my client looks like this

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

When I run this I get the following exception

Unable to deserialize XML body with root name 'response' and root namespace '' (for operation 'GetFoo' and contract ('IFooBarService', 'http://tempuri.org/')) using XmlSerializer. Ensure that the type corresponding to the XML is added to the known types collection of the service.

If I comment out the GetBar operation from IFooBarService, it works fine. I know I'm missing an important concept here - just don't know quite what to look for. What is the proper way to construct my contract types, so that they can be properly deserialized?

A: 

I'd say your third-party service is badly broken. There's a namespace collision here - there are two elements named response but with different XML Schema types.

I think you're going to have to not use any .NET technology that involves deserializing this XML. There would be no way to tell .NET into which .NET type to deserialize the XML.

You'll just have to do it by hand. LINQ to XML is handy for this purpose.

John Saunders
so even though my contract says `GetFoo` returns a `FooResponse`, it won't try to use that type?
qntmfred
@qntmfred: It would have to assume that `GetBar` will never return a `FooResponse`. Given that it's easy enough for a service to return different elements for each response, I don't fault .NET for not making such an assumption.
John Saunders