Tonight was a very enjoyable night of coding. I created the first phase of my "activity aggregator". I actually had a more clever name for it, but being tired, it slips my mind right now.
Currently, I post several places.. short updates for on Twitter. Longer discussions end up on here, my blog. I have some other sources I plan on integrating over time, such as links I found useful (similar to Digg, but also where I can place why I found it useful). That means growth, and when it comes to design, it's best to design change into it up front.
The first thing I needed to do was create my table and business object to collect these activities. In my table, I store ActivityDate, what type of activity it was (foreign key to another table -- ActivityType), a brief summary of the activity text, and finally the url someone interested could click on to get more information. The internal members of my activity class look like this:
15 #region Private Members
16
17 private int activityID;
18 private int activityTypeID;
19 private string activityDate;
20 private string activitySummary;
21 private string activityDetailsURL;
22
23 #endregion
Each private member has a publically exposed property.
Most of my activities will have XML feeds, such as the RSS feed of my blog, and the Twitter API. Therefore, I enforce a similar implementation by creating an abstract base class, called BaseFeed, which looks like this:
1 using System.Xml.Linq;
2 using RubiconPortal.Common;
3
4 namespace RubiconPortal.BusinessObjects
5 {
6 internal abstract class BaseFeed : BaseClass
7 {
8
9 public abstract int ParseFeed(XDocument doc);
10
11 }
12 }
So now I have a "contract" that I need to use to have a similar method for any activity I want to log. I could have used an interface for this, since there's no true implentation here, and I may refactor it later to do so, but I do have some ideas where I may want to provide some implementation, so that's why I chose an abstract class.
So the first item I wanted to do was implement capturing my Twitter posts in this activity, since I currently don't have a way to capture and post them on my site. I will add the rest of the activities later. In a previous post, I described how I took the Yedda Twitter API and modified it to return XDocuments, and here's another chance to take advantage of that change with LINQ.
When I post to my Twitter feed, I want to make sure my home page automatically reflects this activity. So I implement a TwitterFeed object, which implements the BaseFeed method ParseFeed. Using LINQ to XML, I pull out the pieces of the response I want, and populate the public properties of my Activities class, then save my activity. Here's what my TwitterFeed class looks like:
1 using System;
2 using System.Linq;
3 using System.Web;
4 using System.Xml.Linq;
5 using Rubicon.Common;
6 using RubiconPortal.Common;
7
8 namespace RubiconPortal.BusinessObjects
9 {
10 internal class TwitterFeed : BaseFeed
11 {
12 public override int ParseFeed(XDocument doc)
13 {
14 try
15 {
16 if (doc != null)
17 {
18 var activityList = from e in doc.Descendants("status")
19 select new RubiconPortal.BusinessObjects.Activity
20 {
21 ActivityTypeID = ActivityTypes.Twitter.Code,
22 ActivityDate = (e.Element("created_at").Value.ParseDateTime()).ToShortDateString() + " " + (e.Element("created_at").Value.ParseDateTime()).ToShortTimeString(),
23 ActivitySummary = HttpUtility.HtmlDecode(e.Element("text").Value),
24 ActivityDetailsURL = "http://twitter.com/" + e.Element("user").Element("screen_name").Value
25 };
26
27 foreach (RubiconPortal.BusinessObjects.Activity item in activityList)
28 {
29 item.Save();
30 }
31 }
32
33 return ReturnCode.Success.Code;
34 }
35 catch (Exception ex)
36 {
37 ErrorHandler(ex, "An unexpected error occurred in TwitterFeed.ParseFeed() - " + ex.Message);
38 return ReturnCode.Failure.Code;
39 }
40 }
41
42 }
43
44 }
Within the ParseFeed method I am using LINQ to XML to populate my business object calling the save() method to write it to the database. As you can see, using LINQ to XML can be a lot simpler than using XML/XPath. Once in the database, I can query it in my user control, and display it on my home page here.
Now, when I make my Twitter post, all I need to do is take the XDocument the Twitter API returns, and pass it into the ParseFeed method, which looks like this...
35 //Post my tweet to Twitter
36 TwitterAPI twit = new TwitterAPI();
37 XDocument doc = twit.UpdateAsXML(Settings.TwitterUserName(), Settings.TwitterPassword(), txtPost.Text);
38
39 //Save it to the activity table for displaying the activity
40 TwitterFeed feed = new TwitterFeed();
41 feed.ParseFeed(doc);
Simple and neat! Now when I implement it for my blog, it will be just as quick and easy!
Props go out to this post I snagged an extension method for formatting the Twitter posting date to something a human can use (and my C# class can use to manipulate and save!)