WCF interoperability in the real world (eBay)

Service Station, by Aaron Skonnard

Syndication

A few weeks ago I was teaching our WCF course at a client site and I decided to do an example of real-world interoperability by having a WCF client application integrate with the eBay SOAP API.
 
Little did I know at the time how much fun awaited me.
 
After acquiring the necessary eBay sandbox test account, authentication tokens, and official WSDL definition, I was ready to rock 'n roll.
 
You can quickly tell how huge the eBay API is by looking at the size of the WSDL file, which comes in at 2.37 MB (yes, MB!). If you try to open it in Internet Explorer, the XSLT transformation will take forever to finish, if it finishes at all due to the sheer size of the document. But hey, eBay is a real-world retail application with lots of bells and whistles and they've tried to expose the whole beast. However, due to the size, I was a little worried about svcutil.exe's ability to handle it. But to my surprise, it chewed it up and spit out the necessary proxy code and some configuration elements. Now I was ready to write some code.
 
For my first test, I set my expectations low and chose to use the GeteBayOfficialTime operation, which simply requests the official time from the eBay server (which is important in a real-time auction system). I was expecting to be able to instantiate the proxy class and invoke the method, but as it turns out, each eBay SOAP operation requires a distinct URL where the method name and authentication tokens are contained in the URL. Here's an example of how you build the request URL:
 
string endpoint = "https://api.sandbox.ebay.com/wsapi";
string callName = "GetebayOfficialTime";
string siteId = "0";
string appId = "..."; // use your app ID
string devId = "..."; // use your dev ID
string certId = "..."; // use your cert ID
string version = "405";
 
// Build the request URL
string requestURL = endpoint
+ "?callname=" + callName
+ "&siteid=" + siteId
+ "&appid=" + appId
+ "&version=" + version
+ "&routing=default";
 
Now I have enough to instantiate the proxy class supplying requestURL for the address:
 
eBayAPIInterfaceProxy proxy = new eBayAPIInterfaceProxy(
"eBayAPI", requestURL);
 
The "eBayAPI" string is the name of the client endpoint configuration generated by svcutil.exe. It gives you a basicHttpBinding configuration using transport security (HTTPS).
 
It feels weird to general a unique URL for each operation within a service, and it quickly becomes tedious from the developer perspective. While this may be the norm in RESTful applications, in SOAP the URL typically identifies the service and the action identifies the operation, which the proxy can easily handle for you.
 
Now if you look at the signature for GeteBayOfficialTime, you'll also notice that it requires you to supply two objects: a CustomSecurityHeaderType and a GeteBayOfficalTimeRequestType. The eBay security design relies on transport-based security (HTTPS) to secure the entire channel, so it wants you to pass the application credentials within the SOAP body -- they don't use any WS-Security techniques.
 
Here's an example of how you can build both of these objects for use in the method:
 
CustomSecurityHeaderType creds = new CustomSecurityHeaderType();
creds.eBayAuthToken = "..."; // use your token
creds.Credentials = new UserIdPasswordType();
creds.Credentials.AppId = appId;
creds.Credentials.DevId = devId;
creds.Credentials.AuthCert = certId;
 
GeteBayOfficialTimeRequestType request =
new GeteBayOfficialTimeRequestType();
request.Version = version;
 
With this in place, you're ready to invoke the operation as shown here:
 
GeteBayOfficialTimeResponseType response =
proxy.GeteBayOfficialTime(ref creds, request);
Console.WriteLine("The time at eBay headquarters is:");
Console.WriteLine(response.Timestamp);
 
Once I understood how the eBay API worked (which was a bit counterintuitive given my understanding of SOAP), I was able to get the correct code in place and I was sure it would work.
 
But the SOAP Gods weren't going to let me off the hook so easy.
 
When I ran the code, I kept getting a helpful "Internal Server Error" message. Great, now I know something went wrong over in eBay Land but I have no idea what. So I pinged the MS interop expert, Kirill, who suggested that it might be the HTTP Content-Type header tripping things up (he had seen this before in a sample he did). It turns out that eBay fails if the charset value is enclosed in quotes as shown here:
 
Content-Type: text/xml; charset="utf-8"
 
They only accept the no-quotes version:
 
Content-Type: text/xml; charset=utf-8
 
Hmmm… ok, so how did I fix that within my WCF client? The charset value is a property emitted by the message encoder so the easiest way to fix this is to inject a custom text message encoder that doesn't include the quotes. I pulled up the WCF SDK to look for a sample and viola, there's actually a sample text message encoder in there -- and it doesn't include quotes around charset -- so I was able to use it as-is. In order to use the custom message encoder, I had to create a custom binding as shown here:
 
HttpsTransportBindingElement https = new HttpsTransportBindingElement();
https.MappingMode = HttpMappingMode.Soap;
CustomBinding bind = new CustomBinding();
bind.Elements.Add(new CustomTextMessageBindingElement(
   "utf-8", "text/xml", MessageVersion.Soap11WSAddressing10));
bind.Elements.Add(https);
 
It's important to note that setting the MappingMode to HttpMappingMode.Soap is very important because if you don't, the default for the HttpsTransportBindingElement is to use HttpMappingMode.SoapWithWsAddressing. And guess what, WS-Addressing also causes eBay to fail. I had to learn this one the hard way too. Anyway, now I can supply the custom binding when creating the proxy:
 
eBayAPIInterfaceProxy proxy = new eBayAPIInterfaceProxy(
bind, new EndpointAddress(requestURL));
 
With all of this in place, I was finally able to make the call work. Phew.
 
A few observations:
  • eBay has a wacky design for a SOAP API. It feels like they designed it primarily for non-SOAP use and then did a retro-fit. The addressing and security mechanisms are a few manifestations of this.
  • Interoperability in the real-world is hard no matter how you shake it. And in order to work through issues you have to understand your SOAP stack (in this case WCF) before you can extend/tweak it (e.g., introducing the custom message encoder into the WCF proxy is not a trivial matter). You also have to understand what's happening on the wire (e.g., the charset & WS-Addressing issues). The Law of Leaky Abstractions rings true, loud and clear, when looking at this type of example.
  • WCF is extremely flexible. It provides all of the necessary programming model options and extensibility points that we needed to work through these issues - a great tribute to its design.
 
I'm afraid that interop snags like these will be more the norm than the exception over the next several years as the dust continues to settle around the various SOAP and WS-* profiles. However, if you're using a good stack, and understand how things work, you can get around them.
 

Posted Apr 18 2006, 12:41 PM by Aaron Skonnard
Filed under: ,

Comments

Mike Parsons wrote re: WCF interoperability in the real world (eBay)
on 04-18-2006 11:11 AM
Hey Aaron ... good observations. Here are a few of mine ...

1.) Shouldn't this complexity/difficulty trigger the question ... "Where have we gone wrong with all this SOAP/Web Services/WCF, etc stuff"? We have taken a problem that should be trivial to solve (get some data from eBay) and turned it into something that requires a technology as complicated as WCF (insert Axis or whatever SOAP framework here) to address.
2.) Why is it we (application developers) accept this complexity as a cost of doing business? Are we not enabling this complexity?
3.) Why is it we tout complexity as flexibility (to quote you ... "WCF is extremely flexible")?
4.) If a consumer were forced to jump thru these hoops to get something to work (i.e. an appliance, etc), they would simply return it to the vendor.

I am not singling out WCF here as the eBay API is just as culpable. Unless we,as an industry, don't address these complexities, I fear that the problems of interoperability will only get worse.
Aaron Skonnard wrote re: WCF interoperability in the real world (eBay)
on 04-18-2006 11:29 AM
Real-world integration/interoperability has always been one of the most costly, troublesome, and complex areas of IT. It's probably the #1 problem for most large enterprises, in terms of cost and just getting things to work.

So to answer your questions, putting the technology aside, the problem we're trying to solve is incredibly complex in and of itself. I realize that some scenarios are much simpler than others, but the more code you have (especially legacy) the harder it gets.

This leads to complicated solutions (some are more compicated than others). We also have the whole SOAP vs. REST/POX debate that causes vendors (like eBay) to scratch their heads and hedge bets on what's going to work best for them. But it doesn't always work best for everyone else (like us in this case).

In general, if your problem space is simple, most of today's SOAP stacks and their corresponding solutions are pretty simple. But once you start doing things that maybe weren't meant to happen (like eBay + SOAP), you start to see some ugly side effects.

However, I do agree that simpler is always better. But when start looking at building an asynchronous pub/sub architecture that uses a combination of queues, reliable messaging, transactions, and message-based security, you might find WCF to be simple after all. ;-)
Mike Parsons wrote re: WCF interoperability in the real world (eBay)
on 04-18-2006 12:19 PM
I would assert that the reason why "Real-world integration/interoperability" is costly, troublesome and complex is because we have made them complex via our usage/implementation of technologies.

I think that in most cases, the problem space is simple, we just add complexity because solving simple problems is not nearly as much "fun" for software engineers :-)

If we spent as much time innovating around solving "simple" problems (which I would assert is 80+% of the case) as we do on solving the "complex" problems, then I believe the intented consumers of our technology would be so much better off.
Aaron Skonnard wrote re: WCF interoperability in the real world (eBay)
on 04-18-2006 1:23 PM
Your point is surely true to some degree but from what I've experienced, the main reason integration/interop is so complex is because most systems/applications were not designed with integration/interop as a design goal/requirement. It's an afterthought.

It's the "services" trend that has promoted thinking about integration/interop earlier in the design process. And it's the fact that there are so many different flavors of technology and applications out there (some of which are too complex for their own good -- your point) that complicates matters further and makes the general requirement difficult to achieve.
Blat wrote re: WCF interoperability in the real world (eBay)
on 04-18-2006 4:45 PM
Doesn't sound that bad really. Try making a DCOM call to Ebay from linux by contrast. SOAP is much easier. Is it seamless? Hell no but it's close.
Christopher Steen wrote Link Listing - April 18, 2006
on 04-18-2006 9:32 PM
"Atlas" Toolkit - Using an Image in a
CollapsiblePanelExtender [Via: Robert
McLaws ]
A few thoughts...
brad wrote re: WCF interoperability in the real world (eBay)
on 04-19-2006 5:43 AM
We use the eBay SOAP API in a production environment via standard asmx clients and it works fine (other than the gigantic WSDL and bizarre complex type problems). Maybe you should revert back to the old soap stack :-). I have some serious concerns as to how the WCF client is going to interop when we try to start using it against all the ugly API's we hit, including: eBay, Amazon Merchants@, Yahoo, Google Adwords API, etc etc. As you said though, the ability to tweak and customize is key. In some cases we just post raw soap as XML and forget about trying to do proxies.
Mike Parsons wrote re: WCF interoperability in the real world (eBay)
on 04-19-2006 10:04 AM
I've been doing some more thinking on this and have a radically simply idea ...

Since most application are approximately 80% data reads, then why don't we just provide the data in a format that the consumer can use immediately without this whole SOAP Proxy business. Converting data to multiple formats is pretty simple with XSL and most vendors certainly have the horsepower to do some simple transformations.

So my recommendation is that we have a simple URL format along the lines of ...

http://someserver/endpoint/getdata.aspx?param1=value1&paramN=valueN&format=dataformat

For example,

http://www.eBay.com?getData.aspx?key=mykey&method=GeteBayOfficialTime&format=ADOXML

where format could be

ADOXML
ADO.NetDataSet
PLAINXML
XMLWITHSCHEMA
JSON
TABDELIMITED

and so on ...


Then I could walk up to any client technology and so something as simple as

VBA Client
***********
Dim oRS as New Adodb.RecordSet
oRS.open "http://www.eBay.com?getData.aspx?key=mykey&method=GeteBayOfficialTime&format=ADOXML"

Ditto for .Net Client or Java or whatever.

The Data would be immediately consumable in the Consumer's technology of choice.

We could even start a community effort to create standard XSL transforms for "de facto standard" data formats.

I have to believe that making it this simple would encourage far more interest in Web Services and hence more exciting applications/integrations



Aaron Skonnard wrote re: WCF interoperability in the real world (eBay)
on 04-19-2006 10:43 AM
You should check out the REST models out there -- they are basically what you want.

A few observations:
1) This completely ties your solution to HTTP.
2) You have to rely on HTTP extensions for any additional protocols you want to implement (security, reliable messaging, transactions).
3) You can't supply 'structured' data in the query string (you're stuck w/name=value).

Nevertheless, there are plenty of solutions out there that work the way you describe because they don't care about these limitations. It's not far off from RSS, which is extremely prevalent.
Mike wrote re: WCF interoperability in the real world (eBay)
on 04-19-2006 12:01 PM
Just curious... why the use of the "ref" keyword passing the credentials to the getOfficialTime method?



Mike Parsons wrote re: WCF interoperability in the real world (eBay)
on 04-19-2006 12:18 PM
I see RSS/ATOM going down the same road as SOAP in that nobody implements it the same way and you have to write a crap load of code on the consumer side (i.e. proxies) to "effectively" consume it.

The nice thing about getting the data in a "de facto" standard format is that I can eliminate all this proxy business and just use technologies that already exist on the client (be it .Net, Java, VBA, JavaScript, Ruby or whatever) and which application developers are already familiar with. Also, applications themselves can readily consume these endpoints without any coding (i.e. Excel->Data->Import External Data->New Web Query)


I agree with your comments that this solution ties you to the somewhat "limited" HTTP but I figure that's the way the world is going anyway ... no? Seems like we have been able to piggyback on HTTP to do some interesting stuff (i.e. VOIP, eCommerce, etc). Sometimes being "constrained" by a technology results in the most innovative solutions ... I mean look at all the cool and useful (i.e. GMAIL) apps being developed around the AJAX set of technologies.

I am not suggesting that we can eliminate the use of technologies like WCF, SOAP but I wonder if we cannot solve many of the problems addressed by these technologies in a much more simplistic and useful fashion.

It's just that the consumption of these technologies (i.e the learning curve, the deployment requirements, etc) is prohibitive to actually getting any "real work" done and providing benefit to the user.

BTW Aaron .. thanks for keeping this thread going :-)
Mike Parsons wrote re: WCF interoperability in the real world (eBay)
on 04-20-2006 12:53 PM
I think this confirms my last point about RSS/ATOM ...

http://code.google.com/apis/gdata/protocol.html
Kirk Allen Evans' Blog wrote Web Service Geek? Go Read Pluralsight's blogs
on 04-20-2006 6:11 PM
I like to write in my blog, but I hardly read other blogs anymore.  In fact, I don't have an aggregator...
Jason Haley wrote Interesting Finds
on 04-21-2006 3:58 AM
Kevin Amerson wrote re: WCF interoperability in the real world (eBay)
on 04-21-2006 12:34 PM
I like to say that the complexity is there because its human nature. The laws governing physics for instance are pretty simple, mainly because we don't control them, we can't argue over them ;).

Give software another 50 years and we'll probably have some standardization, many of the arguments going on will fade away or be solved.
mattonsoftware.com wrote .NET Resources
on 05-06-2006 2:35 AM
The following links to .NET resources have been collated over time with the assistance of colleagues. ...
PB wrote re: WCF interoperability in the real world (eBay)
on 07-24-2006 3:10 PM
Have you tried interop with wsHttpBidning.I mean I have a WCF host(Cosnole application) and when I have the binding as basicHttpBinding then I am able to generate the wsdl without any problem , but as soon as I changed the binding to wsHttpBinding then i get the following error..

**********error description ***************

Warning: This web reference does not conform to WS-I Basic Profile v1.1.
SOAP 1.1 binding was not found: WS-I's Basic Profile 1.1 consists of implementat
ion guidelines that recommend how a set of core Web services specifications shou
ld be used together to develop interoperable Web services. For the 1.1 Profile,
those specifications are SOAP 1.1, WSDL 1.1, UDDI 2.0, XML 1.0 and XML Schema.

********************************************
NathanA's Web Services Blog wrote WCF and eBay
on 10-12-2006 11:25 AM
eBay provides a very rich, though very complicated, SOAP API . It is possible to use WCF with eBay, but

Add a Comment

(required)  
(optional)
(required)  
Remember Me?