Introduction
In this article, I'd like to describe MetaWeblog
API and later share some C# examples of using it with Windows Live Writer. I started thinking about writing custom blog engines which will support MetaWeblog
API after discovering that Windows Live Writer support this API.
What is Windows Live Writer?
It is a Microsoft program which allow you to make posts to most favorites blog engines.
What is MetaWeblog API?
The MetaWeblog
API (MWA) is a programming interface that allows external programs to get and set the text and attributes of weblog posts. It builds on the popular XML-RPC communication protocol.
What is XML-RPC?
It is remote procedure calling using HTTP as the transport and XML as the encoding. XML-RPC is designed to be as simple as possible, while allowing complex data structures to be transmitted, processed and returned.
First I'd like briefly talk about XML-RPC and its C# implementation. On XML-RPC implementation page, I found a link to Charles Cook's XML-RPC.NET package with tons of examples and docs. Using this package, you can simply add XML-RPC support to your classes by adding several attributes (XMLRpcService
, XmlRpcMethod
). Below, you can see an example of blogger class with XML-RPC support:
[XmlRpcService(
Name = "blogger",
Description = "This is a sample XML-RPC service illustrating method
calls with simple parameters and return type.",
AutoDocumentation = true)]
[XmlRpcUrl("http://www.gtrifonov.com/MetaBlogApi.ashx")]
public class blogger : XmlRpcService
{
[XmlRpcMethod("metaWeblog.newPost")]
public string newPost(string blogid, string username,
string password, XmlRpcStruct rpcstruct, bool publish)
{
}
}
As you noticed, newPost
method uses a parameter with type of XmlRpcStruct
. This type represents XML-RPC struct
data type. In XML-RPC, there are few simple data types, array datatype and XML-RPC struct
data type which is basically a simple representation of dictionary.
MetaWeblog API Interface
MetaWeblog
API interface contains the following methods:
-
metaWeblog.newPost (blogid, username, password, struct, publish) returns string
Add new post
-
metaWeblog.editPost (postid, username, password, struct, publish) returns true
Edit existing post
-
metaWeblog.getPost (postid, username, password) returns struct
Returns existing post
-
metaWeblog.getCategories (blogid, username, password) returns struct
Returns blog categories
-
metaWeblog.getRecentPosts (blogid, username, password, numberOfPosts)
returns array of structs
Return recent posts
-
metaWeblog.newMediaObject (blogid, username, password, struct) returns struct
Add new media object to post
When I started coding and testing this interface, I found that Windows Live Writer called blogger.getUsersBlogs
and blogger.deletePost
methods which are actually defined in Blogger
API. I defined these methods with appropriate XmlRPcMethod
attributes in my blogger class and started coding: Below you can find the skeleton of my blogger
class:
using System;
using System.Web;
using CookComputing.XmlRpc;
using System.Xml;
using System.Xml.Xsl;
using System.Xml.XPath;
using System.Collections.Generic;
using System.IO;
[XmlRpcService(
Name = "blogger",
Description = "This is a sample XML-RPC service illustrating method
calls with simple parameters and return type.",
AutoDocumentation = true)]
[XmlRpcUrl("http://www.gtrifonov.com/MetaBlogApi.ashx")]
public class blogger : XmlRpcService
{
[XmlRpcMethod("blogger.getUsersBlogs")]
public XmlRpcStruct[] getUsersBlogs(string appKey, string username, string password)
{
....
return struct;
}
[XmlRpcMethod("metaWeblog.setTemplate")]
public bool setTemplate(string appKey, string blogid,
string username, string password, string template, string templateType)
{
return true;
}
[XmlRpcMethod("metaWeblog.getCategories")]
public XmlRpcStruct[] getCategories(string blogid, string username, string password)
{
XmlRpcStruct rpcstruct = new XmlRpcStruct();
rpcstruct.Add("description", "description");
rpcstruct.Add("categoryid", "123");
rpcstruct.Add("title", "title");
return new XmlRpcStruct[] { rpcstruct };
}
[XmlRpcMethod("metaWeblog.getRecentPosts")]
public XmlRpcStruct[] getRecentPosts(string blogid,
string username, string password,int numberOfPosts)
{
XmlRpcStruct[] posts = new XmlRpcStruct[iterator.Count];
.......
return posts;
}
[XmlRpcMethod("metaWeblog.getTemplate")]
public string getTemplate(string appKey, string blogid,
string username, string password, string templateType)
{
.....................
return id;
}
[XmlRpcMethod("metaWeblog.editPost")]
public bool editPost(string postid, string username,
string password, XmlRpcStruct rpcstruct, bool publish)
{
..................
return true;
}
[XmlRpcMethod("metaWeblog.getPost")]
public XmlRpcStruct getPost(string postid, string username, string password)
{
..................
return rpcstruct;
}
[XmlRpcMethod("blogger.deletePost")]
public bool deletePost(string appKey, string postid,
string username, string password, bool publish)
{
return false;
}
[XmlRpcMethod("metaWeblog.newMediaObject")]
public XmlRpcStruct newMediaObject(string blogid,
string username, string password, XmlRpcStruct rpcstruct)
{
return struct;
}
}
Issues
After defining all methods and adding basic functionality, I figured out that Windows Live Writer was not using getTemplate
and setTemplate
methods and trying to detect your blog appearance by connecting to blog site and downloading content. It's strange because these methods were designed especially for this.
Also I found that in XML-RPC RFS documentation method getRecentPosts
returns struct
with array of posts, but Windows Live Writer expects to receive array of struct
s.
After defining all methods and adding basic functionality, I figured out that Windows Live Writer was not using
getTemplate
and
setTemplate
method and trying to detect your blog appearance by connecting to blog site and downloading content. It's strange because these methods were designed especially for this.
Also I found that in XML-RPC, RFS documentation method getRecentPosts
returns struct
with array of posts, but Windows Live Writer expects to receive an array of struct
s.
If you tried coding method getCategories
looking only at RFS, it will not work with Windows Live Writer, because the writer expects categoryid
as one of the structure members. Thanks to Wiktor for his post with the response code example listed below:
="1.0"
<methodResponse>
<params>
<param>
<value>
<array>
<data>
<value>
<struct>
<member>
<name>categoryid</name>
<value>1</value>
</member>
<member>
<name>title</name>
<value>Category 1</value>
</member>
<member>
<name>description</name>
<value>Description </value>
</member>
</struct>
</value>
</data>
</array>
</value>
</param>
</params>
</methodResponse>
I hope that issues with template methods will be solved in the next Windows Live Writer beta releases.
References
C# Source Code
You can find source code of C# implementation (using XML files as RSS storage) by visiting my website here.
Why I didn't include them with this article? I periodically update some stuff. In future I'd like to publish an RSS engine with XML storage provider, to let users with low level hosting plans to use it as a quick solution for blog posting.
This article was originally published at George Trifonov Blog.
History
- 9th October, 2006: Initial post