January 2008 - Posts

More BlogApi fixes....All done now I think

Anyone who's interested can get the latest version here.

I've been dogfooding this one with Windows Live Writer, and found and fixed a variety of bugs that were preventing the two from working together in peace and happiness etc.

I've tested adding a post, editing a post, including categories (which was one of the sources of trouble), retrieving recent posts, retrieving one of those posts for editing, and uploading images. I now have working implementations of all of these scenarios, and WLW now has no trouble with them.

So I'm reasonably confident in saying that after some embarrassing hiccups, niftiness has finally been achieved.

BlogApi fix

I just discovered a bug in my code for the MetaWeblog API getRecentPosts command - I was passing postId (which in this case is naturally empty) to the implementation method rather than blogId. So embarrassing.  Lucky nobody was actually using it :-)

The updated code can be found here.

I discovered this one since I'm writing an implementation for my own web site which I'm currently putting through its paces.
Other than that stupid, stupid little slip it's coming on quite well.

MetaWeblog API library for .NET 3.5 (esp. WCF)

Technorati Tags: MetaWeblog API, .NET, WCF

[UPDATE 14/01/2008: A new version of the code is now available with numerous (OK, several) bug fixes, following testing in the real world]

The clock is about to tick over into 2008 here in Godzone, and all over the country happy drunks are merrily beating each other senseless. I can already hear local members of the knuckle-walking community cheerfully grunting to one another in what passes for a greeting among those of us whose ancestors spent insufficient time banging the rocks together...(I can think of no better way to start the new year than to insult 90% of the population. It'll save time later)

But I myself am sadly once more slaving over a hot keyboard. At least for a few more minutes (I have however marked the occasion by cracking open a Stella. But I digress). The reason I'm posting at this late hour is to make available the first version of a library I've written for Blog servers to work with the MetaWeblog API (as I've said before, I loathe XML-RPC, but you have to be pragmatic about these things). This means that you can enable your blog (if it doesn't have such support already) to work with tools such as Windows Live Writer. Which is nifty.

The idea is that you grab the aforementioned code from here, write a class implementing the IBlogProvider interface (I don't like using the -Provider name for something that isn't an ASP.NET Provider, but I couldn't think of anything better), and use said class to mediate between your data store (and if appropriate, file system) and the MetaWeblog-parsing-and-regurgitating code which is abstracted away into the MetaWeblogManager class. The library defines a few data structures such as BlogInfo, UserInfo, CategoryInfo and BlogEntry to enable complex data to be passed back and forth between MetaWeblogManager and its BlogProvider (the class you'll write to implement IBlogProvider) without the latter having to deal with or know about XML-RPC gunk.

Please note that this library requires .NET 3.5, as it relies heavily on LINQ to XML (and as you can see the following implementation bits use 3.5 as well).

It's designed to work with WCF 3.5 SOAP-less services, but could be made to work with something like an HttpHandler as well with a little extra code to convert between XElements and Request/Response stream content.

An example WCF contract looks like this:

using System.ServiceModel;
using System.ServiceModel.Web;
using System.Xml.Linq;

[ServiceContract]
public interface IBlogService
{

    [OperationContract]
    [WebInvoke(BodyStyle = WebMessageBodyStyle.Bare,
        RequestFormat = WebMessageFormat.Xml,
        ResponseFormat = WebMessageFormat.Xml, Method = "POST")]
    XElement MetaWeblog(XElement request);
}

The implementing service being something like:

using System.Xml.Linq;
using Daly.Blogging;

public class BlogService : IBlogService
{
        MetaWeblogManager manager = new MetaWeblogManager { BlogProvider = new TestBlogProvider() };
        public XElement MetaWeblog(XElement request)
        {
            return manager.Execute(request);
        }
}

Note that TestBlogProvider is just an example - this would be whatever class you create to implement IBlogProvider.

I have to admit that for something so tiny separating the contract stuff out into a separate interface is a bit precious, so feel free not to do that. But that's just my opinion, I know some of you have Very Strong Views on that sort of thing.

The config for this service looks like this:

<system.serviceModel>
    <bindings>
      <webHttpBinding>
        <binding name="blogBinding" maxReceivedMessageSize="204800" ></binding>
      </webHttpBinding>
    </bindings>
    <services>
      <service name="BlogService">
        <endpoint address="" behaviorConfiguration="Daly.Blogging.WebBehaviour" bindingConfiguration="blogBinding"
         binding="webHttpBinding" contract="IBlogService" />
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name="WebBehaviour">
          <webHttp />
        </behavior>
        <behavior name="Daly.Blogging.WebBehaviour">
          <webHttp />
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>

This is actually only necessary in this case if you plan to support metaWeblog.newMediaObject and allow media files larger than about 20K (maxReceivedMessageSize has to be bumped up from its default 64K to allow for the base64-encoded-and-therefore-expanded file contents) - otherwise you can leave out the system.serviceModel config entries and include a Factory="System.ServiceModel.Activation.WebServiceHostFactory" attribute in your .svc file.

To answer a few questions you may have:

  1. What's with all this Daly.Blogging nonsense? - It's not, in fact, because I have an enormous ego (that's a coincidence). I've just used that namespace to avoid name collisions with your own code.
  2. Why use an interface instead of an abstract class for the "BlogProvider"? - Good question. I might change my mind about this later.
  3. Why are the (very few) fault code numbers defined as constants instead of an enum? - To avoid casting them back to System.Int32, and because they are never read, only written (er, that sort of made sense to me at the time).
  4. Why not implement a proper ASP.NET Provider?  - I planned to do this at one point (Sunday afternoon, to be precise), then decided that it didn't really fit the use case. The truth is that the provider will always be a custom implementation that you write yourself, there is no useful default or pre-packaged version. So there's not much point in providing declarative support. That being the case, I decided to keep it simple and avoid the Reflection overhead. For those who are interested in such things this implementation is more or less a Strategy pattern.

I may update the code over the next few days. I also intend to provide some useful information about implementing a BlogProvider, unless I forget. Or get hit by a meteorite. You know, stuff.

Anyway, Happy New Year.