About those view locator conventions Wednesday, 22 Oct, 2014

As I mentioned in a previous post, I do not like some of the default PRISM view location conventions.

As a refresher, these are:

It's the view naming that I don't like: In my world (which is based on Caliburn.Micro and ReactiveUI), views should be named MyAwesomeView. This is a simple distinction, but an important one for me because I automatically expect view names to end in View.

Fortunately in PRISM 5, this is easy to change:

ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver(viewType =>
{
    var viewName = viewType.FullName;
    var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
    var viewModelName = string.Format(CultureInfo.InvariantCulture, " {0}Model, {1} ", viewName.Replace("Views", "ViewModels"), viewAssemblyName);
    return Type.GetType(viewModelName);
});

We get the full name of the view, and the full name of the assembly, and then replace "Views" for the "ViewModels" folder, and add "Model" to the end. I would call this somewhere in your applications startup, such as in the bootstrapper Run.

Autowiring

Something else that you can do in PRISM 5, is autowire the view model and view such that the DataContext of the view is automatically populated.

ViewModelLocationProvider.SetDefaultViewModelFactory(type => Container.GetInstance(type));

I'm using StructureMap here (of which I am a big fan), but you should be able to get to work with your favourite IoC library.

This though, means that you have to tell StructureMap about all your views in order for it to be able to resolve them. That's too much messing about remembering having to update a Registry everytime I add a view. StructureMap can solve that for us no problem:

public class ViewRegistrationConvention : IRegistrationConvention
{
    public void Process(Type type, Registry registry)
    {
        if (!type.Name.EndsWith("View") || ! type.IsConcrete()) return ;

        registry.For(typeof(object)).Use(type).Named(type.Name);
    }
}

Here we say that if the name of the type being resolved ends with "View", and it is a concrete type (i.e. not an abstract class or interface), then add it to the registry. The trick with PRISM is that it is asking to resolve an object with a specific name, it doesn't try to resolve the type of the view, so adding something to the registry as For<MyAwesomeView>().Use<MyAwesomeView>() won't work, you have to use For(typeof(object)) and make it a named instance, using the name of the type.

And then just register the convention when you configure the container:

Container.Configure(configure =>
{
    configure.Scan(scan =>
    {
        ...
        scan.Convention<ViewRegistrationConvention>();
    });
});

Then from the region manager, you can RequestNavigate("AwesomeRegion", new Uri(typeof(MyAwesomeView))), or use the extension method in my previous post.


A useful PRISM extension method Monday, 20 Oct, 2014

I'm doing some work with Microsoft Prism at the moment, and once again I've gotten annoyed that RequestNavigate doesn't have a generic overload.

Naturally I had to write it, again:


public static class RegionManagerExtensions
{
    public void RequestNavigate(this IRegionManager regionManager, string regionName)
    {
        regionManager.RequestNavigate(regionName, new Uri(typeof(TView), UriKind.Relative).Name));
    }
}

the new Uri(typeof(TView)...) works because of the view locator conventions I've implemented.


How I moved my blog to sandra snow, part two Friday, 30 May, 2014

Once you have liberated your content from Wordpress, getting it generated by Snow is fairly trivial.

  1. Compile Snow.
  2. Copy SnowSite somewhere.
  3. Copy the fresh Snow files into a sub folder of the folder you created in #2. Mine is called _compiler and contains snow.exe, Nancy.dll, Nancy.ViewEngines.Razor.dll and Nancy.Testing.dll.
  4. Clean out the _posts folder, as it contains the markdown for philiphaydon.com, who is the creator of Snow.
  5. Edit the snow.config. You'll want to change things to reflect your details, e.g. your name, email, blog title etc. The urlFormat is important. Mine is set to yyyy/MM/dd/slug, which follows the same pattern as my old wordpres blog. This important because it means that the blog posts be generated with the same url, which means I don't have to dick about with 302 redirects or any of that shit.
  6. Compile your site. This is best achieved via a batch file which should live in the folder above the \Snow folder you created in #2. The batch file will look something like:
echo off
cls
.\Snow\_compiler\Snow.exe config=.\Snow\ debug=true server=true

Here, we tell snow where to find the snow.config file, specify that we'd like snow to give us some debug output to the console window, and that we want it to fire up its built in web server so that we can preview our site.

Name the batch file compile.snow.bat so that Snow doesn't delete it when it compiles your site. When you now execute the batch file, Snow should compile your blog and fire it up in your default webbrowser, so you can check it out, and make sure it looks ok.

At this point, you should be ready to deploy your site somewhere.


How I moved my blog from wordpress to snow, part one Monday, 03 Mar, 2014

Wherein I show you how I moved my blog from Wordpress, to a statically generated html hosted on github. I will assume that you have a wordpress blog, hosted on either Wordpress.com or your own hosting. If you don't have a wordpress based blog, then that's ok, most of this will still apply.

We can identify a pretty broad set of tasks straightaway:

  1. Export posts from wordpress into markdown.
  2. Configure Sandra.Snow to publish our markdown.
  3. Make it look nice.
  4. Setup github to publish our new site.
  5. Update our DNS settings.

Liberating content from Wordpress

Export wordpress content

Jekyll has some tooling that enables auto-exporting of your blog and its contents into markdown for you, but as it is still (relativly) early days for Sandra.Snow, there is no such tooling for us to leverage.

Wordpress makes it fairly easy to export your blog posts, pages, comments and some other meta-information, packaging everything up into a single XML file, that depending on the number of blog post and other content you have, can be fairly large.

When you click export, you'll be able to download the XML file containing your content. Now we just have to pull out what we want.

wp2md

I looked around for something that would do the conversion of my wordpress content into markdown, but I couldn't find one that I liked, or that worked exactly the way that I wanted it to. So I wrote my own.

The export file format isn't documented anywhere that I could find online, there were a few bits and pieces here and there on blogs and on some forums, but, honestly, it's just an xml file, it's not all that difficult. The only thing that may trip you up is the number of xml namespaces it uses, although if like me you've had a job maintaining software which manages complex xml, then it's no big deal.

I found it has a root <rss> element, followed by <channel> and then <item> where an item is a post, comment or even a page. An item is then broken down into further child elements which include things like the title of the post (or page, or comment), the url, publication date, actual content of the post, and various other pieces of meta data about the post. For example:

<title>Definitely given up on my github-csharp-api project</title>
<link>http://temporalcohesion.co.uk/2013/11/07/definitely-given-up-on-my-github-csharp-api-project/</link>
<pubDate>Thu, 07 Nov 2013 21:08:19 +0000</pubDate>
<dc:creator><![CDATA[stuart]]></dc:creator>
<guid isPermaLink="false">http://temporalcohesion.co.uk/?p=394</guid>
<description></description>
<content:encoded><![CDATA[Not that I'd spent much time working on it lately. The fine folks at github have released Ocktokit.net, a C# library for accessing the github api. It's an official api - it renders my crappy project useless, so I'm putting it down completely.

I will not work on it anymore.]]></content:encoded>
<excerpt:encoded><![CDATA[]]></excerpt:encoded>
<wp:post_id>394</wp:post_id>
<wp:post_date>2013-11-07 21:08:19</wp:post_date>
<wp:post_date_gmt>2013-11-07 21:08:19</wp:post_date_gmt>
......

So I defined a POCO Item.cs model class to hold everything interesting about a post, and then parsed the document to get all of the items.

Items = (from item in _document.Root.Element("channel").Elements("item")
  select new Item
  {
    Title = item.Element("title").Value,
    PublicationDate = ParseDateTime(item.Element("pubDate").Value),
    Author = item.Element(dc + "creator").Value,
    ....
  }).ToList()

Fairly standard Linq-to-Object parsing of the XML document. You can see the XML Namespace dc being used, that is just a static namespace member defined as private static XNamespace dc = "http://purl.org/dc/elements/1.1/"; at the top of the class.

Now that we have a whole bunch of Items, we can move on to generating the markdown.

Markdown is really fairly simple. Before I embarked on this process, I'd never realised how powerfully simple it is. Our Item now contains the (mostly) encoded content of our post, so we don't have any worry about doing any escaped html removal. To my eyes, and someone correct me if I'm wrong, but it seems to me that Wordpress virtually converts our content into markdown when it generates the export. I could be wrong, but it's what it looks like to me.

We can then use the Visitor pattern to control how we want our Items to be processed.

parser.Parse(document);
parser.VisitWith(new PostVisitor());

I did not have very many pages on my wordpress blog, so I was not concerned with converting them. Similarly, I'd already converted my wordpress blog to use disqus comments, so I did not need to write a Visitor to handle converting the comments.

As this post is already getting fairly long, I will leave a discussion of the Visitor pattern to another time, but you can see the PostVisitor implementation in detail in the repo on Github.com.


Extending Sandra.Snow Wednesday, 19 Feb, 2014

After switching my blog over to use Sandra.Snow, I noticed that in at least one feed aggregator that my blog shows up in, it wasn't displaying correct. The escaped html in the feed generator from the markdown by Snow wasn't getting rendered in the aggregator correctly. After a little digging it was apparant to me that the RssResponse in Snow was not correctly setting it's content type.

I could have left it there, or submitted a small patch to fix the issue (I still will), but I noticed that the feed it generates isn't a pure atom feed, so I basically copied the relevant classes (changing 'rss' to 'atom') in the class names, and did a little configuration, and swapped over the feed to use atom.

Even though I know that the atom feed validates, this post is in part a test to see what happens...