Posted on March 22, 2008 15:58 by mcollins

In the previous post of this series, I introduced you to the Blogger API.  The Blogger API is the first of a series of APIs based on the XML-RPC protocol that are used to publish content from WYSIWYG applications such as Windows Live Writer or Microsoft Office Word 2007 to websites such as blogs, knowledge bases, or FAQ-type applications.  In this post, we're going to go to the next step and discuss the MetaWeblog API which refined and enhanced the Blogger API.

There are a couple of specifications available for the MetaWeblog API:

  • The "official" specification is here.
  • The Microsoft implementation of the MetaWeblog API for the Live Spaces service is here.

 

The MetaWeblog API doesn't completely replace the Blogger API.  Instead, it enhances the API and provides better support for publishing richer content to websites.  For example, in the Blogger API, we didn't have the concept of categories for organizing our content and making it easier to find.  With MetaWeblog, we have the concept of categories.  Another addition was that Blogger's blogger.newPost operation only posted the content of a blog post to the blog.  The blog post didn't have a title for indexing or summarizing the content of a page, for example in a table of contents.  MetaWeblog adds an explicit title to the post definition.

The MetaWeblog API defines the following operations on top of the Blogging API:

  • metaWeblog.editPost: edits a post that has been published to the blog or website
  • metaWeblog.getCategories: gets a list of categories that exist on the blog or website
  • metaWeblog.getPost: gets the content for a post that has been published to the blog or website
  • metaWeblog.getRecentPosts: gets the most recent posts from the blog or website
  • metaWeblog.newMediaObject: uploads the contents of a media object such as an image to the blog or website
  • metaWeblog.newPost: publishes a post to the blog or website

 

You'll notice that both the Blogger API and the MetaWeblog API define editPost and newPost operations.  The MetaWeblog API operations obsolete the Blogger API's operations, so with MetaWeblog we shouldn't have to worry about implementing those operations.  You still can implement them if you have compatibility concerns, but most MetaWeblog clients won't use the Blogger API operations.

The two big additions to the MetaWeblog API are the getCategories and newMediaObject operations.  As we discussed, getCategories allows blogs or websites to implement the concept of categories in order to organize content on a blog or website.  Additionally, newMediaObject allows WYSIWYG clients such as Microsoft Office Word or Windows Live Writer publish media objects such as images that are embedded inside the content of a post.  This is an exciting edition to the publishing process because content authors don't need to separately publish images to the website using FTP or some other method.  Instead, the WYSIWYG client can publish both text and images at the same time.

The other big difference is that the MetaWeblog API introduces the formal concept of a post object.  While a post in the Blogger API consisted of just the text for the post content, in the MetaWeblog API, the post has now become a structure based on the RSS specification for uploading the post content with additional metadata such as the title and categories for the post.  In the MetaWeblog API, the following fields are defined for a post:

  • author: The name or email address for the author of a post. This field corresponds to the <author> element in an RSS item.  This field normally isn't used when publishing a new post to a website, but may be included in the post data when calling metaWeblog.getPost to get the data for an existing post.
  • categories: An array of strings containing the categories that the post is associated with.
  • comments: The URL of the comments page for the post.  This field is normally present when calling metaWeblog.getPost to get the data for an existing post.
  • dateCreated: The date and time when the post was created.  Usually present when getting a post using metaWeblog.getPost.
  • description: The HTML text for the post.
  • enclosure: A structure describing a file that has been attached to the post.
  • excerpt: A short summary of a post, like an abstract.
  • keywords: Used to attach keywords to a post.  Some blogging engines use this field to create tags to mark related posts.
  • link: The URL for the blog post.  Appears when using metaWeblog.getPost.
  • publicationDate: The date and time that the post should be published.
  • publish: True or false to indicate if the post has been published.
  • source: The source of the post if the post originated from another site or RSS feed.
  • title: The title of the blog post.

 

The metaWeblog.newPost operation is defined below:

   1: [XmlRpcMethod("metaWeblog.newPost",
   2:     Description = "Publishes a new post to the blog.")]
   3: string NewPost(string blogId, string userName, string password,
   4:     XmlRpcStruct post, bool publish);

 

Here, I use the XML-RPC.NET's implementation of XmlRpcStruct to represent the actual post content.  I could have created a class with fields matching the fields of a post, but I actively chose to use XmlRpcStruct instead.  The reasoning is mostly for future expansion or to support custom extensions to the post data structure.  By accessing the post information using a XmlRpcStruct instead of a class, my implementation of NewPost can access the custom information without my having to expand or change a post structure in the future to support enhancements.  All of the other parameters of NewPost are the same as in the Blogger API, and the return value is still the unique identifier of the new post.

The metaWeblog.editPost operation also is updated to accept a post as a data structure:

   1: [XmlRpcMethod("metaWeblog.editPost",
   2:     Description = "Updates a post that has been posted to the blog.")]
   3: bool EditPost(string postId, string userName, string password,
   4:     Post post, bool publish);

 

The rest of the behavior of EditPost mirrors the Blogger API's version.

You'll notice that the MetaWeblog API doesn't have a delete operation.  The MetaWeblog API is implemented alongside the Blogger API, so it's going to be expected that clients can continue to use the blogger.deletePost operation to delete posts from a website.

The metaWeblog.getCategories operation has been defined to allow WYSIWYG editors to query the blog to determine what categories are defined for the blog:

   1: [XmlRpcMethod("metaWeblog.getCategories",
   2:     Description = "Returns the categories for the blog.")]
   3: Category[] GetCategories(string blogId, string userName,
   4:     string password);

 

The Category data structure that is returned by this operation is defined below:

   1: [Serializable]
   2: [XmlRpcMissingMapping(MappingAction.Error)]
   3: public class Category {
   4:     /// <summary>
   5:     /// The title of the category.
   6:     /// </summary>
   7:     [SuppressMessage("Microsoft.Design", "CA1051",
   8:         Justification = "Public fields must be exposed for XML-RPC.NET")]
   9:     public string description;
  10:     
  11:     /// <summary>
  12:     /// The URL of the web page where the category's contents can be
  13:     /// viewed.
  14:     /// </summary>
  15:     [XmlRpcMissingMapping(MappingAction.Ignore)]
  16:     [SuppressMessage("Microsoft.Design", "CA1051",
  17:         Justification = "Public fields must be exposed for XML-RPC.NET")]
  18:     public string htmlUrl;
  19:  
  20:     /// <summary>
  21:     /// The URL of the RSS feed for the category.
  22:     /// </summary>
  23:     [XmlRpcMissingMapping(MappingAction.Ignore)]
  24:     [SuppressMessage("Microsoft.Design", "CA1051",
  25:         Justification = "Public fields must be exposed for XML-RPC.NET")]
  26:     [SuppressMessage("Microsoft.Naming", "CA1704",
  27:         Justification = "The field name is specified by the MetaWeblog " +
  28:         "API")]
  29:     public string rssUrl;
  30:  
  31:     /// <summary>
  32:     /// The title of the category.
  33:     /// </summary>
  34:     [SuppressMessage("Microsoft.Design", "CA1051",
  35:         Justification = "Public fields must be exposed for XML-RPC.NET")]
  36:     public string title;
  37: }

 

Windows Live Writer expects that the title and description fields of this structure will have the same value.  It's probably a good idea to just make that the default functionality for your implementation.

The metaWeblog.getPost operation is used to retrieve a post from the website using the post's identifier:

   1: [XmlRpcMethod("metaWeblog.getPost",
   2:     Description = "Retrieves the content for a post from the blog.")]
   3: Post GetPost(string postId, string userName, string password);

 

The GetPost operation will return a data structure containing a post.  You'll notice that my definition of this method is returning a Post object rather than an XmlRpcStruct.  To make it easier to implement this method, I subclassed the XmlRpcStruct class to define a Post class with properties that I could set.  Here's the code:

   1: /// <summary>
   2: /// Represents a post that is sent or received by a MetaWeblog service.
   3: /// </summary>
   4: [Serializable]
   5: [SuppressMessage("Microsoft.Design", "CA1035",
   6:     Justification = "Supports XML-RPC.NET")]
   7: [SuppressMessage("Microsoft.Naming", "CA1710",
   8:     Justification = "Supports XML-RPC.NET")]
   9: [SuppressMessage("Microsoft.Usage", "CA2229",
  10:     Justification = "Supports XML-RPC.NET")]
  11: public class Post : XmlRpcStruct {
  12:     /// <summary>
  13:     /// The name of the <see cref="AllowComments"/> field.
  14:     /// </summary>
  15:     public const string AllowCommentsName = "mt_allow_comments";
  16:  
  17:     /// <summary>
  18:     /// The name of the <see cref="AllowPings"/> field.
  19:     /// </summary>
  20:     public const string AllowPingsName = "mt_allow_pings";
  21:  
  22:     /// <summary>
  23:     /// The name of the <see cref="Author"/> field.
  24:     /// </summary>
  25:     public const string AuthorName = "author";
  26:  
  27:     /// <summary>
  28:     /// The name of the <see cref="BaseName"/> field.
  29:     /// </summary>
  30:     public const string BaseNameName = "mt_base_name";
  31:  
  32:     /// <summary>
  33:     /// The name of the <see cref="Body"/> field.
  34:     /// </summary>
  35:     public const string BodyName = "mt_text_more";
  36:  
  37:     /// <summary>
  38:     /// The name of the <see cref="Categories"/> field.
  39:     /// </summary>
  40:     public const string CategoriesName = "categories";
  41:  
  42:     /// <summary>
  43:     /// The name of the <see cref="Comments"/> field.
  44:     /// </summary>
  45:     public const string CommentsName = "comments";
  46:  
  47:     /// <summary>
  48:     /// The name of the <see cref="DateCreated"/> field.
  49:     /// </summary>
  50:     public const string DateCreatedName = "dateCreated";
  51:  
  52:     /// <summary>
  53:     /// The name of the <see cref="Description"/> field.
  54:     /// </summary>
  55:     public const string DescriptionName = "description";
  56:  
  57:     /// <summary>
  58:     /// The name of the <see cref="Enclosure"/> field.
  59:     /// </summary>
  60:     public const string EnclosureName = "enclosure";
  61:  
  62:     /// <summary>
  63:     /// The name of the <see cref="Excerpt"/> field.
  64:     /// </summary>
  65:     public const string ExcerptName = "excerpt";
  66:  
  67:     /// <summary>
  68:     /// The name of the <see cref="Guid"/> field.
  69:     /// </summary>
  70:     public const string GuidName = "guid";
  71:  
  72:     /// <summary>
  73:     /// The name of the <see cref="Keywords"/> field.
  74:     /// </summary>
  75:     public const string KeywordsName = "keywords";
  76:  
  77:     /// <summary>
  78:     /// The name of the <see cref="Link"/> field.
  79:     /// </summary>
  80:     public const string LinkName = "link";
  81:  
  82:     /// <summary>
  83:     /// The name of the <see cref="Password"/> field.
  84:     /// </summary>
  85:     public const string PasswordName = "password";
  86:  
  87:     /// <summary>
  88:     /// The name of the <see cref="PublicationDate"/> field.
  89:     /// </summary>
  90:     public const string PublicationDateName = "publicationDate";
  91:  
  92:     /// <summary>
  93:     /// The name of the <see cref="Publish"/> field.
  94:     /// </summary>
  95:     public const string PublishName = "publish";
  96:  
  97:     /// <summary>
  98:     /// The name of the <see cref="Slug"/> field.
  99:     /// </summary>
 100:     public const string SlugName = "wp_slug";
 101:  
 102:     /// <summary>
 103:     /// The name of the <see cref="Source"/> field.
 104:     /// </summary>
 105:     public const string SourceName = "source";
 106:  
 107:     /// <summary>
 108:     /// The name of the <see cref="Title"/> field.
 109:     /// </summary>
 110:     public const string TitleName = "title";
 111:  
 112:     /// <summary>
 113:     /// The name of the <see cref="TrackbackPingUrls"/> field.
 114:     /// </summary>
 115:     public const string TrackbackPingUrlsName = "mt_tb_ping_urls";
 116:  
 117:     /// <summary>
 118:     /// The name of the <see cref="WPAuthor"/> field.
 119:     /// </summary>
 120:     public const string WPAuthorName = "wp_author";
 121:  
 122:     /// <summary>
 123:     /// Gets or sets whether comments are allowed for the post.
 124:     /// </summary>
 125:     /// <remarks>
 126:     /// <para>
 127:     /// This field corresponds to the <c>mt_allow_comments</c> field
 128:     /// of the post structure.
 129:     /// </para>
 130:     /// <para>
 131:     /// <list>
 132:     /// <listheader>
 133:     /// <term>Value</term>
 134:     /// <description>Description</description>
 135:     /// </listheader>
 136:     /// <item>
 137:     /// <term>0</term>
 138:     /// <description>No comments are allowed.</description>
 139:     /// </item>
 140:     /// <item>
 141:     /// <term>1</term>
 142:     /// <description>Comments can be read and written.</description>
 143:     /// </item>
 144:     /// <item>
 145:     /// <term>2</term>
 146:     /// <description>Comments can be read but not written.</description>
 147:     /// </item>
 148:     /// </list>
 149:     /// </para>
 150:     /// </remarks>
 151:     public int AllowComments {
 152:         get { return (int)this[AllowCommentsName]; }
 153:         set { this[AllowCommentsName] = value; }
 154:     }
 155:  
 156:     /// <summary>
 157:     /// Gets or sets whether Trackback pings are allowed on the post.
 158:     /// </summary>
 159:     public int AllowPings {
 160:         get { return (int)this[AllowPingsName]; }
 161:         set { this[AllowPingsName] = value; }
 162:     }
 163:  
 164:     /// <summary>
 165:     /// Gets or sets the email address of the author of the blog post.
 166:     /// </summary>
 167:     public string Author {
 168:         get { return (string)this[AuthorName]; }
 169:         set { this[AuthorName] = value; }
 170:     }
 171:  
 172:     /// <summary>
 173:     /// Gets or sets the base name for the post.
 174:     /// </summary>
 175:     /// <remarks>
 176:     /// This property corresponds to the <c>mt_basename</c> field of the
 177:     /// post structure.
 178:     /// </remarks>
 179:     public string BaseName {
 180:         get { return (string)this[BaseNameName]; }
 181:         set { this[BaseNameName] = value; }
 182:     }
 183:  
 184:     /// <summary>
 185:     /// Gets or sets the body text of the blog post.
 186:     /// </summary>
 187:     /// <remarks>
 188:     /// This field corresponds to the <c>mt_text_more</c> field of the 
 189:     /// post structure.
 190:     /// </remarks>
 191:     public string Body {
 192:         get { return (string)this[BodyName]; }
 193:         set { this[BodyName] = value; }
 194:     }
 195:  
 196:     /// <summary>
 197:     /// Gets or sets the categories for the blog post.
 198:     /// </summary>
 199:     [SuppressMessage("Microsoft.Performance", "CA1819",
 200:         Justification = "Supports XML-RPC.NET")]
 201:     public string[] Categories {
 202:         get { return (string[])this[CategoriesName]; }
 203:         set { this[CategoriesName] = value; }
 204:     }
 205:  
 206:     /// <summary>
 207:     /// Gets or sets the URL of the comments page for the post.
 208:     /// </summary>
 209:     public string Comments {
 210:         get { return (string)this[CommentsName]; }
 211:         set { this[CommentsName] = value; }
 212:     }
 213:  
 214:     /// <summary>
 215:     /// Gets or sets the date and time that a post was created.
 216:     /// </summary>
 217:     public DateTime DateCreated {
 218:         get { return (DateTime)this[DateCreatedName]; }
 219:         set { this[DateCreatedName] = value; }
 220:     }
 221:  
 222:     /// <summary>
 223:     /// Gets or sets the content or body of the post.
 224:     /// </summary>
 225:     public string Description {
 226:         get { return (string)this[DescriptionName]; }
 227:         set { this[DescriptionName] = value; }
 228:     }
 229:  
 230:     /// <summary>
 231:     /// Gets or sets a structure containing information about a media
 232:     /// object that is attached to the item.
 233:     /// </summary>
 234:     [SuppressMessage("Microsoft.Usage", "CA2227",
 235:         Justification = "Supports XML-RPC.NET")]
 236:     public XmlRpcStruct Enclosure {
 237:         get { return (XmlRpcStruct)this[EnclosureName]; }
 238:         set { this[EnclosureName] = value; }
 239:     }
 240:  
 241:     /// <summary>
 242:     /// Gets or sets the excerpt for the post.
 243:     /// </summary>
 244:     /// <remarks>
 245:     /// This property corresponds to the <c>mt_excerpt</c> field of the
 246:     /// post structure.
 247:     /// </remarks>
 248:     public string Excerpt {
 249:         get { return (string)this[ExcerptName]; }
 250:         set { this[ExcerptName] = value; }
 251:     }
 252:  
 253:     /// <summary>
 254:     /// Gets or sets the unique identifier for the post.
 255:     /// </summary>
 256:     public string Guid {
 257:         get { return (string)this[GuidName]; }
 258:         set { this[GuidName] = value; }
 259:     }
 260:  
 261:     /// <summary>
 262:     /// Gets or sets the keywords for the post.
 263:     /// </summary>
 264:     /// <remarks>
 265:     /// This field corresponds to the <c>mt_keywords</c> field of the
 266:     /// post structure.
 267:     /// </remarks>
 268:     public string Keywords {
 269:         get { return (string)this[KeywordsName]; }
 270:         set { this[KeywordsName] = value; }
 271:     }
 272:  
 273:     /// <summary>
 274:     /// Gets or sets the URL of the item.
 275:     /// </summary>
 276:     public string Link {
 277:         get { return (string)this[LinkName]; }
 278:         set { this[LinkName] = value; }
 279:     }
 280:  
 281:     /// <summary>
 282:     /// Gets or sets the password for the post.
 283:     /// </summary>
 284:     /// <remarks>
 285:     /// This field corresponds to the <c>wp_password</c> field of the
 286:     /// post structure.
 287:     /// </remarks>
 288:     public string Password {
 289:         get { return (string)this[PasswordName]; }
 290:         set { this[PasswordName] = value; }
 291:     }
 292:  
 293:     /// <summary>
 294:     /// Gets or sets the publication date for the post.
 295:     /// </summary>
 296:     public DateTime PublicationDate {
 297:         get { return (DateTime)this[PublicationDateName]; }
 298:         set { this[PublicationDateName] = value; }
 299:     }
 300:  
 301:     /// <summary>
 302:     /// Gets or sets a flag indicating whether the post is published.
 303:     /// </summary>
 304:     public bool Publish {
 305:         get { return (bool)this[PublishName]; }
 306:         set { this[PublishName] = value; }
 307:     }
 308:  
 309:     /// <summary>
 310:     /// Gets or sets the slug value.
 311:     /// </summary>
 312:     /// <remarks>
 313:     /// This property corresponds to the <c>wp_slug</c> field of the
 314:     /// post structure.
 315:     /// </remarks>
 316:     public string Slug {
 317:         get { return (string)this[SlugName]; }
 318:         set { this[SlugName] = value; }
 319:     }
 320:  
 321:     /// <summary>
 322:     /// Gets or sets the source information for the post.
 323:     /// </summary>
 324:     [SuppressMessage("Microsoft.Usage", "CA2227",
 325:         Justification = "Supports XML-RPC.NET")]
 326:     public XmlRpcStruct Source {
 327:         get { return (XmlRpcStruct)this[SourceName]; }
 328:         set { this[SourceName] = value; }
 329:     }
 330:  
 331:     /// <summary>
 332:     /// Gets or sets the title of the blog post.
 333:     /// </summary>
 334:     public string Title {
 335:         get { return (string)this[TitleName]; }
 336:         set { this[TitleName] = value; }
 337:     }
 338:  
 339:     /// <summary>
 340:     /// Gets or sets the collection of Trackback ping URLs associated
 341:     /// with the post.
 342:     /// </summary>
 343:     /// <remarks>
 344:     /// This property corresponds to the <c>mt_tb_ping_urls</c> field
 345:     /// of the blog post.
 346:     /// </remarks>
 347:     [SuppressMessage("Microsoft.Performance", "CA1819",
 348:         Justification = "Supports XML-RPC.NET")]
 349:     public string[] TrackbackPingUrls {
 350:         get { return (string[])this[TrackbackPingUrls]; }
 351:         set { this[TrackbackPingUrls] = value; }
 352:     }
 353:  
 354:     /// <summary>
 355:     /// Gets or sets the author of the post.
 356:     /// </summary>
 357:     /// <remarks>
 358:     /// This field corresponds to the <c>wp_author</c> field of the
 359:     /// post structure.
 360:     /// </remarks>
 361:     public string WPAuthor {
 362:         get { return (string)this[WPAuthor]; }
 363:         set { this[WPAuthor] = value; }
 364:     }
 365: }

 

The first part of the Post class's implementation contains constant definitions with the names of the fields as they appear in the structure.  The second part contains properties that make it easier to set the values of these fields.  I also made the constants for the field names public so that they could be used for the implementation of EditPost and NewPost.  You'll also notice that my Post definition has additional fields of the post that I didn't discuss earlier.  These are extension fields that are defined by the Moveable Type and WordPress APIs, which we'll discuss in the future posts as we discuss each of those extensions to our web publishing service.

The metaWeblog.getRecentPosts operation is useful to retrieve the most recently publish posts on the blog or website.  This could be useful in the implementation of a WYSIWYG editor.

   1: [XmlRpcMethod("metaWeblog.getRecentPosts",
   2:     Description = "Retrieves the most recent posts from the blog.")]
   3: XmlRpcStruct[] GetRecentPosts(string blogId, string userName,
   4:     string password, int numberOfPosts);

 

You can limit the number of posts that are returned by using the numberOfPosts parameter on the GetRecentPosts operation.

Finally, MetaWeblog defined the metaWeblog.NewMediaObject method to support uploading objects such as images embedded in a blog post to the website.

   1: [XmlRpcMethod("metaWeblog.newMediaObject",
   2:     Description = "Publishes a media object on the blog.")]
   3: NewMediaObjectResponse NewMediaObject(string blogId, string userName,
   4:     string password, MediaObject mediaObject);

 

The MediaObject class used as a parameter for the NewMediaObject operation looks like this:

   1: /// <summary>
   2: /// Stores information about a media object being uploaded to a blog
   3: /// using the <see cref="IMetaWeblogService.NewMediaObject"/> operation.
   4: /// </summary>
   5: [Serializable]
   6: [XmlRpcMissingMapping(MappingAction.Error)]
   7: public class MediaObject {
   8:     /// <summary>
   9:     /// The binary contents of the media object.
  10:     /// </summary>
  11:     [SuppressMessage("Microsoft.Design", "CA1051",
  12:         Justification = "Public fields must be exposed for XML-RPC.NET")]
  13:     public byte[] bits;
  14:  
  15:     /// <summary>
  16:     /// The name of the media object.
  17:     /// </summary>
  18:     [SuppressMessage("Microsoft.Design", "CA1051",
  19:         Justification = "Public fields must be exposed for XML-RPC.NET")]
  20:     public string name;
  21:  
  22:     /// <summary>
  23:     /// The media object's MIME content type.
  24:     /// </summary>
  25:     [SuppressMessage("Microsoft.Design", "CA1051",
  26:         Justification = "Public fields must be exposed for XML-RPC.NET")]
  27:     public string type;
  28: }

 

In this structure, name is the name or file name of the media object being uploaded, type is the MIME content type for the data being uploaded, and bits is a byte array that contains the full media object data.

The return value for the metaWeblog.newMediaObject operation is the URL of the new media object, wrapped in a structure:

   1: /// <summary>
   2: /// Represents the response of the
   3: /// <see cref="IMetaWeblogService.NewMediaObject"/> operation.
   4: /// </summary>
   5: [Serializable]
   6: [XmlRpcMissingMapping(MappingAction.Error)]
   7: public class NewMediaObjectResponse {
   8:     /// <summary>
   9:     /// The URL where the media object can be downloaded from.
  10:     /// </summary>
  11:     [SuppressMessage("Microsoft.Design", "CA1051",
  12:         Justification = "Public fields must be exposed for XML-RPC.NET")]
  13:     public string url;
  14: }

 

The full source code for the MetaWeblog API interface is below:

   1: /// <summary>
   2: /// Defines the operations supported by the MetaWeblog API for publishing
   3: /// content to a website or blog.
   4: /// </summary>
   5: public interface IMetaWeblogService {
   6:     /// <summary>
   7:     /// Updates a post that has been posted on the blog.
   8:     /// </summary>
   9:     /// <param name="postId">
  10:     /// The unique identifier for the post to update.
  11:     /// </param>
  12:     /// <param name="userName">
  13:     /// The login for a user that can edit the blog post.
  14:     /// </param>
  15:     /// <param name="password">The user's password.</param>
  16:     /// <param name="post">
  17:     /// The updated contents of the post.
  18:     /// </param>
  19:     /// <param name="publish">
  20:     /// True if the post should be published.
  21:     /// </param>
  22:     /// <returns>
  23:     /// Returns true if the post was successfully updated.
  24:     /// </returns>
  25:     [XmlRpcMethod("metaWeblog.editPost",
  26:         Description = "Updates a post that has been posted to the blog.")]
  27:     bool EditPost(string postId, string userName, string password,
  28:         Post post, bool publish);
  29:  
  30:     /// <summary>
  31:     /// Returns the list of categories for the blog.
  32:     /// </summary>
  33:     /// <param name="blogId">
  34:     /// The unique identifier of the blog.
  35:     /// </param>
  36:     /// <param name="userName">
  37:     /// The login for a user with administrator rights to the blog.
  38:     /// </param>
  39:     /// <param name="password">The user's password.</param>
  40:     /// <returns>
  41:     /// Returns an array containing the categories for the blog.
  42:     /// </returns>
  43:     [XmlRpcMethod("metaWeblog.getCategories",
  44:         Description = "Returns the categories for the blog.")]
  45:     Category[] GetCategories(string blogId, string userName,
  46:         string password);
  47:  
  48:     /// <summary>
  49:     /// Retrieves the contents of a post from the blog.
  50:     /// </summary>
  51:     /// <param name="postId">
  52:     /// The unique identifier of the post to retrieve.
  53:     /// </param>
  54:     /// <param name="userName">
  55:     /// The login for a user that can access the post.
  56:     /// </param>
  57:     /// <param name="password">
  58:     /// The user's password.
  59:     /// </param>
  60:     /// <returns>
  61:     /// Returns the contents of the post.
  62:     /// </returns>
  63:     [XmlRpcMethod("metaWeblog.getPost",
  64:         Description = "Retrieves the content for a post from the blog.")]
  65:     Post GetPost(string postId, string userName, string password);
  66:  
  67:     /// <summary>
  68:     /// Retrieves the most recent posts from the blog.
  69:     /// </summary>
  70:     /// <param name="blogId">
  71:     /// The unique identifier of the blog.
  72:     /// </param>
  73:     /// <param name="userName">
  74:     /// The login for a user that can access the blog.
  75:     /// </param>
  76:     /// <param name="password">The user's password.</param>
  77:     /// <param name="numberOfPosts">
  78:     /// The maximum number of posts to retrieve.
  79:     /// </param>
  80:     /// <returns>
  81:     /// Returns an array of blog posts.
  82:     /// </returns>
  83:     [XmlRpcMethod("metaWeblog.getRecentPosts",
  84:         Description = "Retrieves the most recent posts from the blog.")]
  85:     XmlRpcStruct[] GetRecentPosts(string blogId, string userName,
  86:         string password, int numberOfPosts);
  87:  
  88:     /// <summary>
  89:     /// Publishes a media object to the website or blog.
  90:     /// </summary>
  91:     /// <remarks>
  92:     /// This operation is used to support publishing images or other
  93:     /// items that may be embedded in a blog post.
  94:     /// </remarks>
  95:     /// <param name="blogId">
  96:     /// The unique identifier of the blog.
  97:     /// </param>
  98:     /// <param name="userName">
  99:     /// The login for a user that can publish to the blog.
 100:     /// </param>
 101:     /// <param name="password">The user's password.</param>
 102:     /// <param name="mediaObject">
 103:     /// The contents of the media object to publish to the blog.
 104:     /// </param>
 105:     /// <returns>
 106:     /// Returns the URL where the media object can be downloaded from.
 107:     /// </returns>
 108:     [XmlRpcMethod("metaWeblog.newMediaObject",
 109:         Description = "Publishes a media object on the blog.")]
 110:     NewMediaObjectResponse NewMediaObject(string blogId, string userName,
 111:         string password, MediaObject mediaObject);
 112:  
 113:     /// <summary>
 114:     /// Publishes a new post to the website or blog.
 115:     /// </summary>
 116:     /// <param name="blogId">
 117:     /// The unique identifier of the blog.
 118:     /// </param>
 119:     /// <param name="userName">
 120:     /// The login for a user that can publish to the blog.
 121:     /// </param>
 122:     /// <param name="password">The user's password.</param>
 123:     /// <param name="post">The contents of the post.</param>
 124:     /// <param name="publish">
 125:     /// True if the post should be published.
 126:     /// </param>
 127:     /// <returns>
 128:     /// Returns the unique identifier of the new post.
 129:     /// </returns>
 130:     [XmlRpcMethod("metaWeblog.newPost",
 131:         Description = "Publishes a new post to the blog.")]
 132:     string NewPost(string blogId, string userName, string password,
 133:         XmlRpcStruct post, bool publish);
 134: }

 

Now that we have the MetaWeblog API defined in a format that we can implement in .NET, the next step is to start implementing it and looking at how Microsoft Office Word 2007 and Windows Live Writer will attempt to use the API to support their editing functions.  We will cover that in the next post, hopefully with a little video demonstration.

Technorati tags: , , , ,


Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Related posts

Comments

October 1. 2009 05:11

art is a lie that tells the truth ugg classic cardy. Humor has been well defined as ugg calssic thinking in fun while feeling in earnest.The decline of literature indicates the decline of a ugg sale online nation ; the two ugg bailey button keep in their ugg classic min downward tendency. http://www.olugg.com/
|

ugg boots sale

October 1. 2009 06:00

Itisbettertowaste<ahref="www.joyceb2b.com/.../a>one'syouththan to do noting <a href="www.joyceb2b.com/...hones-c-111.html">bose headphones</a> with it at all. One <a href="http://www.joyceb2b.com/">cell phones</a> thing I know. If a jewel falls into the <a href="www.joyceb2b.com/specials.html">nokia 8800 arte</a> mire, it remains as precious as before; and though dust should ascend to <a href="http://www.joyceb2b.com/">bose in-ear headphones</a> heaven, its former worthlessness will not altered.
|

nokia8800

October 5. 2009 23:06

Fear not that the chi flat iron life shall come to an end, but rather fear that it shall never have a ghd iv dark styler beginning. ghd iv kiss styler it is while you are patiently toiling at the little tasks of ghd hair iron life that the meaning and shape of great whole ghd mk4 iron of life dawn on you. http://www.ghdhairon.com/
|

GHD Hair Iron

October 7. 2009 08:03

a wise luxury handbags on sale man never loses anything if he has chanel handbangs himself.a great jimmy choo handbags man is always willing to be little. Death is the only bottega veneta pure, beautiful conclusion of a great cheap handbags passion.When the fight begins within himself, a man's worth something. http://www.supershandbag.com/
|

supershandbag

October 12. 2009 15:51

To most ugg boots men , the ugg bailey button experience is like the stern light of an ugg lo pro button ship which il-luminates only the uggs boots track it has passed. Too much ugg knightsbridge experience is a dangerous thing. We know nothing of what will happen in future , but by the analogy of past experience. Absence to love is what wind is to fire. It extinguishes the small; it inflames the great. http://www.hideboots.com/

|

ugg bailey button

October 14. 2009 13:45

When the fight begins within ugg bailey button himself, a man's worth something ugg lo pro button.Have no fear of perfection---you'll never reach it. uggs boots it is better to die on your feet than to live on your knees. ugg boots life is not all beer and skittles. Fear not that the life shall come to an end, but rather fear that it shall never have a ugg knightsbridge beginning. http://www.4ezlive.com/
|

UGG Boots

October 26. 2009 22:59

<h2 align="center">The warmest ugg boots</h2>
<p>While access to source sheepskin is more and more expensive, in order to create the warmest and highest quality <a href="www.goodugg.co.uk/...short-c-160.html">ugg" rel="nofollow">www.goodugg.co.uk/...short-c-160.html">ugg boots</a>, we are still at the cost of manufacturing. In addition to perfect our sheep fleece, the inner is extremely dense, so that your feet are wrapped in a fleece and fluffy soft and warm.</p>
<p>--&gt;<strong>The improvements come with toes</strong><br />
Traditional <a href="www.goodugg.co.uk/...ots-p-24145.html">ugg boots</a> are cosy, soft and easy to wear. The inner sheepskin fibres are denser, plusher and much softer on your skin, and the sheepskin definitely won't scratch your skin or cause odour problems associated with tradition ugg boots. You can actually see the difference very clearly.<br>
--&gt;<strong>Designed for bare toes</strong><br />
This premium graded sheepskin <a href="www.goodugg.co.uk/...-tall-c-162.html">ugg" rel="nofollow">www.goodugg.co.uk/...-tall-c-162.html">ugg tall boots</a> creates the worlds warmest and cosiest fashion icon. The thicker inner fleece acts as natural air conditioner, circulating and maintaining body warmth on colder days. Designed for bare feet our boots offer the ultimate indulgence in luxury and comfort.<br>
--&gt;<strong>Actively remove foot odor</strong><br />
A thicker spongy fleece of <a href="www.goodugg.co.uk/...short-c-160.html">ugg" rel="nofollow">www.goodugg.co.uk/...short-c-160.html">ugg classic short</a> will circulate more air. Synthetic ugg boots created from lower grade sheepskin do not posses this ability to circulate air as effectively as merino sheepskin. <br>
--&gt;<strong>Comfortable all year round</strong><br />
The worlds warmest <a href="www.goodugg.co.uk/...-tall-c-167.html">ugg boots</a> are also the worlds coolest, but only when your feet need chilling of course! Our thicker fleece allows your toes to enjoy their favourite footwear all year round.<br>
--&gt;<strong>Fashion Laws</strong><br />
The sheepskin boots and ugg boots women choose are predominantly of the <a href="www.goodugg.co.uk/...p-23487.html">classic tall ugg boot</a> or classic short styles. Proving that sheepskin boots truly are unisex.</p>
<p>We have to savor the hidden glamour of Ugg Boots with a different angle.</p>
<p>All rights reserved, reprint, please specify source comes from <a href="www.goodugg.co.uk/.../a> --<a href="www.goodugg.co.uk/...on-c-178.html">bailey button</a>,<a href="www.goodugg.co.uk/...ridge-c-321.html">ugg knightsbridge boots</a>,<a href="www.goodugg.co.uk/...rdy-c-161.html">cardy boots</a>,<a href="www.goodugg.co.uk/...-tall-c-162.html">ugg" rel="nofollow">www.goodugg.co.uk/...-tall-c-162.html">ugg tall classic</a></p>
|

angelia110

November 23. 2009 22:23



<a href="http://www.asicscloset.com/">asics onitsuka shoes</a>
<a href="www.asicscloset.com/...50.html">Discounted Women's asics onitsuka tiger mexico 66 shoes</a>
<a href="www.asicscloset.com/...c-46_52.html">Cheap men's asics onitsuka tiger mini clubman shoes</a>
|

asics onitsuka

November 24. 2009 16:34

very interesting, great article, very usefull for us...thank you
|

mengembalikan jati diri bangsa

November 26. 2009 08:42

If a man join together to pursuit knowledge, no one can take it from him.cheap nfl jersys Books are to human beings which as nba jerseys sale emory to the individuanl nhl Jerseys.We cannot change anything mlb jerseys unless we learn and accept it, Damn does not liberate it, it oppresses.A classic adidas jerseys book which people praise but don't read.A man dies still if he has done nothing, as one who has done football child jerseys much.Education is something? which remains ofter one has forgotten everything football jerseys he learned in school.Education is something remains ofter one has forgotten everything he learned in school.http://www.nfljerseymlb.com/
|

cheap nhl jersey sale

November 26. 2009 08:42

Sorrow is peace in my heart like the ugg 5806 boots evening among the tall upside lace uggs silent trees.if you tears when you miss the ugg 5817 style boots sun, you will also miss the stars.her eager ugg 5819 fur boots face bothers my ugg 5842 classic boots dreams as the ugg 30th anniversary rain at ugg 5691 lo pro button night.once we dreamt that we were ugg 5202 infant's erin strangers. when we wake up we find that we were to love each other's. http://www.uggboots4buy.com/
|

ugg fur boots 5817

December 8. 2009 12:30

Systems, and all other contributors, offer the information provided on the website and in the
|

ugg bailey button

December 9. 2009 13:57

Hello admin, nice post.. Please keep them coming!!!
|

new games

December 9. 2009 17:37

<a href="www.realuggbuy.com/...d-p-1102.html">cheap ugg classic tall boots</a><br>
<a href="www.realuggbuy.com/...and-p-1102.html">ugg 5815 Boots on sale</a><br>
<a href="www.realuggbuy.com/...nd-p-1102.htmll">ugg classic tall chestnut</a>
|

ugg classic tall chestnut

December 11. 2009 06:24

<a href="http://www.oluggs.com/">uggs on sale</a>
<a href="www.oluggs.com/uggbaileybuttonc39.html">bailey" rel="nofollow">www.oluggs.com/...eybuttonc39.html">bailey button</a>
<a href="www.oluggs.com/uggbaileybuttonc39.html"> cheap uggs</a>
<a href="www.oluggs.com/...ccardyc27.html">discount ugg boots</a>
<a href="www.oluggs.com/...assictallc31.html">women's ugg</a>
<a href="www.oluggs.com/uggmayfairec46.html">UGG Mayfaire</a>
<a href="www.oluggs.com/...tnutbootsp1067.html">ugg classic short chestnut</a>
<a href="www.oluggs.com/...lassicshortc30.html">ugg classic short </a>
<a href="www.oluggs.com/...bootsgreyp1113.html">ugg bailey button grey</a>
<a href="www.oluggs.com/uggsundancec35.html">ugg sundance boots</a>
<a href="www.oluggs.com/uggnightfallc34.html">ugg nightfall boots</a>
<a href="www.oluggs.com/uggultratallc38.html">ugg" rel="nofollow">www.oluggs.com/uggultratallc38.html">ugg ultra tall</a>
<a href="www.oluggs.com/uggultratallc38.html">ugg" rel="nofollow">www.oluggs.com/uggultratallc38.html">ugg ultral short</a>
<a href="www.oluggs.com/...ssiccardyc27.html">cardy boots</a>
<a href="http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg boots</a>
<a href="http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg boots sale</a>
<a href="http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg boots uk</a>
<a href="http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg australia</a>
<a href="http://www.oluggs.com">cheap ugg boots</a>
<a href="www.oluggs.com/...lassiccardyc27.html">ugg cardy</a>
<a href="www.oluggs.com/uggbaileybuttonc39.html">bailey" rel="nofollow">www.oluggs.com/...eybuttonc39.html">bailey button uggs</a>
<a href="www.oluggs.com/uggbaileybuttonc39.html">ugg bailey</a>
<a href="www.oluggs.com/uggclassictallc31.html">ugg classic tall</a>
<a href="http://www.myugleahy.com/">uggs" rel="nofollow">http://www.myugleahy.com/">uggs on sale</a>
<a href="http://www.myugleahy.com/">ugg boots on sale</a>
<a href="http://www.myugleahy.com/">discount ugg boots</a><a href="www.myugleahy.com/...sicshortc86.html">UGG" rel="nofollow">www.myugleahy.com/...sicshortc86.html">UGG Classic</a>
<a href="www.myugleahy.com/...sicshortc86.html">UGG" rel="nofollow">www.myugleahy.com/...sicshortc86.html">UGG Classic Short</a>
<a href="www.myugleahy.com/...sictallc103.html">UGG Classic Tall</a>
<a href="www.myugleahy.com/...iccardyc104.html">UGG Classic Cardy</a>
<a href="www.myugleahy.com/...sicminic102.html">UGG Classic Mini</a>
|

UGGStyle

December 13. 2009 20:29

<strong><a href="www.souggs.com/specials.html">Australia Ugg Boots</a></strong> becoming more and more popular,new style <strong><a href="http://www.souggs.com/">ugg boots</a></strong> will be the best seller for this Christmas,includes<strong><a href="www.souggs.com/products_all.html">Ugg Knightsbridge</a>,<a href="www.souggs.com/...ley-button-c-2.html">UGG Bailey Button</a></strong>;and the <strong><a href="www.shoeshotsale.com/.../strong><strong><a href="www.souggs.com/ugg-tall-5815-c-3.html">ugg classic tall boots,</a></strong> <strong><a href="www.souggs.com/...cardy-5819-c-1.html">ugg cardy boots</a></strong> also hot sale for these years,you can choose your lovely <strong><a href="www.souggs.com/products_new.html">UGGS Boots</a></strong> on shoesem.com,You can choose the <strong><a href="www.souggs.com/..._products.html">discount ugg boots</a></strong> or the newest <strong><a href="www.souggs.com/.../strong> for yourself or your friends.
|

ugg

December 13. 2009 22:53

I am really enjoying reading your well written articles. It looks like you spend a lot of effort and time on your blog. I have bookmarked it and I am looking forward to reading new articles. Keep up the good work!
|

Philadelphia Flyers

December 23. 2009 23:23

This is my first time i visit here. I found so many interesting stuff in your blog especially its discussion. From the tons of comments on your articles, I guess I am not the only one having all the enjoyment here! keep up the good work.
|

Halley Reel

January 8. 2010 19:56

Hello, amazing blog post! pls continue this awesome work!!
|

tetris online

January 14. 2010 15:35

Hello, your website's theme is incredible and i like it. Your blog posts are gorgeous. Please continue this great work. Take Care!!
|

room escape games

January 30. 2010 05:16

Hi, I applaud your blog for informing people, very interesting article, keep up it coming Smile
|

vans shoes

February 10. 2010 21:22

Technological innovation and the advancement of science continue to change the market. Also, technological innovations have lowered the cost of entry for new competitors. This is because electronic-only publishers do not incur costs associated with the production, warehousing and distribution of print copies.
|

STANTON

March 4. 2010 01:14

I love watching movies online, it is way easier than going to the theaters.
|

free hd movies

March 5. 2010 19:07

Just a message to say : that rocks !
|

large wall mirrors

Add comment


 

[b][/b] - [i][/i] - [u][/u]- [quote][/quote]



Live preview

March 12. 2010 16:39

|