This marks a significant moment in my blog's lifetime. Today I (finally) took the time to migrate the blog from .Text .95 to DasBlog 2.0.
I have long desired to move off of .Text for a couple of reasons: 1) it has long not been updated (yes, I know about the SubText branch) and 2) it runs on the .NET Framework 1.1. In and of itself, .NET 1.1 is not bad. In fact, I think it was a pretty rockin' platform 7 years ago.
I have recently acquired Back in February I acquired a replacement server machine for two workstations that I was using as my web servers. This machine has, except for a few moments of glory, sat still, quiet, and off in my office just waiting to run. Well, today, I finally had a moment to dedicate to get the DasBlog engine running and all of my websites transferred over to the new machine. This new box is running Windows Server 2008 and IIS 7.0 (another reason I wanted to move my blog over to the newer .NET platform). Thus far, DasBlog is running great and I'm very much enjoying it.
Despite conducting several searches I couldn't find any real help or canned utilities for taking .Text content and migrating it. Pretty much everything led to a dead-end (404) or a SourceForge project that had no downloads. I did, however, stumble upon some code written by Scott Hanselman that illustrated in a few simple steps the process of creating DasText entries and associated comments. I've taken this code and tailored it for .Text. If you're migrating from a .Text with multiple blogs you'll have to customize it a bit, but it should be pretty simple.
I've updated the code to extract blog posts, associated categories, and comments. NOTE: This code was not written to be elegant; it's really just a brute-forced-extraction of the data. That's all I was interested in. I only ever needed to run it once and then I was done.
NOTE: THIS CODE IS OBSOLETE AND HAS BEEN REPLACED AND UPDATED IN THIS POST.
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using newtelligence.DasBlog.Runtime;
namespace ConvDotTextToDasBlog {
class Program {
static void Main(string[] args) {
IBlogDataService dataService = BlogDataServiceFactory.GetService(AppDomain.CurrentDomain.BaseDirectory, null);
string connStr = @"Initial Catalog=Blog; Data Source=(local); Integrated Security=True";
using ( SqlConnection conn = new SqlConnection(connStr) ) {
conn.Open();
using ( SqlCommand cmPosts = new SqlCommand("SELECT COUNT(ID) FROM blog_Content WHERE PostType=1; SELECT * FROM blog_Content WHERE PostType=1", conn) ) {
using ( SqlDataReader drPosts = cmPosts.ExecuteReader() ) {
drPosts.Read();
int totalCount = drPosts.GetInt32(0);
drPosts.NextResult();
int currIndex = 0;
while ( drPosts.Read() ) {
int postId = drPosts.GetInt32(0);
string postTitle = drPosts.IsDBNull(1) ? string.Empty : drPosts.GetString(1);
DateTime dtCreated = drPosts.GetDateTime(2);
DateTime dtModified = drPosts.GetDateTime(10);
string postText = drPosts.GetString(12);
string postAuthor = drPosts.GetString(5);
Console.WriteLine("Processing Post #{0} ({1} of {2})", postId, ++currIndex, totalCount);
Entry entry = new Entry();
entry.CreatedLocalTime = dtCreated;
entry.ModifiedLocalTime = dtModified;
entry.Title = ( postTitle.Length > 0 ? postTitle : postText.Substring(0, Math.Min(20, postText.Length)) );
entry.Content = postText;
entry.EntryId = postId.ToString();
entry.Categories = getPostCategories(postId, connStr);
entry.Author = postAuthor;
dataService.SaveEntry(entry);
}
}
}
using ( SqlCommand cmComments = new SqlCommand("SELECT COUNT(ID) FROM blog_Content WHERE PostType=3; SELECT * FROM blog_Content WHERE PostType=3", conn) ) {
using ( SqlDataReader drComments = cmComments.ExecuteReader() ) {
drComments.Read();
int totalCount = drComments.GetInt32(0);
drComments.NextResult();
int currIndex = 0;
while ( drComments.Read() ) {
int commentId = drComments.GetInt32(0);
int refPostId = drComments.GetInt32(13);
DateTime dtCreated = drComments.GetDateTime(2);
string commentAuthorName = drComments.IsDBNull(5) ? string.Empty : drComments.GetString(5);
string commentAuthorIp = drComments.IsDBNull(7) ? string.Empty : drComments.GetString(7);
string commentAuthorUrl = drComments.IsDBNull(11) ? string.Empty : drComments.GetString(11);
string commentText = drComments.GetString(12);
Console.WriteLine("Processing Comment #{0} ({1} of {2})", commentId, ++currIndex, totalCount);
Comment comment = new Comment();
comment.CreatedLocalTime = dtCreated;
comment.ModifiedLocalTime = dtCreated;
comment.TargetEntryId = refPostId.ToString();
comment.Author = commentAuthorName;
comment.AuthorHomepage = commentAuthorUrl;
comment.AuthorIPAddress = commentAuthorIp;
comment.Content = commentText;
dataService.AddComment(comment);
}
}
}
}
}
private static string getPostCategories(int postId, string connStr) {
string sql = "SELECT cat.Title FROM blog_Links AS links INNER JOIN blog_LinkCategories AS cat ON links.CategoryID = cat.CategoryID WHERE links.PostID = @PostID";
List<string> categories = new List<string>();
using ( SqlConnection cn = new SqlConnection(connStr) )
using ( SqlCommand cm = new SqlCommand(sql, cn) ) {
cn.Open();
cm.Parameters.Add("@PostID", SqlDbType.Int).Value = postId;
using ( SqlDataReader dr = cm.ExecuteReader(CommandBehavior.CloseConnection) ) {
while ( dr.Read() )
categories.Add(dr.GetString(0));
}
}
return string.Join(";", categories.ToArray());
}
}
}
For the most part the site is up and running, but I'd like to migrate my rating system and my download manager to this new platform. This hasn't been straightforward as .Text is SQL Server-based and DasBlog is file-based, so I'll have to come up with something...but I look forward to exploring the DasBlog object model to see if I can come up with something that works.