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.


Thanks a lot Dude. You are a C# god! I won't tell anybody at Apache ;) I'll see about trying to get all this into my next WSDL.

Posted by Randy Charles Morin at

RSS 2 Atom XSLT

Here's an RSS 2.0 to Atom syntax XSLT that iM working on. The tough part was the date. If someone ever invents another date format, then send me their email address, I've got some friends who'll take care of them. Try it out and give me some...

Excerpt from iBLOGthere4iM at

Sam takes my Atom WSDL to another level. I guess he's directing my next move, which will be to take what he learned and incorporate it into my WSDL....

Excerpt from iBLOGthere4iM at

Sam,

For one, the title of this entry should be ATOM API, not AXIS API.

Secondly, I'm not sure what POST is supposed to do or why it's needed.

DB

Posted by Don Box at

My test server
[link]
Still some differences in our WSDL, I'll ping you later re: them.

Posted by Randy Charles Morin at

Don, the title has been fixed.  Thanks!

In some server applications, the client is permitted to assign URIs to new data.  In those contexts, PUT can also be used to create new content.  In other settings, the server reserves the right to assign URIs, in which case POST is needed.  Posting a comment is a typical example.

For more background, see DifferentlyAbledClients and CarrotVsOrange.

Posted by Sam Ruby at

I saw the text and thought "Oh my God!", then looked at the source and took off the noose.

That qname attibute ain't pretty though.

(btw, am I right in thinking the entryType class was autogenerated from the WSDL?)

Posted by Danny at

entryType, authorType, generatorType, contentType, Security, UsernameToken, passwordType, linkType, AtomAPI are all autogenerated from the WSDL. As well as the contentTypeMode enumeration.

The command to do this with the .Net SDK is:

wsdl.exe http://intertwingly.net/stories/2003/12/18/AtomAPI.wsdl

With WSE, the command appears to be WseWsdl instead.  Axis has WSDL2Java.  Other projects have similar functionallity.  With IDEs like VisualStudio or Eclipse, this can all be done from within the GUI.

Posted by Sam Ruby at

FYI, wss4j ([link]) supports both X509 profile and UserNameToken profile from WS-Security spec.

Posted by Davanum Srinivas at

Atom API via C#

Sam Ruby over at IBM is writing some C# code to call the Atom API via WSDL.... [more]

Trackback from The Scobleizer Weblog

at

Good news.  Qualified names will be removed from content in WSSE.

Posted by Don Park at

The glass is broken

MyCGIServer free offering has been discountinued. I have my own reasons to disregard their bargain prices, so this weblog and all related resources will be dismissed in the next few days....

Excerpt from Through the blogging-glass at

ATOM API WSDL and other acronyms

Quote: Via Sam Ruby (who built a small C# app based on the ATOM WSDL), we find Randy Charles Morin, who has created WSDL for ATOM. Atom, which, as it turns out, isn't an acronym for anything, is the heir-apparent to RSS....

Excerpt from iBLOGthere4iM at

Sam, I notice you are passing around the WSDL in this blog entry.

[link]

You might want to update to this one.

[link]

Or was there a reason you wanted to go w/ the older one?

If not, I think this one is slightly more correct, but not entirely. Maybe I'll put a few seconds into fixing it, so that all the Atom SOAP implementations don't end up broken. Blogger :(

P.S. I like the anti-SPAM beyond 30 days, track my IP thingy.

Posted by Randy Charles Morin at

Randy, I guess I lost track of which was the latest.  Could you do me a favor and add a simple pointer to OffWikiPages?

Posted by Sam Ruby at

Shall do this! Hopefully tonight. I'm also going to investigate the issues you brought up privately. In particular, this...

[link]

Posted by Randy Charles Morin at

Atom API: I Want My SOAP!

A discussion on the Atom Wiki should make it possible for clients that lack PUT and DELETE to fully implement the Atom API.  If folded in to the next revision of the API, this enhancement will make J2ME Atom API clients a...

Excerpt from Matt Croydon::postneo at

I've been trying this code with Blogger.com, no joy at all.

Blogger.com returns a SOAP fault with the following exception:

java.lang.ArrayIndexOutOfBoundsException: 7 at com.google.common.Base64.decode4to3(Base64.java:417)
at com.google.common.Base64.decode(Base64.java:573)
at com.google.common.Base64.decode(Base64.java:487)
at com.google.common.Base64.decode(Base64.java:433)
at com.pyra.blogger.WSSEAuthentication.<init>(WSSEAuthentication.java:133)
at com.pyra.blogger.AtomHandler.processSOAPRequest(AtomHandler.java:718)

I know my username/blogid/password are correct - everything from tcpTrace looks great. Any suggestions?

Posted by Jon Meyer at

The glass is broken

MyCGIServer free offering has been discountinued. I have my own reasons to disregard their bargain prices, so this weblog and all related resources will be dismissed in the next few days. Update: or maybe not, since Javalobby has come to the rescue....

Excerpt from Through the blogging-glass at

Hi I am trying a VB.NET version of the sample c# blog client provided by Sam.

how should the following line be written in VB.NET

blog.content[0].Any = new XmlNode[1];

i am not able to create a new XMLNode in VB.NET like that.
somebody please help.

Posted by Pradeep kumar at

Hi, Pradeep. To create any kind of Node (Element, Attribute, etc.) in the DOM, you need to have some kind of context. This context lies within the DOM itself, so to create an XML element, you write doc.CreateElement(..). The return from this method is your new element.

Posted by Asbjørn Ulsberg at

I tried using
xmldocument.CreateNode

but it says cast from xmlelement() to xmlnode is not possible.

it does not create a instance of xmlnode and the assignment to "Any" fails..

any ideas??

Posted by Pradeep Kumar at

That's why I said you should use 'CreateElement()' and not 'CreateNode()'...

Posted by Asbjørn Ulsberg at

Thanks for helping me out.

I tried ur suggestions.

CreateElement too returns an XmlElement object and it says invalid cast exception from XmlElement to XmlNode()

sam's example C# from [link]
Line 41:

blog.content[0].Any = new XmlNode[1];

VB.NET version that I tried
blog.content(0).Any = new XmlDocument().CreateElement("root")

The above code gave an InvalidCastException

How to initialize this "Any" member?

Posted by Pradeep Kumar at

The 'Any' property is an XmlNode array, so you first need to instanciate it:

blog.content(0).Any = new XmlNode[1];
And then you need to set the first index of the array to your element:
blog.content(0).Any(0) = doc.CreateElement(...);

Posted by Asbjørn Ulsberg at

Actually, the next line in the original C# code takes care of this.  The VB equivalent would be:

blog.content(0).Any(0) = d.DocumentElement

Posted by Sam Ruby at

That's right, Sam. I see that I'm mixing VB.NET and C# syntax as well. Bah! :-)

Posted by Asbjørn Ulsberg at

SampleClient.vb

To build:

wsdl /language:vb http://www.atomenabled.org/developers/api/AtomAPI.wsdl
vbc /r:System.Xml.dll /r:System.dll /r:System.Web.Services.dll SampleClient.vb AtomAPI.vb
Posted by Sam Ruby at

I'm working with the vb client example; but can't seem to get the userid password url combo to work.  For example at www.blogger.com user I assume to be my userid, password my password, but what is the url?  [link] doesn't work

Also, am I free to use the atom api in my code (which I want to sell)?

Any help would be appreciated.

Thanks, Rob

Posted by Rob at

I am trying to write a Java blogger client ,and use a WSDL2JAVA tool to generate stub .But how can I send an XmlElement object ?

Posted by Ray Chen at

hi there.
just wanted to know, how come the example
crashes when run against bloggers atom endpoint with 'you should supply a blogid' exception?

i've tried adding one in code.. (trying the integer blog number, and it's url) but with no success...

any ideas?

Posted by reflog at

Sam Ruby and Atom

Sam's got big ones ... working for IBM and actually using C#. But it's also clear that he knows the APIs inside out and outside in. He defintely makes my top 10 list for the year of folks who are helping to dramatically advance the state of the art. Sam Ruby: Atom API via WSDL...... [more]

Trackback from Occasionally Connected

at

AtomAPI

DaveJohnson created this page on Sat Jul 24 05:35:53 EDT 2004:AtomAPI The Atom API is a web services API for weblogging applications. See also Atom Atom4J AtomFormat WeblogAPIs MetaWeblogAPI BloggerAPI Resources The Atom API Specification...

Excerpt from RollerWiki at

Hello,

I am trying to write a client app that uses the Atom API to make posts to a blog on Blogger. Using the sample app by Sam Ruby and after customizing the .wsdl to point to "http://www.blogger.com/atom/", I get the following error when I try to post:

"The request failed with HTTP status 405: Method Not Allowed."

Anyone have any idea why?

Thanks!
Nathan

Posted by Nathan at

Hi Sam, I've just been trying some code based on this and I get the same error as Jon above - have you seen this before?

Posted by Danny at

It Just Doesn't Works

Danny Ayers: Tonight I planned to get to the bottom of problems I encountered last night (while tired), working on a minimal SOAP-based (WSDL-generated, C#) Atom client. My starting point was the marvellous material put forward by Sam and...

Excerpt from RSS at

Doesn't work.  I have VS.Net 2003.  I switch between username, userID, or my email address as the username trying to get this to work.  I either get a message that

"We're sorry but the Username/Password combination you've entered is either invalid or you don't have permission to access this Blog."

or

"This username/password combination is not valid. Please retry."

For the blogID, i'm using the id number of my blog.

Posted by Lewis Moten at

I am getting the same problem when I try calling blogger.  Does anyone know if this worked before and now not because of changes that maybe happenning at blogger?

Posted by Niels Hansen at

In my experience, this has never worked.

Posted by Randy Charles Morin at

This ATOM API doesn't work for me either when trying to post to blogger.com. Tried the C#/SOAP and build-by-hand ways. I guess no one tests this stuff. Build an API that doesn't work. Oh yea! <vent>"Build it and they will come... then pull their hair out trying to decipher java stack traces and leave."</vent>

Posted by John at

My stubbornness overcame my apathy and laziness and I googled enough to find enough information to get the C#/WSDL example code to supposedly successfully post (return code 201) to a blogger blog on blogpost.com.

The downside is that you won't be able to edit your blog via blogger's web interface not will you be able to republish your blog.

Unless you want to freeze your blog in time, this is not a feature.

So I'll wait until the blogger folks get their act together before I post the necessary diffs to the C#/WSDL sample code.

Posted by John at

Sam Ruby: Atom API via WSDL

Sam Ruby: Atom API via WSDL...

Excerpt from Peter's Kommentare at

Excuse me, could any one here mind guiding me along? i am currenly doing a pocket blogger application using C# and i found this coding very useful for me. i have it’s reference downloaded as well, however, there is this error kept coming out after i have deploy it in the emulator. the error msg shows “System.TypeLoadException”. i don’t understand how to debug that’s why i’m stuck here.

isit something that i need to add before this coding? like the namespace must be the same as reference? or i need to have something "using classname: referenceName"?

________________________________________________________
Tortuga.Blogger blogger = new Tortuga.Blogger();
 
blogger.LoginName = “login”;
blogger.Password = “password”;
 
bool ok = blogger.Login();
if (!ok)
{
  return;
}

// Find the blog by name.
Tortuga.Blog blog = blogger.GetBlogByTitle("Testing");
if (blog == null)
{
  // Not found...
  return;
}
 
// Create a BlogPost object.  
Tortuga.BlogPost post = new Tortuga.BlogPost();

post.Title = “Test Blog Post from C# Program”;
post.Content = “This was posted by a C# application using the Tortuga Blogger API”;

ok = blog.UploadNewPost(post);
if (!ok)
{
  MessageBox.Show("Failed to upload new post!");
  return;
  }
 
// Get the URL for the post just created.
MessageBox.Show(blog.UploadedPostUrl);

__________________________________________________

thank you

Posted by le shao at

Add your comment