Anders Tornblad

All about the code

Monthly archive for January 2016

Complete blog remake, part 1

For a while now, I have been thinking of migrating this blog to a completely different environment. I have grown really tired of the two most important technical aspects of this blog: the hosting provider, and the blog platform.

Leaving WordPress

For some bloggers, WordPress is the way to go. The platform is pretty easy to use, even if there is a bit of a learning curve, and it's still capable enough for more advanced blogging solutions, especially if you are ready to go down the messy plugin path. For lots of blogs, WordPress does the job.

However, for my needs, WordPress is too big, too small, and too messy. Too big, because what I really only need is to serve some text to readers. This can be done with a static filesystem serving articles. But I also need archives, search and some structure in the form of categories and labels. WordPress does that but so could I. Too small, because I want to be able to show nicely formatted source code in different languages, display some graphics based on data, link to my spare-time projects and GitHub repositories in a good way. There are plugins for all of those, but WordPress plugins tend to be really messy. Too messy, in fact, because the WordPress core and all those plugins tend to make it difficult to properly keep blogs upgraded and secure. You should always apply security patches, but that might break some plugin that hasn't got around to patching or upgrading yet.

There are more arguments for leaving WordPress behind, and I think Daniel Thornbury said it best.

Writing my own blog engine couldn't be that difficult. After all, it's just a matter of mapping urls to information, right? That's what web servers do. When looking at my WordPress configuration, I realized that I should be able to create a very simple ASP.NET MVC site to do all this for me. This is a run-down of what addresses are handled:

Addresses for routing

All of this could be handles with a pretty simple chain of calls to MapRoute, like this:

public static void RegisterRoutes(RouteCollection routes) { routes.MapRoute( name : "MonthlyArchivePage", url : "{year}/{month}/page/{page}", constraints : new { year = @"^\d{4}$", month = @"^\d{2}$", page = @"^\d+$" }, defaults : new { controller = "Archive", action = "MonthPage" } ); routes.MapRoute( name : "MonthlyArchiveFirstPage", url : "{year}/{month}", constraints : new { year = @"^\d{4}$", month = @"^\d{2}$" }, defaults : new { controller = "Archive", action = "MonthPage", page = 1 } ); routes.MapRoute( name : "LabelPage", url : "label/{name}/page/{page}", constraints : new { page = @"^\d+$" }, defaults : new { controller = "Archive", action = "LabelPage" } ); routes.MapRoute( name : "LabelPageFirstPage", url : "label/{name}", defaults : new { controller = "Archive", action = "LabelPage", page = 1 } ); routes.MapRoute( name : "CategoryPage", url : "category/{name}/page/{page}", constraints : new { page = @"^\d+$" }, defaults : new { controller = "Archive", action = "CategoryPage" } ); routes.MapRoute( name : "CategoryPageFirstPage", url : "category/{name}", defaults : new { controller = "Archive", action = "CategoryPage", page = 1 } ); routes.MapRoute( name : "Search", url : "search", defaults : new { controller = "Search", action = "Index" } ); routes.MapRoute( name : "Feed", url : "feed", defaults : new { controller = "Feed", action = "Index" } ); routes.MapRoute( name : "StartPage", url : "page/{page}", constraints : new { page = @"^\d+$" }, defaults : new { controller = "Start", action = "Page" } ); routes.MapRoute( name : "SingleArticle", url : "{postname}", defaults : new { controller = "Article", action = "Single" } ); routes.MapRoute( name : "StartFirstPage", url : "", defaults : new { controller = "Start", action = "Page", page = 1 } ); }

With a total of five controller classes and just seven action methods, the MVC part is really simple. Each method has a non-complex data query and a corresponding view, all sharing a common set of "master page" layout views. The paginated views (start page and archive pages) all share their pagination technique, so I only have to write it once. These are some examples of how simple the code can be:

public class ArchiveController : Controller { public ActionResult MonthPage(int year, int month, int page) { DateTime startDate = new DateTime(year, month, 1); DateTime endDate = startDate.AddMonths(1); var query = from article in ApplicationData.Current.Articles where article.Published >= startDate && article.Published < endDate select article; var model = new ArchivePageModel { AllArticles = query.ToArray(), Page = page, PageSize = 10, Title = "Monthly archive for " + startDate.ToString("MMMM yyyy") }; return View("Page", model); } public ActionResult LabelPage(string name, int page) { var query = from article in ApplicationData.Current.Articles where article.Labels.Contains(name, StringComparer.InvariantCultureIgnoreCase) select article; var model = new ArchivePageModel { AllArticles = query.ToArray(), Page = page, PageSize = 10, Title = $"Label archive for {name}" }; return View("Page", model); } } public class ArticleController : Controller { public ActionResult Single(string postname) { var article = ApplicationData.Current.SingleOrDefault(a => a.PostName.Equals(postname, StringComparison.InvariantCultureIgnoreCase)); if (article == null) { return HttpNotFound(); } return View(article); } }

I also want to keep the data backend super-simple, so I actually decided to go with putting the articles on files in the App_Data folder, and storing the entire dataset in the HttpApplicationState object, effectively caching everything in-memory between app restarts. But since I don't want to actually restart the application every time I add a new post, I also write a "data refresh" action method that clears and rebuilds the cache. That method is set up with some added security so that it can only be called from localhost.

All in all, writing all the C# code needed for migrating from WordPress to ASP.NET MVC takes about a day. Adding some nice CSS stuff and JavaScript takes another day.

Leaving Loopia

For several years now, I have been a customer of Swedish web hosting provider Loopia. They have always been almost good enough, not quite living up to 100 % of my expectations. When ASP.NET 4 came out, it took Loopia almost two years to provide it to customers, and then ASP.NET 4.5 was already in the works. Their current version of PHP is 5.5.11, which was release almost two years ago. This is really bad for several reasons.

I'm not talking about web developers wanting the latest shiny toys to play with (even if that is also the case). No, I'm talking about security and quality. Failing to upgrade means failing to install security patches. I'm not demanding an upgrade to PHP 7, and not even PHP 5.6, but at the very least they should upgrade to 5.5.30, which has had a lot of bugfixes and security added since 5.5.11.

Loopia has worked for me in the past, but they have also always been a little too expensive given what they provide. Too little, too late, too expensive.

So I decided to move to Microsoft Azure. With a really nice set of tools available for developers, and an exquisitely well-made integration with Visual Studio, the choice was simple. I can design and create my blog, run all my tests, publish it and even debug it remotely from within the same tool.

Brave new world

So I did a full move. From PHP to ASP.NET and C#. From Loopia to Microsoft Azure. From MySQL to filesystem. From WordPress to my own creation. And it's all in the cloud, monitored, secure, load-balanced, and almost completely free!

Next time, I will talk a little about the Azure part of the move. Deployment, scheduled jobs, monitoring and so on.

Complete blog remake, part 1 (this part)
Complete blog remake, part 2
403s for the Naughty List