Scott Hanselman

The Weekly Source Code 55 - NotABlog: A Local XML-RPC MetaWebLog Endpoint That Lies To Windows Live Writer

August 2, '10 Comments [23] Posted in ASP.NET | Blogging | IIS | Source Code
Sponsored By

WLW in Use My team has to write a lot. We write some blog posts, sure, but we also write a lot of tutorials for various sites. Right now the http://www.asp.net site runs on Umbraco, but MSDN runs on custom internal what-not, and there's other sites as well. The only common thread is HTML.

Sometimes someone will write a tutorial or document in Word, then try to get some HTML out of that, that will only ends in pain and suffering. We could use something like Markdown or Dreamweaver or Expression Web, or write the HTML ourselves, but we keep coming back to Windows Live Writer. No joke, for our workflow, WLW is the best blog editor out there.

It creates nice clean markup, and lets us stick to the basics, which for us are H1, P, PRE, UL, LI, ACRONYM, BLOCKQUOTE, IMG and not much more. It supports plugins for editing and coloring code (I use the PreCode plugin) and has very nice image handling features like Watermarks, resizing and linking to larger versions, etc. We would like to write everything in it.

Problem is, it doesn't include a Save As dialog. We could view|source and copy the HTML directly after we edit, but WLW uses temporary image links of a custom type while editing with names like $whatever.png and hides the images in temp files and opaque blobs.

NOTE: Windows Live Writer does support editing and publishing to the Blogger API, the MetaWeblog API and via AtomPub. AtomPub is the newest and most rigid, but I'm going to start by creating a MetaWeblog Server because I understand it and it's trivially lightweight. I'll try to follow this post up the with the same functionality except with AtomPub soon in order to juxtapose the two. Remember that MetaWeblog extends the Blogger API and is all about blogging and content. AtomPub isn't just about blogging, it's about editing anything. WLW is a blogging client that speaks AtomPub, but it's not a general AtomPub client.

So what I'm going to build is a small local "NotABlog" server that I can point Windows Live Writer to and fool it into thinking it's a blog. Then I'll effectively be able to Create, Read, and Update blog posts (HTML files and their associated images) that are sitting in a local publish folder.

This sample might be interesting to you and your organization (or the not-yet-written AtomPub version) because you could potentially put an endpoint in front of existing systems that you work on and enable business users to edit content with Windows Live Writer. WLW isn't too scary for business folks and it's a nice interface for updating existing custom content management systems that you might have lying around. Creating an editing endpoint for existing clients is a low-effort way to reinvigorate existing content management systems.

Metaweblog

Many years ago (like 12) XML-RPC was created by Dave Winer and some Microsofties. It's not SOAP, it's literally remote procedure calls over HTTP with XML. There are other protocols built on top of XML-RPC, which are just interfaces. Effectively they are agreements that an endpoint will contain certain named methods with certain parameters.

The MetaWeblog API is an XML-RPC interface that Dave made that lets you edit weblog entries. It's older, but it's effectively universal. Here's an example of what an XML-RPC call looks like.



examples.getSomething


70


Charles Cook created an amazing and elegant library called XML-RPC.NET and has given it to the community. He's kept it working nicely such that I was able to get it working in my .NET 4.0 application without any modification even though I was using an older 1.0.0.8 version for .NET 1.0 in my first version. That's a testament to Charles' work. Later I downloaded the latest 2.4.0 from 2008 and it worked nicely also and fixed some bugs.

In 2008, Keyvan Nayyeri created a nice little MetaWeblog ASP stub in ASP.NET so I started building with that. I just return true in the ValidateUser method, because this is for local editing. I lie (return hard-coded stuff in a few places) to Windows Live Writer.

Here's what the interface looks like:

namespace NotABlog
{
public interface IMetaWeblog
{
#region MetaWeblog API

[XmlRpcMethod("metaWeblog.newPost")]
string AddPost(string blogid, string username, string password, Post post, bool publish);

[XmlRpcMethod("metaWeblog.editPost")]
bool UpdatePost(string postid, string username, string password, Post post, bool publish);

[XmlRpcMethod("metaWeblog.getPost")]
Post GetPost(string postid, string username, string password);

[XmlRpcMethod("metaWeblog.getCategories")]
CategoryInfo[] GetCategories(string blogid, string username, string password);

[XmlRpcMethod("metaWeblog.getRecentPosts")]
Post[] GetRecentPosts(string blogid, string username, string password, int numberOfPosts);

[XmlRpcMethod("metaWeblog.newMediaObject")]
MediaObjectInfo NewMediaObject(string blogid, string username, string password, MediaObject mediaObject);

#endregion

#region Blogger API

[XmlRpcMethod("blogger.deletePost")]
[return: XmlRpcReturnValue(Description = "Returns true.")]
bool DeletePost(string key, string postid, string username, string password, bool publish);

[XmlRpcMethod("blogger.getUsersBlogs")]
BlogInfo[] GetUsersBlogs(string key, string username, string password);

[XmlRpcMethod("blogger.getUserInfo")]
UserInfo GetUserInfo(string key, string username, string password);

#endregion
}
}

You just need to derive from Charles' XmlRpcService and he'll handle the routing of the HTTP POSTs and the calling of the methods and tearing apart of the parameters. (Actually, as a curiosity back in the ASP.NET MVC 1.0 timeframe both Phil and I write XmlRpcRoutes and supporting samples just to see if it was possible. It is.)

The idea is to catch the calls and just redirect them to the file system. Here's a simple example:

string IMetaWeblog.AddPost(string blogid, string username, string password,
Post post, bool publish)
{
if (ValidateUser(username, password))
{
string id = string.Empty;
string postFileName;
if (String.IsNullOrEmpty(post.title))
postFileName = Guid.NewGuid() + ".html";
else
postFileName = post.title + ".html";

File.WriteAllText(Path.Combine(LocalPublishPath, postFileName), post.description);

return postFileName;
}
throw new XmlRpcFaultException(0, "User is not valid!");
}

Go run it yourself if you like. Here's how.

Setting up your Local Publishing Endpoint

First, edit the web.config and change your local publish directory if you like. Currently it just puts posts in a folder .\LocalPublish in the current directory of your web application. Free free to change it. I put it in my desktop.











Since this is a web application, I need a Web Server to run it under. I didn't want to require Visual Studio or IIS to run it, so I figured I'd use IIS Express from WebMatrix to do it since it's free and you don't need to be Admin to run it (except on Win2k3). Install WebMatrix and you'll get IIS Express.

I created a batch file called StartNotABlog.bat and put this in it:

SET ExecPath=%ProgramFiles(x86)%
IF "%ExecPath%" == "" SET ExecPath = "%ProgramFiles%

"%ExecPath%\Microsoft WebMatrix\iisexpress.exe" /path:"%CD%" /port:12345

It's pretty straightforward and it'll work on both x86 and x64. It starts up a Web Server on port 12345 with the current directory (that the batch file is running in, not the environment's current directory) as the path.

Now, start up Windows Live Writer. Add a blog, select Other...

What kind of Blog Services

And select "Metaweblog API" as the type.

Choose a Blog Type

Put in http://localhost:12345/MetaWeblogAPI.ashx as the remote posting URL.

Enter your remote posting URL  

There's no username or password so just put in something.

Windows Live Writer (2) 

Click Next and Finish and go edit a post! I'm using it now to edit a 3000 word tutorial on ASP.NET.

image

Not a Blog.zip. Download the Code and have fun playing with it. There's actually not much there but it's already changed how I do my job. Now the trick will be to show the bosses how easy it is to give anything an endpoint that WLW will talk to. Maybe this blog post will help. ;)

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web
Monday, August 02, 2010 6:34:04 AM UTC
I was looking for a solution to receive decent HTML files from business people without giving them DreamWeaver or so, since Word to HTML is a real pain. This might actually do the trick !
Monday, August 02, 2010 7:32:37 AM UTC
Interesting Scott. I'll give it a try :p
Monday, August 02, 2010 7:41:55 AM UTC
Scott,

When I click the link to download the sample I am redirected to my Hotmail login page. I enter my credentials and am logged in. But I cannot reach your public page. Can you check out the link please?

Thanks
Monday, August 02, 2010 8:39:59 AM UTC
Yes, I was on a dogfood server for Windows Live. Hit Ctrl-F5 on my blog to refresh and the code link should work now.
Monday, August 02, 2010 9:36:55 AM UTC
Perfect I got it ;)
Monday, August 02, 2010 12:24:51 PM UTC
Nice :) some time ago wanted to make a content on quasi-CMS editable but the project wen't away unfinished. If I get something similar I'll use your approach.
Monday, August 02, 2010 1:00:28 PM UTC
Great post, Scott! Sometimes we forget that we have other tools to use and we end-up creating a huge and complex administrative area for a web site that could (and should) take advantage of other tools like Windows Live Writer.

Thanks for the post!
Monday, August 02, 2010 5:46:29 PM UTC
Great idea! I use Umbraco, WLW and Community server. But I would love to be able to use WLW to edit Codeplex content so using your fake server I might write a converter from the basic Html to the wierd dialect CodePlex uses. The strange urls and such kept me from it but this provides a nice solution.
Erno
Monday, August 02, 2010 6:27:53 PM UTC
You've read my mind! :D Thank you for the post!

4 weeks ago I was trying to use Silverlight to edit news on my site, it was fun until I hit the HTML editing :(, and I’ve abandoned the idea then started thinking about using WLW to publish news in my site :)
Tuesday, August 03, 2010 6:16:15 AM UTC
That's really a nice solution, worked out completely.

I wanted to include a similar thing in my own blog engine to enable support of the nice Live Writer application. I can make use of this very easily.

Thanks!
Wednesday, August 04, 2010 12:30:19 AM UTC
Hi there,

Great post! My current blog uses the same approach and has no admin, just a custom written endpoint for Windows Live writer.

I am also in the process of writing a CMS that has basically no admin section, simply because live writer does such a good job.
Wednesday, August 04, 2010 12:01:14 PM UTC
When I click the link to download the sample I am redirected to my Live login page. I enter my credentials and am logged in. But I cannot reach your public page. Can you check out the link please?

Tried the Ctrl-F5 and refresh but still no go
Saturday, August 07, 2010 7:56:14 AM UTC

An awesome article briefly including all the concepts of ASP.Net and other stuffs ....

Loved going through it and learning more into other things.... :)


Regards,
H.
Sunday, August 08, 2010 3:25:57 PM UTC
Interesting and something cool to check out. I'm curious though, this effectively lets you save locally but there's a "Save as Draft" feature already built into WLW.

Other than being able to setup a server and posting to it (and the cool factor of writing a fake blog endpoint) what's the advantage of this over saving a local draft? If you set this up as a server so your team can collaborate why not just have them post their drafts to it (File | Post draft to blog). When the draft is online on any blog software (post to your SharePoint team site?) anyone can retreive it with WLW.

Like I said, not knocking this cool idea but other than the cool factor you can get the same results with the tools as-is.
Monday, August 09, 2010 5:57:11 PM UTC
Bil - Save As Draft just saves to an opaque binary blob, not locally anywhere. As for posting it to a online service, that's fine, but then you have to View Source and mess with it and change all the HREFs.
Friday, August 13, 2010 7:09:44 PM UTC
I get an error when I try to publish a blog that has an image: "... the blog does not support picture publishing." And it then asks if I want to set up FTP for picture publishing. Did you use FTP for the pictures?
Tom
Saturday, August 14, 2010 2:02:56 AM UTC
I would pay about $40 for a WLW on the Mac. It's a bit weird that the platform for `cool' people like Justin Long doesn't even have a decent blog editor, let alone something like WLW. Anyway ... the IMetaWeblog.AddPost method has a bug--if you save a post with a title x, then save another post with the same title x, you accidentally overwrite the contents of the previously-saved post. Oops :-)
Wednesday, August 25, 2010 3:21:29 PM UTC
Give credit where credit is due.

Keyvan Nayyeri cloned his code from the original code on CodeProject, listed here: Coding Blog Engine with MetaWeblog API Support and Using it with Windows Live Writer; look it up, you'll see.

The article was written October 9, 2006 by George Trifonov. The first to clone George's 2006 article was Deepak Kamboj, but I cannot find the blog where he cloned the article any longer. Maybe he removed it.

Regardless, credit should be given where credit is due.

Sorry to be a wet blanket about this, but original authors deserve to be credited properly when they were the first to write original code.

I included the links above to prove that Keyvan Nayyeri did not credit George Trifonov. However, Keyvan may not have known that George was the original author since Deepak Kamboj didn't say where he got his code either.
Jerold Anderson
Wednesday, August 25, 2010 5:14:31 PM UTC
Thanks, I didn't know!

That said, let's be clear, without taking too much away from folks' accomplishments. Charles Cook did 90% of the work here with the XmlRpcService.

Implementing the metaweblog API isn't hard, it's 20 minutes tedious, and even then it's only 9 methods. There's just an implemented interface at that codeplex project, but nothing underneath. I know because I implemented the interface with DasBlog (4? years ago) and was the one who added newMediaObject.

Still, a useful sample for all.
Sunday, August 29, 2010 7:06:02 PM UTC
Hi Scott,

I'm having problems downloading the sample.
I am just redirected to my Windows Live page. I tried CTRL-F5, but the result is the same.
Are we back to the dogfood server?

// Vincent
Vincent
Friday, November 05, 2010 8:59:48 PM UTC
i am getting the same i really wanna try this out in action so i can see how it is implemented it also is it possible to inegrate this type of functionality into an MVC 2 website or does this only run standalone beside another server instance
Wednesday, November 17, 2010 1:50:25 PM UTC
For those having issues with the link for the source, try this URL: http://cid-cd06a7367371152c.skydrive.live.com/self.aspx/Public/NotABlog.zip

Simply replaced office-df in the URL with skydrive and it worked as expected.
Wednesday, December 08, 2010 11:31:05 AM UTC
Hi scott,

I hooked up my blog to windows live writter and I have some problems;

1-I realized that you are using the same syntaxhighliter as I do. which plug-in do you use for inserting codes from WLW?

2-I hooked it up with Metawebblog API and I am unable to update the blogs. You mentioned that but is there a way to solve that problem?

3-I assume that you are uploading your pictures from WLW. How can I implement that feature as well.

I wantted to create a new plug-ins for WLW but I am unable to find the Live Writer SDK download page.
Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.