WordPress Blog and ASP.NET MVC Integration

5 12 2010

This was too easy/cool to keep tucked away. I wanted the most cheap and cheerful way of listing the top 10 blog posts, into a larger, containing website I am building for a client. I started out by Googling (googeloper) “wordpress integration c#”. Unexpectedly, nothing obvious I was looking for surfaced. Most solution seemed to rely on having WordPress installed physically beneath the website, or proposed options such as FTP based integration. Yuck! No. I just wanted the 10 latest posts in real time (i.e. as of now). Hold on I thought, that’s exactly what feeds have been designed to do. Blog engines (such as WordPress) have excellent feed support, including a REST based API, support for RSS and Atom. Wowzers.

There is plenty of good information about those topics elsewhere. I really just wanted to demonstrate how simple it is to query such a feed taking a server side approach (assuming your web server has Internet HTTP GET access to the feed). To do this, I used System.Net.WebClient, LINQ to XML and ASP.NET MVC 3. The feed I am consuming is for a WordPress blog, but there is absolutely no dependency/coupling that the blog must be WordPress based. It could for example, be a Blogger feed.

Another factor that should be given consideration is whether taking a server side (e.g. ASP.NET) approach versus a client side (e.g. jQuery) approach is a better fit for you. If for example search engine visibility (SEO) of the integrated blog content is important to you, a server side approach may be a better fit.

1. Using a browser review the feed you’re targeting. For example, if the (WordPress) blog is http://example.com then have a look at http://example.com/feed/ or http://example.com/feed/atom. Below is a sample of the first chunk of Atom feed for this WordPress blog.

<?xml version="1.0" encoding="UTF-8"?><feed
  xmlns="http://www.w3.org/2005/Atom"
  xmlns:thr="http://purl.org/syndication/thread/1.0"
  xml:lang="en"
  xml:base="http://bencode.net/wp-atom.php"
  xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"  >
	<title type="text">benCode</title>
	<subtitle type="text">Ben Simmonds: BizTalk Server Guy in Sydney</subtitle>

	<updated>2010-11-24T02:03:03Z</updated>

	<link rel="alternate" type="text/html" href="http://bencode.net" />
	<id>http://bencode.net/feed/atom/</id>
	<link rel="self" type="application/atom+xml" href="http://bencode.net/feed/atom/" />

	<generator uri="http://wordpress.com/">WordPress.com</generator>
<link rel="search" type="application/opensearchdescription+xml" href="http://bencode.net/osd.xml" title="benCode" />
<link rel="search" type="application/opensearchdescription+xml" href="http://wordpress.com/opensearch.xml" title="WordPress.com" />
	<link rel='hub' href='http://bencode.net/?pushpress=hub' />
		<entry>
		<author>
			<name>beness</name>
						<uri>http://www.bencode.net/</uri>
					</author>
		<title type="html"><![CDATA[SSO Configuration Road Block]]></title>
		<link rel="alternate" type="text/html" href="http://bencode.net/2010/11/24/sso-configuration-road-block/" />
		<id>https://bencode.wordpress.com/2010/11/24/sso-configuration-road-block/</id>
		<updated>2010-11-24T02:03:03Z</updated>
		<published>2010-11-24T01:58:25Z</published>
		<category scheme="http://bencode.net" term="BizTalk" /><category scheme="http://bencode.net" term="SSO" /><category scheme="http://bencode.net" term="Error" />		<summary type="html"><![CDATA[Recently I’ve had the need to setup a BizTalk Server 2006 R2 virtual machine. Quietly confident about my experience with this version of BizTalk, I jumped in head first to *quickly* get a simple single server based installation configured on a 32-bit VMWare based VM. Lesson learned today…never, ever underestimate the obscure errors that BizTalk [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bencode.net&amp;blog=2452880&amp;post=109&amp;subd=bencode&amp;ref=&amp;feed=1" width="1" height="1" />]]></summary>
		<content type="html" xml:base="http://bencode.net/2010/11/24/sso-configuration-road-block/"><![CDATA[<p>Recently I’ve had the need to setup a BizTalk Server 2006 R2 virtual machine. Quietly confident about my experience with this version of BizTalk, I jumped in head first to *quickly* get a simple single server based installation configured on a 32-bit VMWare based VM.</p>

2. Below is a snippet of simple C# that leverages LINQ to XML to parse an Atom feed. This code is in a controllers action method, because of ASP.NET MVC, but again this code has no requirement for you to be using MVC. Side note: LINQ to XML makes working with XML much more fluid for the C#/VB developer. Very very nice to use!

public ActionResult Index()
{
  XNamespace xsd = "http://www.w3.org/2005/Atom";
  var client = new WebClient();
  var feed = client.DownloadString("http://www.bencode.net/feed/atom");
  var document = XDocument.Parse(feed);
  var blogs = 
    from e in document.Descendants(xsd + "entry")
    select new BlogModel()
    {
      Title = (string)e.Element(xsd + "title"),
      Content = new HtmlString((string)e.Element(xsd + "content"))
    };
  return View(blogs);
}

3. A simple MVC 3 Razor view:

@model IEnumerable<MvcApplication.Model.BlogModel>

@{
    View.Title = "Blogs";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h1>Blogs</h1>

@foreach (var blog in Model) {
<div class="blogpost">
  <h2>@blog.Title</h2>
  <p>@blog.Content</p>
</div>
}

4. Downloading, streaming, parsing and rendering this feed should be considered an expensive operation. Something that you probably don’t want to happen for each request that comes in for your page/site. To cache this entire “pipeline” of work, I went with some ASP.NET MVC output caching, by marking up the controller action with the following custom attribute:

[OutputCache(VaryByParam="none", Duration=60)]
public ActionResult Index()
{
  ...

The result: