intertwingly

It’s just data

Atom API via WSDL


I've written a small C# app to use the WSDL that Randy has been writing/coordinating.  A few small changes to the WSDL were required to get this to a clean compile (try compiling the app with the original WSDL to see what was needed, then try this one).  On top of that, a bit more changes were required to get it to produce a recognizable request.  The latter changes are the subject of this blog entry.

If you look at the app, it starts out simply enough.  Get a few parameters from the command line.  Create a blog entry.  Fill in some fields.  Set issued to DateTime.Now... and let all the pesky serialization and marshalling details be taken care of for you.  Sweet.

Nested structures and attributes are no problem.  Those map to strongly typed datastructures.  If you use an IDE, you can even get Intellisense.  The content element is pretty straightforward... with the XMLDocument class doing all the heavy lifting.  You even get an enumeration for the mode attribute, so this value can be checked at compile time.

Then you get to the Username Token header.  At this point, there are a number of choices.

If you are have WSE installed, the choice is easy.  You can take advantage of the Username token support that is already built in.  Get the SoapContext, add the Token, and away you go.  Here's some sample listings.

Oh, and if you aren't using Microsoft.Net, Axis has a similar handler.  Use it.  And if you aren't using Axis, then find out how your platform vendor supports this, and use their recommendation.

As you might have guessed by now, I didn't go that way.

Your next choice is to build the XMLNodes using XMLDocument, much like I did for content, and provide that for the header.  This isn't all that difficult, but you do lose the benefits of having the generated classes, IDE, and the like.  This may seem like a stark choice, but it is important to know that it is available.

And as you might have guessed again, I didn't go that way either.  Warning: there be dragons ahead.

Building the security header using the generated classes starts out pretty simple.  There are System classes that provide things SHA1 cryptography support, and base64 encoding.  All that is left is to fill in the fields.

The first sign of trouble comes in with the computation of the hash.  This requires that you know what the value of the created element is.  By that, I don't mean the date, but actual characters that this date will be serialized as.  Remember all those pesky serialization and marshalling details that are taken care of for you?  Well, now they matter.  You need to know what time zone and what fractional seconds the runtime will provide for you, before this all is serialized and sent over the wire.

One way to regain control is to simply declare this one element as a string.  It isn't that hard: ToString("u") pretty much does the right thing anyway.  I say pretty much, as it uses a space instead of a "T" as a separator, but one call to Replace and this is cleaned right up.

First problem down, now onto the second one.  This is the gnarly one.

Password Type is supposed to be wsse:PasswordDigest.  In XML jargon, that's called a qualified name, or a qname for short.  Ask Mark Nottingham, he maintains that qnames are evil.  He's got a point.

Here, the problem is similar.  The prefix "wsse" needs to be declared to map to a specific namespace.  The name of the prefix doesn't matter, what it maps to does.  That would be fine, but this is another one of those pesky administrative details that the tooling takes care of for you.  Except that it doesn't know about this usage as it is "tunneled" inside an attribute.

I hate it when abstractions leak this way.

The first workaround I tried was declaring an attribute named "xmlns:wsse" in the WSDL, but .Net is too smart.  This attribute is simply eaten.

The second workaround I had better luck with.  I declared that this element supported anyAttribute and then procedured to construct a specific attribute with the correct prefix in the code.  The name of this attribute doesn't much matter as it merely is a ruse to get the namespace prefix declared.

This seems to work.  Now I produce a recognizable request. 

Onto debugging...

Summary: if you have the opportunity to use WSE or Axis, then removing the security header from the WSDL is the way to go.  Otherwise, The above looks to be one means to get the job done using the version of .Net that is available on Windows Update.