I Needed a New Website, So I Decided to Build a Blog

Wednesday, April 3, 2013 at 6:00 PM

So I've had this domain for a couple of years, and I haven't really done anything with it. It's just been sitting here begging me to use it for something, anything. Well a couple weeks ago I finally decide to host a blog here. I looked into some of the .NET blog / CMS projects that were available: 

I didn't get very far when I realized that, even though all of them could be good choices in their own right, they are probably overkill for my little blog. I got to thinking that what I really should (and want to) do is write my own. Follow me after the jump for what I thought I would I need, what's been done so far, and what I plan to implement in the future.

Tech

For this project, I'm using a typical Microsoft technology stack:

  • Windows Server 2008 R2
  • IIS 7.5
  • SQL Server 2008 R2
  • .NET 4.0 (Created the project with VS2010, but planning to migrate to 4.5)
  • ASP.NET MVC 4

Other packages:

Requirements

Ok, it's a blog. In its most basic form, there are a few things that every blog should have:

  • Blog posts
  • Versioning
  • Comment system
  • User accounts
  • Site settings

In order to get the site online, the first items I tackled were the blog posts, user accounts, and site settings. This has allowed me to quickly get a functional site up, so I can make a few posts while I work on the other features that aren't quite as crucial.

Code

(The full source code for this project can be found on GitHub)

So far this simple blog has three parts: site settings, blog posts (and versions), and user profiles.

Site Settings

Let's start with the site settings. Currently, they are used for global configurations such as the site title, tagline, and Google Analytics account number. Here's the full model as it exists today.

public class SiteSettingsDto
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [StringLength(100)]
    [DisplayName("Site Title")]
    public string SiteTitle { get; set; }

    [StringLength(500)]
    [DisplayName("Tagline")]
    public string Tagline { get; set; }

    [StringLength(500)]
    [DisplayName("Alternate Tagline")]
    public string AltTagline { get; set; }

    [StringLength(1000)]
    [DisplayName("Menu Links")]
    public string MenuLinks { get; set; }

    [DefaultValue(10)]
    [DisplayName("Blog Posts Per Page")]
    public int PostsPerPage { get; set; }

    [DefaultValue(true)]
    [DisplayName("Allow Comments")]
    public bool AllowComments { get; set; }

    [StringLength(20)]
    [DisplayName("Google Analytics Account Number")]
    public string GoogleAccount { get; set; }

    [DataType(DataType.DateTime)]
    [DisplayName("Date Last Updated")]
    public DateTime LastModifiedDate { get; set; }

    [DisplayName("Last Modified By")]
    public UserProfileDto LastModifiedBy { get; set; }
}

For my site,

  • SiteTitle is WadeRohrbach.com
  • Tagline is "A personal blog on technology, photography, and whatever else catches my eye..."
  • AltTagline is "A personal blog..." (displays when the window width < 768px)
  • MenuLinks map to blog posts that are flagged as content pages such as About and Contact
  • GoogleAccount is my Google Analytics account number
  • LastModifiedDate and LastModifiedBy tell who last changed these settings and when

The final two settings, PostsPerPage and AllowComments, are not in use yet. They will control how many blog posts will be displayed on one page and whether or not to globally allow comments, respectively.

Blog Posts and Versions

The blog post model relates closely to the model for versions; they are shown below.

public class BlogPostBaseDto
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required, StringLength(100)]
    public string Title { get; set; }

    [StringLength(100)]
    [DisplayName("URL Slug")]
    public string UrlSegment { get; set; }

    [Required]
    [DisplayName("Post Content")]
    public string Text { get; set; }

    public virtual UserProfileDto Author { get; set; }

    [DataType(DataType.DateTime)]
    [DisplayName("Date Last Modified")]
    public DateTime LastModifiedDate { get; set; }

    [Required]
    [DisplayName("Published?")]
    public bool IsPublished { get; set; }

    [DataType(DataType.DateTime)]
    [DisplayName("Publish Date")]
    public DateTime PublishedDate { get; set; }

    [Required]
    [DisplayName("Comments?")]
    public bool AllowComments { get; set; }

    [Required]
    [DisplayName("Content Page?")]
    public bool IsContentPage { get; set; }
}

public class BlogPostDto : BlogPostBaseDto
{
    public BlogPostDto()
    {
        PublishedDate = DateTime.Now;
        IsPublished = false;
        AllowComments = true;
    }
}

public class BlogVersionDto : BlogPostBaseDto
{        
    public virtual BlogPostDto VersionOf { get; set; }
}

As you may have noticed, both the blog post and blog version inherit from blog post base. This is so I could implement table-per-class (TPC) inheritance for these entities. Basically, I made the decision to go with TPC in order to store the versions separate from the blog posts. Keeping the versions separate will minimize the number of records in the blog post table when my site gets to the point where it has thousands of posts with corresponding versions (haha!). I chose to use inheritance over distinct classes to keep the representative objects almost identical. That way if I need to add a property to a blog post, all I have to do is add it to the blog post base and it's automatically added to the version as well. At the time of this writing, the only difference between a blog post and a blog version is the version contains a reference to the blog post that it is a version of. 

User Profiles

User management is handled through Microsoft's ASP.NET Simple Membership. Eventually, I'd like to allow logging in with your Facebook, Google, or other OpenID account, but for now I am only utilizing user accounts for administrator access. Regardless, here is the user profile model.

public class UserProfileDto
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    public string UserName { get; set; }
    public string DisplayName { get; set; }
    public string EmailAddress { get; set; }
    public string WebSite { get; set; }
    public bool Active { get; set; }
}

So as of right now, the only domain models that I have for this site are the site settings, blog post and versions, and user profiles models. With further development, I am sure that more will be needed. A domain model for comments comes immediately to mind.

Project Status

As you can probably guess, the site functionality is far from complete. I currently just have a pretty basic blog. So far I have implemented the initial site settings, blog post management, and users in the administrator role. The site is functional from a blogger's perspective, but lacks end user interaction such as commenting and social media links. There are also a number of other secondary features that I would like to implement as well. Here is far from exhaustive list of features to come.

  • Comments
  • Photo stream such as Picasaweb, Flickr, or 500px
  • OpenID login
  • Organize posts with Categories and Tags
  • Dynamic sidebar content
  • Category grouping in the sidebar
  • Monthly grouping in the sidebar
  • User administration
  • Pinned blog posts

So far this has been a fun little project that will continue to be a work in progress. Stick with me and I'll keep you updated on how it's coming along.


Add Comment