Rick Strahl's Web Log

Wind, waves, code and everything in between...
ASP.NET • C# • HTML5 • JavaScript • AngularJs
Contact   •   Articles   •   Products   •   Support   •   Search
Ad-free experience sponsored by:
ASPOSE - the market leader of .NET and Java APIs for file formats – natively work with DOCX, XLSX, PPT, PDF, images and more

Extending Live Writer for Blog Posting


:P
On this page:

I've been using Live Writer for writing blog posts for some time and I'mvery happy with the way I can post entries to my Web Log. The process is pretty damn painless compared to what I went through with using Word and uploading images separately at the time.

Plug In Creation

Over the last year I've written a few enhancements to Live Writer to help make my life easier by creating a few small add-ins. The one I probably use the most is the SnagIt Screen Capture plug in that lets me capture screen shots with SnagIt and embed them into messages. Live Writer will pick up the captured images and post them to the server without anything staying being on my local machine.

Another small plug in is the Amazon Link Inserter which I unforutnately don't use enough of <s>, but it basically lets you pick books and inject the images. I actually created two versions of this plug in - a WinForm version and a WPF version which is a bit more visual.

One thing I do A LOT of when writing blog posts is paste code from Visual Studio. There are a number of these things around already but one thing most of these tools don't do is automatically strip off the leading spaces and format the code 'just the way I like it' which is pretty basic - stripped of margins and left padding (so when you pick a snippet in the middle of a class you don't get all the indenting from namespace, class, method for example).  I just want to go into Visual Studio copy a piece of code and simple click on the add-in and paste it into Live Writer without any special formatting I have to do in Visual Studio or in Live Writer.

So yesterday I finally sat down and created - yup , yet another Paste from Visual Studio plug-in. To do this I created another small plug-in that takes advantage of JT Leigh's Copy as HTML plug in for Visual Studio. Some people scoff at an add-in for source formatting, but the VS add-in is highly configurable in its formatting and it comes with the source code. In fact I've used the RTF formatting code in a number of places before - it's easy to drop into anything to pick up HTML code from Visual Studio.

His plug-in provides the source code for turning Visual Studio's RTF code into HTML and I hi-jacked his code into this plug to do a non-configured and preset paste operation with default settings that strip all left indents and use Courier New for pasting. Since I do a shitload of pasting from Visual Studio code this saves a lot of time during posting, not having to futz around with various options. Incidentally prior to putting together this add-in I would use the Visual Studio Plug in to Copy as HTML from Visual Studio and then use the Insert Html From Clipboard plugin to paste it into the live writer. With this new option I just cut in Visual Studio and use my Insert from Visual Studio button to paste and it's always formatted the same way. Cool.

While I was at it - I actually also created a Insert Html From Clipboard plugin (into the same assembly) just because it's so damn trivial. From within Live Writer it's a snap to just pick up the clipboard text which can be HTML text and directly paste it into Live Writer via the plug in. It's literally 2 lines of code.

Just to give you an idea here how easy it is to create a plugin for LiveWriter here's the Paste Html plug in which only grabs the text from the clipboard:

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using WindowsLive.Writer.Api;
 
namespace PasteCodeAndHtml
{
    [WriterPluginAttribute
   ("6317F6F1-D284-45D3-9634-99EEAD02D16C",
    "Paste as Html",
    ImagePath = "Images.Paste.png",
    PublisherUrl = "http://www.west-wind.com/",
    Description = "Paste html from your clipboard into the post")]
 
 
    [InsertableContentSourceAttribute("Html from Clipboard")]
    public class Plugin : ContentSource
    {
        public override DialogResult CreateContent(IWin32Window dialogOwner, ref string newContent)
        {
            DialogResult result = DialogResult.OK;
            if (Clipboard.ContainsText() == true)
            {
                // *** Grab the HTML from the clipboard and add a break afterward so text goes back to 'normal' ALWAYS on a new line.
                newContent = Clipboard.GetText() + "<p></p>\r\n";
            }
           
            return result;
        }
    }
}

The idea is simply to set newContent to whatever the content of your insertion text is - in this case the HTML from the clipboard which is simply retrieved as text. For the Paste from Visual Studio code I pass the clipboard's RTF text to J. Leigh's Copy to HTML formatter which turns the VS code into an HTML string (properly formatted to the defaults I set) and then that is pasted into the page. For the SnagIt plug in and <img> tag is injected with a link to an internal filename that Live Writer automatically fixes up. It's extremely easy to create a content plug in that provides some customized functionality.

You can download the code from the Visual Studio Code and Insert Html From Clipboard plug in here if you're interested or you want to tweak the behavior a bit.

Live Writer Posting API

With a little time on my hands for this long weekend I also finally got around to making a few adjustments to my WebLog's MetaWebLog API to support some of the enhanced features that Live Writer supports for posting message content. Basically Live Writer supports various blog engines including WordPress and Movable Type both of which provide some extended features that MetaWebLogApi doesn't support. A couple of things I have support in my blog for and I always have been updating after Live Writer posted them is the Post Abstract (Excerpt) and Keywords.

Live Writer allows you to tell what features your blog supports  by providing a manifest XML file on the server in your Web log's root directory. Inside of that XML file  you can specify any features that you want above and beyond the default settings for the specified provider. So I use MetaWebLogAPI for example and I can then add a few features like this:

<?xml version="1.0" encoding="utf-8" ?>
<manifest xmlns="http://schemas.microsoft.com/wlw/manifest/weblog">
  <options>
    <clientType>Metaweblog</clientType>
    <supportsNewCategories>Yes</supportsNewCategories>    
    <supportsEmbeds>Yes</supportsEmbeds>
    <supportsExcerpt>Yes</supportsExcerpt>
    <supportsKeywords>Yes</supportsKeywords>
    <supportsAuthor>Yes</supportsAuthor>
    <supportsExtendedEntries>Yes</supportsExtendedEntries>
  </options>
</manifest>

Once you've added 'extra' features to the manifest any Post updloads/edits will cause Live Writer to add additional MetaWebLogAPI properties to each of the Post uploads and display additional fields in the Live Writer UI:

AdditionalProps

Here the Keywords, Author and Excerpt fields are additional fields that aren't visible by default unless the manifest file specifies these fields are available (at least for MetaWebLogAPI).

Some time ago I posted my implementation of MetaWebLogAPI which is heavily based on SubText's and Charles Cook's Xml-Rpc implementation. Working with these API classes is totally easy and what's nice is that in order to support the above Live Writer extensions is as easy as adding properties to the Post structure in the MetaWebLogAPI implementation:

[XmlRpcMissingMapping(MappingAction.Ignore)]
public struct Post
{
    [XmlRpcMissingMapping(MappingAction.Error)]
    [XmlRpcMember(Description = "Required")]
    public DateTime dateCreated;
    [XmlRpcMissingMapping(MappingAction.Error)]
    [XmlRpcMember(Description = "Required")]
    public string description;
    [XmlRpcMissingMapping(MappingAction.Error)]
    [XmlRpcMember(Description = "Required")]
    public string title;
 
    public string[] categories;
    public Enclosure enclosure;
    public string link;
    public string postabstract;
    public string permalink;
 
    [XmlRpcMember(Description = "Not required when posting. Type may be either int or string")]
    public object postid;
    public Source source;
    public string userid;
 
    //*** Live Writer Extended Properties
    public string mt_excerpt;
    public string mt_keywords;        
}

The property names match the names of the 'fields' that Live Writer is adding to the post update content and once the fields have been added to the structure these values simple show up in any methods that receive Post as a parameter:

public string newPost(object blogid, string username, string password, Post post, bool publish)
{
    this.ValidateUser(username, password);
 
    busEntry Entry = WebLogFactory.GetEntry();
 
    blog_Entries LastEntry = null;
 
    if (Entry.LoadLastPost())
    {                
        // *** Disconnect the DataRow
        LastEntry = Entry.Entity;
        LastEntry.SynchronizeFieldsToDataRow(true);
    }
 
    Entry.New();
 
    Entry.Entity.Title = post.title;
    Entry.Entity.Body = post.description;
    Entry.Entity.Author = post.userid;
 
 
    if (post.dateCreated.Year > 2000)
        Entry.Entity.Entered = post.dateCreated;
    else
        Entry.Entity.Entered = DateTime.Now;
 
    if (post.categories != null)
    {
        string Categories = "";
        foreach (string Category in post.categories)
            Categories += Category + ",";
 
        Entry.Entity.Categories = Categories.TrimEnd(',');
    }
 
    // *** Extended Properties
    if (!string.IsNullOrEmpty(post.mt_excerpt))
        Entry.Entity.Abstract = post.mt_excerpt;
 
    if (!string.IsNullOrEmpty(post.mt_keywords))
        Entry.Entity.Keywords = post.mt_keywords;
 
 
    Entry.Entity.Active = publish;
    Entry.Entity.Author = App.Configuration.WebLogAuthor;
 
    if (LastEntry != null)
        Entry.Entity.Location = LastEntry.Location;
 
    if (!Entry.Save())
       throw new XmlRpcException("Failed to save new entry: " + Entry.ErrorMessage);
 
    return Entry.Entity.Pk.ToString();
}

Although these are little things they are saving me a trip into the admin interface which is a small but frequent timesaver.

Live Writer is nice because it's extensible - if you're using it and using it as frequently as I do, it might be worthwhile to dig into the API and see what you can do to optimize your own workflow. Most of the extensibility features are super easy to hook into with .NET code and it may well save you a bunch of time and maybe even get you to post a few additional posts from time to time...

Posted in Live Writer  

The Voices of Reason


 

Sylvain Bujold
January 03, 2008

# re: Extending Live Writer for Blog Posting

Do you have any tricks to easily paste (and format) formatted VFP code within a post ? I use the 'Insert Code' plugin but it doesn't support VFP.

Rick Strahl
January 03, 2008

# re: Extending Live Writer for Blog Posting

The Paste Code from VS plug in works mostly. It's not fully correct (mainly comments don't work) but it's close enough. The problem is that VFP's RTF formatting is very different from Visual Studio's and so most VS code converters won't work on it.

Joe Cheng [MSFT]
January 04, 2008

# re: Extending Live Writer for Blog Posting


West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2020