Migration to BlogEngine.NET

It was about time I migrated my weblog, based on .Text version 0.95 to a more modern blogging platform. As you will probably know, the codebase of .Text was integrated to Community Server ages ago. I doubt whether much of that original code is still alive in CS, if any at all.

Anyway, both BlogEngine.NET and dasBlog seemed like good alternatives. Subtext too. I decided to go with BlogEngine.NET. It’s not that I did extensive research on all the options, as long I was able to migrate the content and use Live Writer for posting. A post by Erik Lane helped me through it. He also posts instructions on how to keep old links working. I didn’t want to mess in the code of BlogEngine.NET, so after updating the BE.NET database, I just added the following hack to global.asax:

    protected void Application_BeginRequest(object sender, EventArgs e)


        HttpContext context = HttpContext.Current;


        // Handle .Text rss feed requests.

        if (context.Request.Url.PathAndQuery.ToLower().Contains("/rss.aspx"))


            context.Response.Redirect("syndication.axd", false);

            context.Response.StatusCode = 301;




        // Handle .Text requests from archived posts

        if (context.Request.Url.PathAndQuery.Contains("/archive/"))


            // lookup post

            int dotTextPostId = GetPostId(context.Request.Url.PathAndQuery);

            System.Collections.Generic.Dictionary<int, string> posts = GetPosts();


            string relativeLink = string.Empty;

            if (posts.ContainsKey(dotTextPostId))

                relativeLink = posts[dotTextPostId];


            string redirUrl = string.Format("{0}://{1}{2}",

context.Request.Url.Scheme, context.Request.Url.Authority,


            context.Response.Redirect(redirUrl, false);

            context.Response.StatusCode = 301;





    private static readonly Regex DOTTEXT =

new Regex(@"/archive/\d{4}/\d{2}/\d{2}/(?<postId>\d+)\.aspx$",

        RegexOptions.IgnoreCase | RegexOptions.Compiled);


    private int GetPostId(string url)


        Match match = DOTTEXT.Match(url);

        if (match.Groups.Count > 0)


            int postId;

            if (int.TryParse(match.Groups["postId"].ToString(), out postId))


                return postId;



        return 0;



    // Retrieve a list of old posts, cache the result

    protected System.Collections.Generic.Dictionary<int, string> GetPosts()


        System.Collections.Generic.Dictionary<int, string> posts =

HttpContext.Current.Cache["posts"] as

            System.Collections.Generic.Dictionary<int, string>;

        if (posts != null) return posts;


        posts = new System.Collections.Generic.Dictionary<int, string>();


        string query =

"SELECT PostID, DottextPostID FROM be_Posts WHERE DottextPostID IS NOT NULL";


        System.Data.SqlClient.SqlDataAdapter sqlDa =

            new System.Data.SqlClient.SqlDataAdapter(query,



        System.Data.DataTable postTable = new System.Data.DataTable();


        foreach (System.Data.DataRow item in postTable.Rows)


            Post p = Post.GetPost((Guid)item["PostID"]);

            posts.Add(int.Parse(item["DottextPostID"].ToString()), p.RelativeLink);



        HttpContext.Current.Cache.Add("posts", posts, null, DateTime.MaxValue,

Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);

        return posts;


It may not be the most well-designed code, but it does the trick.