Yesterday, in my flurry of posting activity all day long, we covered the Blogger API, the MetaWeblog API, and in a screencast I demonstrated how Microsoft Office Word 2007 would use the MetaWeblog API to communicate with the website and publish text and images to the website using operations from each of those APIs.
Today, we turn our attention to using Windows Live Writer and geting Windows Live Writer to work with our website. While we could connect Windows Live Writer up to our website directly, just like we did with Word, there are some features supported by Windows Live Writer that make the content publishing experience much easier when the website supports it.
The first feature that we're going to implement to add support for Windows Live Writer is a protocol called Really Simple Discovery (RSD). RSD is basically an XML document that is placed on your website (or in our case, will be generated by our website using an HTTP handler in ASP.NET). The XML elements in the RSD document tell a client program such as Windows Live Writer where to locate the MetaWeblog publishing service. The link to the RSD document is contained in the header of the home page for the blog or website that we're publishing to from Windows Live Writer.
At runtime, what will happen is that we'll start up Windows Live Writer and register a new blog or website with it. Windows Live Writer will ask us for the URL to the home page for the blog or website, which we'll type in. Windows Live Writer will download the contents of the home page and will look in the <head> section for an HTML element that will look similar to this:
1: <html>
2: <head>
3: ...
4: <link rel="EditURI" type="application/rsd+xml"
5: title="RSD" href="http://localhost:9500/rsd.ashx"/>
6: ...
7: </head>
8: <body>
9: ...
10: </body>
11: </html>
The <link> element in the HTML uses the rel attribute to identify the link for RSD. Once a program such as Windows Live Writer finds this line, Windows Live Writer will be able to use the URL in the href attribute to locate the RSD document (or in our case, our HTTP handler).
While I could have created an XML file for RSD, I chose to go with creating an HTTP handler that will build the RSD document at runtime. The reason why I chose to do this is that the URLs specified in the RSD document need to be absolute URLs for Windows Live Writer to locate the APIs correctly. In my HTTP handler, I use the current request information to build the URL for the MetaWeblog API implementation. Here's the code for the RSD HTTP handler:
1: public class ReallySimpleDiscoveryHandler : IHttpHandler { 2: /// <summary>
3: /// Returns true to indicate that the HTTP handler can be reused for
4: /// multiple requests.
5: /// </summary>
6: public bool IsReusable { 7: get { return true; } 8: }
9:
10: /// <summary>
11: /// Handles the request and serves the RSD document to the client.
12: /// </summary>
13: /// <param name="context">
14: /// The <see cref="HttpContext"/> used to handle the current
15: /// request.
16: /// </param>
17: public void ProcessRequest(HttpContext context) { 18: string rootUrl = String.Format("{0}://{1}:{2}/", 19: context.Request.Url.Scheme, context.Request.Url.Host,
20: context.Request.Url.Port);
21:
22: XNamespace ns = "http://archipelago.phrasewise.com/rsd";
23: XDocument rsdDocument = new XDocument(new XElement(ns + "rsd",
24: new XAttribute("version", "1.0"), 25: new XElement(ns + "service", "Content Publishing 101"),
26: new XElement(ns + "engineLine",
27: "http://www.sogeti-phoenix.com"),
28: new XElement(ns + "homePageLink", rootUrl),
29: new XElement(ns + "apis",
30: new XElement(ns + "api",
31: new XAttribute("name", "MetaWeblog"), 32: new XAttribute("preferred", "true"), 33: new XAttribute("apiLink", rootUrl + 34: "ContentPublishingService.ashx"),
35: new XAttribute("blogID", "michael")), 36: new XElement(ns + "api",
37: new XAttribute("name", "Blogger"), 38: new XAttribute("preferred", "false"), 39: new XAttribute("apiLink", rootUrl + 40: "ContentPublishingService.ashx"),
41: new XAttribute("blogID", "michael"))))); 42:
43: context.Response.Write(rsdDocument.ToString());
44: }
45: }
I'm using the new LINQ XML support introduced in .NET 3.5 to build the RSD XML document. The RSD that I am generating tells an RSD client that we support both the MetaWeblog API and the Blogger API, but the MetaWeblog API is preferred over the Blogger API. The XML that this handler outputs looks like this:
1: <rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">
2: <service>Content Publishing 101</service>
3: <engineLine>http://www.sogeti-phoenix.com</engineLine>
4: <homePageLink>http://localhost:9500/</homePageLink>
5: <apis>
6: <api name="MetaWeblog" preferred="true"
7: apiLink="http://localhost:9500/ContentPublishingService.ashx"
8: blogID="michael" />
9: <api name="Blogger" preferred="false"
10: apiLink="http://localhost:9500/ContentPublishingService.ashx"
11: blogID="michael" />
12: </apis>
13: </rsd>
One thing to note is that I thought that I read someplace that the blogID attribute in the RSD output isn't used, however when I tried this out I discovered that Windows Live Writer does use it to get the blogid value that it will use with the Blogger and MetaWeblog APIs. This has important ramifications for using Windows Live Writer for your blog or website.
The main issue that will affect your website is if you were to build some sort of multi-blogger experience, or build a website with several subsites, each with their own sets of categories. The way that Windows Live Writer requires and uses the blogID attribute means that you can't have one global RSD file that works for the entire site. Each blog or subsite on your website will need to have its own RSD file.
Now that we have told Windows Live Writer how to find our content publishing service using RSD, it's not time that we help Windows Live Writer out by telling it what features that we support. Windows Live Writer is actually a fully developed editing environment with a lot of features for creating new content to be published up to a website. However, Windows Live Writer also knows that it can't be everything to everyone. There are some features that Windows Live Writer does support that some blog engines and content management systems don't support. So we have to help out Windows Live Writer from our website to tell WLW what features we do support. We also want to go a step beyond that and help customize Windows Live Writer to give our content authors a few customizations to help them do their jobs of publishing content. We can do all of this by providing Windows Live Writer with an XML manifest file that tells Windows Live Writer about our blog or website.
During the blog/website registration process with Windows Live Writer, Windows Live Writer will download our RSD file to find the location of the MetaWeblog API. Windows Live Writer, like Microsoft Office Word 2007, will then make some calls to our website to make sure that the blog exists and to get the list of categories for the website. Somewhere during the registration process, Windows Live Writer will look at our home page to also find a link to the manifest file for Windows Live Writer. We will add this link right next to the RSD link in the header section of our home page:
1: <html xmlns="http://www.w3.org/1999/xhtml">
2: <head runat="server">
3: <title>Untitled Page</title>
4: <link rel="EditURI" type="application/rsd+xml" title="RSD"
5: href="http://localhost:9500/rsd.ashx" />
6: <link rel="wlwmanifest" type="application/wlwmanifest+xml"
7: href="http://localhost:9500/wlwmanifest.ashx" />
8: </head>
9: <body>
10: <form id="form1" runat="server">
11: <div>
12:
13: </div>
14: </form>
15: </body>
16: </html>
On line 6 is the link to our manifest file for Windows Live Writer. I've chosen once again to implement this as an HTTP handler because at some point in the future I may choose to allow the website administrator to selectively configure which options the website should support. For example, the website administrator may not want posts that have embedded JavaScript code in them, or <embed> elements.
Before I show you the source code for the HTTP handler and the resulting XML generated by it, you might want to pause and take a look at the manifest file specification for Windows Live Writer. Here's the source code for my manifest file generator:
1: public void ProcessRequest(HttpContext context) { 2: XNamespace ns = "http://schemas.microsoft.com/wlw/manifest/weblog";
3: XDocument xmlDocument = new XDocument(new XElement(ns + "manifest",
4: new XElement(ns + "options",
5: new XElement(ns + "clientType", "Metaweblog"),
6: new XElement(ns + "supportsScripts", "Yes"),
7: new XElement(ns + "supportsEmbeds", "Yes")),
8: new XElement(ns + "weblog",
9: new XElement(ns + "serviceName", "Michael's Blog"),
10: new XElement(ns + "homepageLinkText",
11: "View Michael's Blog"),
12: new XElement(ns + "adminLinkText",
13: "Manage Michael's Blog"),
14: new XElement(ns + "adminUrl",
15: new XCData("http://localhost:9500/Admin")), 16: <