Migration from Orchard to MiniBlog

The past couple of days I’ve been working on migrating my blog from the Orchard CMS to MiniBlog. The main reason for me to migrate to a different system is because I don’t work a lot with Orchard anymore. There were also some crashes from time to time which I couldn’t explain.

I’m currently hosting my websites on Azure Websites, because of that I didn’t feel much for using a database system. SQL Azure is very nice of course, but it can also be quite expensive, especially if you don’t really need the features. The alternative is SQL Compact, but I’m not very keen on using this as well.

While searching for a database-less blogging system, I came across several solutions like Ghost, Jekyll and MiniBlog. All of these systems are slightly different and work with different techniques. The main reason I’m using MiniBlog as my new blogging engine is because it’s based on .NET. I could list all the cool features which are included, but as it’s already stated on the GitHub page, I won’t repeat it over here.

MiniBlog is a system which saves it’s posts in XML files. Therefore, I had to migrate all of my posts from the Orchard database to the files which MiniBlog understands. There’s already a project on GitHub called MiniBlogFormatter. This tool is able to export posts from DasBlog, BlogEngine.NET and WordPress to the MiniBlog format. I’ve used the code from this project as a basis for exporting my own Orchard posts.

It would have been cool if I was able to extend the MiniBlogFormatter project with my Orchard exporting code. There was however one caveat for this, I don’t know how to access the Orchard API from a remote application. I do know how to create modules, therefore I’ve created a module which was able to export the posts in the necessary format. If you want to know how to create an Orchard module yourself, there’s a post on this blog where I elaborate more on this.

The module itself isn’t fool-proof and user friendly (yet). It’s available on GitHub, so you can use it if you want or use it as inspiration for your own solution.

You can see I’ve created a new route so my own controller will be triggered.

new RouteDescriptor {
    Priority = 5,
    Route = new Route(
        "Migrate",
        new RouteValueDictionary {
                                    {"area", "JanVNL.Migrate"},
                                    {"controller", "Migrate"},
                                    {"action", "index"}
                                },
        null,
        new RouteValueDictionary {
                                    {"area", "JanVNL.Migrate"}
                                },
        new MvcRouteHandler())
}

The MigrateController will eventually hit the Initialize-method in the GetBlogPost class, which looks like this:

internal ICollection<blogpost> Initialize(bool redirect)
{
	var blog = Retriever.GetBlog(_blogService);
	var blogPosts = _blogPostService.Get(blog, VersionOptions.Published);
	_allBlogPosts = new List<blogpost>();
	string redirects = string.Empty;
	foreach (var blogPostPart in blogPosts)
	{
		if (redirect)
		{
			string currentSlug = GetUrl(blogPostPart);
			string redirectRule = "<location path=\"{0}\"><system.webServer><httpRedirect enabled=\"true\" destination=\"https://jan-v.nl/post/{0}\" httpResponseStatus=\"Permanent\" /></system.webServer></location>";
			redirects = redirects + string.Format(redirectRule, currentSlug);
		}
		else 
		{
			var blogPost = new BlogPost();
			blogPost.Title = blogPostPart.Title;
			blogPost.Content = blogPostPart.Text;
			blogPost.PubDate = blogPostPart.PublishedUtc.Value;
			blogPost.LastModified = blogPostPart.PublishedUtc.Value;
			//blogPost.Categories = blogPostPart.;
			blogPost.Slug = GetUrl(blogPostPart);
			blogPost.Author = blogPostPart.Creator.UserName;
			blogPost.IsPublished = true;
			_allBlogPosts.Add(blogPost);
			Storage.Save(blogPost, string.Format("C:\\BlogPosts\\{0}.xml", blogPost.Slug));
		}
	}
	return _allBlogPosts;
}

In this piece of code I’m iterating through all blog posts, converting them one by one to a BlogPost object and storing them using the Storage class. The BlogPost and Storage class are copied from the MiniBlogFormatter repository.

You probably also noticed the if-statement with the redirect variable. I’m using this variable to switch between saving the blog posts and generating a web.config block for adding the redirect rules. To retrieve the redirect rules, you have to set a breakpoint in the code and copy the contents of the redirects variable to the web.config. Not very user friendly, indeed.

This code worked for Orchard 1.7.2. I’m fairly sure it will also work on Orchard 1.5.x. and above. You can try it on other versions of course, most of the time you’ll get decent warnings or errors if something doesn’t work properly.


Share