<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>John Sheehan : Blog &#187; SubSonic</title>
	<atom:link href="http://john-sheehan.com/blog/index.php/category/subsonic/feed/" rel="self" type="application/rss+xml" />
	<link>http://john-sheehan.com/blog</link>
	<description></description>
	<lastBuildDate>Mon, 30 Aug 2010 22:13:14 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
<atom:link rel="hub" href="http://pubsubhubbub.appspot.com"/><atom:link rel="hub" href="http://superfeedr.com/hubbub"/>		<item>
		<title>Building a mostly real-time web-based Twitter client with ASP.NET MVC, jQuery and TweetSharp, Part 1</title>
		<link>http://john-sheehan.com/blog/building-a-mostly-real-time-web-based-twitter-client-with-aspnet-mvc-jquery-and-tweetsharp-part-1/</link>
		<comments>http://john-sheehan.com/blog/building-a-mostly-real-time-web-based-twitter-client-with-aspnet-mvc-jquery-and-tweetsharp-part-1/#comments</comments>
		<pubDate>Tue, 26 May 2009 00:51:17 +0000</pubDate>
		<dc:creator>John</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[ASP.NET MVC]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Managed Assembly]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[SubSonic]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://john-sheehan.com/blog/building-a-mostly-real-time-web-based-twitter-client-with-aspnet-mvc-jquery-and-tweetsharp-part-1/</guid>
		<description><![CDATA[Back when I launched ManagedAssembly.com around MIX I put together a page to show real-time Twitter search results for ‘MIX09’. On the heels of the dvplrs.com launch this week and the lack of .NET representation, I decided to update my live Twitter page to show live updates of notable people in the .NET community. This [...]]]></description>
			<content:encoded><![CDATA[<p>Back when I launched <a href="http://managedassembly.com/" target="_blank">ManagedAssembly.com</a> around MIX I put together a page to show real-time Twitter search results for ‘MIX09’. On the heels of the dvplrs.com launch this week and the lack of .NET representation, I decided to update my live Twitter page to show live updates of notable people in the .NET community. This is how I built it. You can see the finished product over at <a href="http://managedassembly.com/twitter" target="_blank">ManagedAssembly.com/Twitter</a>.</p>
<p>Since I decided to use the standard Twitter API instead of the Search API, I had to build a server-side cache of updates so that I wasn’t hitting the API on every view of the page which would quickly exhaust the API rate limits. Using a database was overkill so I decided to use ASP.NET’s built-in cache mechanism to store new updates. When the client makes a request for the latest updates, the items will be served out of the cache. The cache is updated every so often with new items.</p>
<p>The workflow when the client makes a request for updates (via jQuery) is like so:</p>
<ul>
<li>Grab the date of the last cache update from the cache. If the value doesn’t exist or it’s older than the cache expiration threshold, it’s time to get more statuses from Twitter. </li>
<li>When new updates are pulled from Twitter, store the highest ID in the cache as well so that for future requests we can get only the new tweets. </li>
<li>Pull the currently cached items and add the new items from the Twitter API call to it. </li>
<li>When updates are sent to the browser, the client-side code stores the latest ID. For future requests this ID is passed back to the server which returns items from the cached list that are greater than the locally-stored ID. </li>
</ul>
<p>What this gives us is the ability to only call Twitter once a minute no matter how many times the site is hit. It also allows for each visitor to only get back tweets that are new to them (which is different for every visitor depending on when the first hit the page) whenever they make a request. Since the tweets are being pulled from memory on almost every request there’s no delay while the API call is being made. If the application restarts and we lose the cache it won’t really matter because we just grab all the updates it will send and repopulate the cache. It also means that the amount of data being sent to the client via JSON is the bare minimum needed. That makes updating the UI simple (just append the new ones without having to process the full list) and keeps the bandwidth requirements low.</p>
<p>That was a lot of words, so time for some code. We start by determining if we need to get new items from Twitter and if so, grabbing them. This uses the <a href="http://john-sheehan.com/blog/pluggable-aspnet-cachemanager/" target="_blank">CacheManager from a previous post</a>.</p>
<div style="font-family: consolas, courier new; background: black; color: white; font-size: 9pt; overflow: auto">
<pre style="margin: 0px"><span style="color: #ffc66d; font-weight: bold">CacheManager</span> cache = <span style="color: #cc7832; font-weight: bold">new</span> <span style="color: #ffc66d; font-weight: bold">CacheManager</span>(<span style="color: #cc7832; font-weight: bold">new</span> <span style="color: #ffc66d; font-weight: bold">ShortTermProvider</span>());</pre>
<pre style="margin: 0px">&#160;</pre>
<pre style="margin: 0px"><span style="color: #6897bb">IEnumerable</span>&lt;<span style="color: #ffc66d; font-weight: bold">TwitterStatus</span>&gt; statuses = <span style="color: #cc7832; font-weight: bold">new</span> <span style="color: #ffc66d; font-weight: bold">List</span>&lt;<span style="color: #ffc66d; font-weight: bold">TwitterStatus</span>&gt;();</pre>
<pre style="margin: 0px"><span style="color: #cc7832; font-weight: bold">long</span> maxId = <span style="color: #0080c0; font-weight: bold">0</span>;</pre>
<pre style="margin: 0px">&#160;</pre>
<pre style="margin: 0px"><span style="color: #6897bb">DateTime</span> lastFetch = cache.Get&lt;<span style="color: #6897bb">DateTime</span>&gt;(<span style="color: #a5c25c; font-weight: bold">&quot;last_fetch&quot;</span>);</pre>
<pre style="margin: 0px"><span style="color: #cc7832; font-weight: bold">if</span> (lastFetch &lt; <span style="color: #6897bb">DateTime</span>.Now.AddMinutes(-<span style="color: #0080c0; font-weight: bold">1</span>)) {</pre>
<pre style="margin: 0px">&#160;&#160;&#160; <span style="color: #cc7832; font-weight: bold">long</span> lastCacheId = cache.Get&lt;<span style="color: #cc7832; font-weight: bold">long</span>&gt;(<span style="color: #a5c25c; font-weight: bold">&quot;last_id&quot;</span>);</pre>
<pre style="margin: 0px">&#160;&#160;&#160; <span style="color: #cc7832; font-weight: bold">if</span> (lastCacheId == <span style="color: #0080c0; font-weight: bold">0</span>)</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160; lastCacheId = <span style="color: #0080c0; font-weight: bold">1</span>; <span style="color: gray; font-weight: bold">// TweetSharp/twitter returns null if you use Since(0)</span></pre>
<pre style="margin: 0px">&#160;</pre>
<pre style="margin: 0px">&#160;&#160;&#160; <span style="color: #cc7832; font-weight: bold">var</span> request = <span style="color: #ffc66d; font-weight: bold">FluentTwitter</span>.CreateRequest().AuthenticateAs(<span style="color: #a5c25c; font-weight: bold">&quot;UserGoesHere&quot;</span>, <span style="color: #a5c25c; font-weight: bold">&quot;passwordgoeshere&quot;</span>);</pre>
<pre style="margin: 0px">&#160;&#160;&#160; request.Configuration.UseGzipCompression();</pre>
<pre style="margin: 0px">&#160;&#160;&#160; request.Statuses().OnFriendsTimeline().Since(lastCacheId).AsJson();</pre>
<pre style="margin: 0px">&#160;</pre>
<pre style="margin: 0px">&#160;&#160;&#160; statuses = request.Request().AsStatuses();</pre>
<pre style="margin: 0px">}</pre>
</div>
<p>The first time this is hit <em>lastFetch</em> doesn’t exist in cache and the cache manager returns the default for DateTime (DateTime.MinValue) which I’m pretty sure is always more than a minute ago. We’ll update the fetch time in cache later. Once we’ve determined that the cache is empty or expired, we grab the <em>last_id</em> value from cache (which is 0 if it doesn’t exist). We then use <a href="http://tweetsharp.com" target="_blank">TweetSharp</a> to get the latest updates and store them in a list.</p>
<p>We also make sure that <em>statuses</em> isn’t null because if you’ve exceed the Twitter API rate limit, TweetSharp returns a null collection. Once we have the updates we have to process them since the text doesn’t include links for @mentions, #hashtags or links. When deciding how to approach this part I contacted <a href="http://twitter.com/jongalloway" target="_blank">Jon Galloway</a> and he pointed me to the code in <a href="http://code.google.com/p/wittytwitter/" target="_blank">Witty</a> which handles creating links, which I borrowed heavily from (thanks Jon!). MA also uses SubSonic 2.2 for the DAL and I used one of the methods provided in that library for determining if a word is a URL.</p>
<div style="font-family: consolas, courier new; background: black; color: white; font-size: 9pt; overflow: auto">
<pre style="margin: 0px"><span style="color: #cc7832; font-weight: bold">if</span> (statuses != <span style="color: #cc7832; font-weight: bold">null</span>) {</pre>
<pre style="margin: 0px">&#160;&#160;&#160; <span style="color: #cc7832; font-weight: bold">foreach</span> (<span style="color: #cc7832; font-weight: bold">var</span> status <span style="color: #cc7832; font-weight: bold">in</span> statuses) {</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #cc7832; font-weight: bold">string</span> raw = status.Text;</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #cc7832; font-weight: bold">string</span>[] words = <span style="color: #ffc66d; font-weight: bold">Regex</span>.Split(raw, <span style="color: #a31515">@&quot;([ \(\)\{\}\[\]])&quot;</span>);</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #ffc66d; font-weight: bold">StringBuilder</span> output = <span style="color: #cc7832; font-weight: bold">new</span> <span style="color: #ffc66d; font-weight: bold">StringBuilder</span>();</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #cc7832; font-weight: bold">foreach</span> (<span style="color: #cc7832; font-weight: bold">string</span> word <span style="color: #cc7832; font-weight: bold">in</span> words) {</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #cc7832; font-weight: bold">if</span> (word.StartsWith(<span style="color: #a5c25c; font-weight: bold">&quot;#&quot;</span>)) {</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #cc7832; font-weight: bold">string</span> hashtag = <span style="color: #ffc66d; font-weight: bold">String</span>.Empty;</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #ffc66d; font-weight: bold">Match</span> foundHashtag = <span style="color: #ffc66d; font-weight: bold">Regex</span>.Match(word, <span style="color: #a31515">@&quot;#(\w+)(?&lt;suffix&gt;.*)&quot;</span>);</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #cc7832; font-weight: bold">if</span> (foundHashtag.Success) {</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; hashtag = foundHashtag.Groups[<span style="color: #0080c0; font-weight: bold">1</span>].Captures[<span style="color: #0080c0; font-weight: bold">0</span>].Value;</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; output.Append(<span style="color: #cc7832; font-weight: bold">string</span>.Format(<span style="color: #a31515">@&quot;#&lt;a href=&quot;&quot;http://search.twitter.com/search?q=%23{0}&quot;&quot; target=&quot;&quot;_blank&quot;&quot;&gt;{0}&lt;/a&gt;&quot;</span>, hashtag));</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #cc7832; font-weight: bold">else</span> <span style="color: #cc7832; font-weight: bold">if</span> (word.StartsWith(<span style="color: #a5c25c; font-weight: bold">&quot;@&quot;</span>)) {</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #cc7832; font-weight: bold">string</span> userName = <span style="color: #ffc66d; font-weight: bold">String</span>.Empty;</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #ffc66d; font-weight: bold">Match</span> foundUserName = <span style="color: #ffc66d; font-weight: bold">Regex</span>.Match(word, <span style="color: #a31515">@&quot;@(\w+)(?&lt;suffix&gt;.*)&quot;</span>);</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #cc7832; font-weight: bold">if</span> (foundUserName.Success) {</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; userName = foundUserName.Groups[<span style="color: #0080c0; font-weight: bold">1</span>].Captures[<span style="color: #0080c0; font-weight: bold">0</span>].Value;</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; output.Append(<span style="color: #cc7832; font-weight: bold">string</span>.Format(<span style="color: #a31515">@&quot;@&lt;a href=&quot;&quot;http://twitter.com/{0}&quot;&quot; target=&quot;&quot;_blank&quot;&quot;&gt;{0}&lt;/a&gt;&quot;</span>, userName));</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #cc7832; font-weight: bold">else</span> <span style="color: #cc7832; font-weight: bold">if</span> (SubSonic.Sugar.<span style="color: #ffc66d; font-weight: bold">Validation</span>.IsURL(word)) {</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; output.Append(<span style="color: #cc7832; font-weight: bold">string</span>.Format(<span style="color: #a31515">@&quot;&lt;a href=&quot;&quot;{0}&quot;&quot; target=&quot;&quot;_blank&quot;&quot;&gt;{0}&lt;/a&gt;&quot;</span>, word));</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #cc7832; font-weight: bold">else</span> {</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; output.Append(word);</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160; }</pre>
<pre style="margin: 0px">&#160;</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160; status.Text = output.ToString();</pre>
<pre style="margin: 0px">&#160;&#160;&#160; }</pre>
<pre style="margin: 0px">&#160;</pre>
<pre style="margin: 0px">&#160;&#160;&#160; cache.Store(<span style="color: #a5c25c; font-weight: bold">&quot;last_fetch&quot;</span>, <span style="color: #6897bb">DateTime</span>.Now);</pre>
<pre style="margin: 0px">}</pre>
</div>
<p>OK now that we’ve got the latest updates from the API and added the links, it’s time to store them in the cache.</p>
<div style="font-family: consolas, courier new; background: black; color: white; font-size: 9pt; overflow: auto">
<pre style="margin: 0px"><span style="color: #cc7832; font-weight: bold">var</span> cachedStatuses = cache.Get&lt;<span style="color: #ffc66d; font-weight: bold">List</span>&lt;<span style="color: #ffc66d; font-weight: bold">TwitterStatus</span>&gt;&gt;(<span style="color: #a5c25c; font-weight: bold">&quot;cachedStatuses&quot;</span>);</pre>
<pre style="margin: 0px"><span style="color: #cc7832; font-weight: bold">if</span> (cachedStatuses == <span style="color: #cc7832; font-weight: bold">null</span>) {</pre>
<pre style="margin: 0px">&#160;&#160;&#160; cachedStatuses = <span style="color: #cc7832; font-weight: bold">new</span> <span style="color: #ffc66d; font-weight: bold">List</span>&lt;<span style="color: #ffc66d; font-weight: bold">TwitterStatus</span>&gt;();</pre>
<pre style="margin: 0px">}</pre>
<pre style="margin: 0px">&#160;</pre>
<pre style="margin: 0px"><span style="color: #cc7832; font-weight: bold">if</span> (statuses != <span style="color: #cc7832; font-weight: bold">null</span>) {</pre>
<pre style="margin: 0px">&#160;&#160;&#160; cachedStatuses.AddRange(statuses);</pre>
<pre style="margin: 0px">}</pre>
<pre style="margin: 0px">&#160;</pre>
<pre style="margin: 0px"><span style="color: #cc7832; font-weight: bold">if</span> (cachedStatuses.Count &gt; <span style="color: #0080c0; font-weight: bold">0</span>) {</pre>
<pre style="margin: 0px">&#160;&#160;&#160; maxId = cachedStatuses.Max(s =&gt; s.Id);</pre>
<pre style="margin: 0px">&#160;&#160;&#160; cache.Store(<span style="color: #a5c25c; font-weight: bold">&quot;last_id&quot;</span>, maxId);</pre>
<pre style="margin: 0px">}</pre>
<pre style="margin: 0px">&#160;</pre>
<pre style="margin: 0px">cache.Store(<span style="color: #a5c25c; font-weight: bold">&quot;cachedStatuses&quot;</span>, cachedStatuses);</pre>
</div>
<p>Last but not least we build a JSON return value for all the tweets in the cache with an ID higher than the one sent by the client (lid is a parameter passed from the client).</p>
<div style="font-family: consolas, courier new; background: black; color: white; font-size: 9pt; overflow: auto">
<pre style="margin: 0px"><span style="color: #cc7832; font-weight: bold">long</span> lastClientId = lid ?? <span style="color: #0080c0; font-weight: bold">1</span>;</pre>
<pre style="margin: 0px">&#160;</pre>
<pre style="margin: 0px"><span style="color: #cc7832; font-weight: bold">var</span> data = <span style="color: #cc7832; font-weight: bold">from</span> s <span style="color: #cc7832; font-weight: bold">in</span> cachedStatuses</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #cc7832; font-weight: bold">where</span> s.Id &gt; lastClientId</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #cc7832; font-weight: bold">orderby</span> s.Id <span style="color: #cc7832; font-weight: bold">descending</span></pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #cc7832; font-weight: bold">select</span> <span style="color: #cc7832; font-weight: bold">new</span> {</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Id = s.Id,</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ProfileImageUrl = s.User.ProfileImageUrl,</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Text = s.Text,</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Source = s.Source,</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; UserName = s.User.ScreenName,</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; RelativeTime = s.CreatedDate.ToRelativeTime(<span style="color: #cc7832; font-weight: bold">false</span>),</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ClientLink = s.Source,</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; IsReply = s.InReplyToStatusId != <span style="color: #0080c0; font-weight: bold">0</span>,</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; InReplyToId = s.InReplyToStatusId,</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; InReplyToUser = s.InReplyToScreenName</pre>
<pre style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; };</pre>
<pre style="margin: 0px">&#160;</pre>
<pre style="margin: 0px"><span style="color: #cc7832; font-weight: bold">return</span> Json(<span style="color: #cc7832; font-weight: bold">new</span> { results = data.Take(<span style="color: #0080c0; font-weight: bold">100</span>), max_id = maxId });</pre>
</div>
<p>In <a href="http://john-sheehan.com/blog/building-a-mostly-real-time-web-based-twitter-client-with-aspnet-mvc-jquery-and-tweetsharp-part-2/">Part 2</a> I’ll cover building the UI.</p>
]]></content:encoded>
			<wfw:commentRss>http://john-sheehan.com/blog/building-a-mostly-real-time-web-based-twitter-client-with-aspnet-mvc-jquery-and-tweetsharp-part-1/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Post-MIX Thoughts</title>
		<link>http://john-sheehan.com/blog/post-mix-thoughts/</link>
		<comments>http://john-sheehan.com/blog/post-mix-thoughts/#comments</comments>
		<pubDate>Sat, 21 Mar 2009 19:12:43 +0000</pubDate>
		<dc:creator>John</dc:creator>
				<category><![CDATA[ASP.NET MVC]]></category>
		<category><![CDATA[Life]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[SubSonic]]></category>
		<category><![CDATA[Thoughts]]></category>

		<guid isPermaLink="false">http://john-sheehan.com/blog/post-mix-thoughts/</guid>
		<description><![CDATA[I had a hunch I’d be too tired to write up a day-by-day recap of my first MIX conference which turned out to be exactly right. You’ve probably heard by now all the stuff that was announced, so I’ll try to keep this an opinion piece instead of a news article. The Good Prior to [...]]]></description>
			<content:encoded><![CDATA[<p>I had a hunch I’d be too tired to write up a day-by-day recap of my first MIX conference which turned out to be exactly right. You’ve probably heard by now all the stuff that was announced, so I’ll try to keep this an opinion piece instead of a news article.</p>
<p><strong>The Good</strong></p>
<p>Prior to attending I had read that the most valuable part of conferences like MIX was not the presentations, but the people. This was absolutely and completely true. There’s no substitute for having conversations with brilliant people and there were a ton of brilliant people at the conference. I had good conversations with <a href="http://haacked.com" target="_blank">Phil Haack</a>, <a href="http://codinghorror.com" target="_blank">Jeff Atwood</a> and the <a href="http://stackoverflow.com" target="_blank">Stack Overflow</a> devs Jarrod and Geoff, <a href="http://www.joelonsoftware.com" target="_blank">Joel Spolsky</a> (possibly the highlight of my career), <a href="http://blog.wekeroad.com" target="_blank">Rob Conery</a>, <a href="http://twitter.com/jongalloway" target="_blank">Jon Galloway</a>, <a href="http://www.hanselman.com" target="_blank">Scott Hanselman</a>, <a href="http://www.encosia.com" target="_blank">Dave Ward from Encosia</a>, <a href="http://www.codethinked.com" target="_blank">Justin Etheredge</a>, some guys from <a href="http://woot.com" target="_blank">Woot</a> and many more. Learning the how and why of how they do things is educational and inspiring.</p>
<p>Thankfully, Microsoft has realized the importance of these types of interactions and does a great job of facilitating them. They set up a room called “3rd Place” with couches, snacks, free wifi and power strips. It was a great setup and worth the price of admission alone. If you’re at MIX next year and none of the sessions at any given time really inspire you, go hang out at 3rd Place and strike up conversations instead. You can always watch the session video later.</p>
<p>One conversation I’m particularly enthused about is the meeting I had with Rob Conery of SubSonic fame. SubSonic has gone a little stale and needs some freshening up. We discussed some issues getting in the way of progress and some ideas for going forward. I’m going to try to get it kick started again, which I will blog about when that happens. I love SubSonic and am excited to start contributing to it&#8217;s future.</p>
<p>I also showed off Managed Assembly when I had a chance and got some good feedback on the site both design-wise and vision-wise. Now that it’s up and running, we’ll see how it goes for a little bit before I make any significant changes.</p>
<p>MIX also does a good job of keeping a good balance of content for designers and developers. I think all devs should have some basic understanding of good design principles and MIX does a good job of exposing that without overdoing it for devs. Bill Buxton and Deborah Adler (she designed the new Target prescription packaging) gave insightful keynotes that had some good design insights for both designers and developers.</p>
<p><strong>The Not-As-Good</strong></p>
<p>One reason 3rd Place was more appealing to me than the sessions is a matter of timing. ASP.NET MVC went final, but there was very little new content that wasn’t already covered at PDC or in blog posts since. Rob Conery’s session stood out because it was the only one that had more stuff in it that I hadn’t seen than stuff that I had seen. It was great. <a href="http://videos.visitmix.com/MIX09/T62F" target="_blank">The video has been posted so you should watch it</a>. Almost everything else that was new was tied to Silverlight. Which brings me to…</p>
<p><strong>The ‘meh’</strong></p>
<p>Silverlight 3. Meh. It’s nice. It does cool stuff. It now works out of the browser, which has huge potential. Adobe AIR now has some serious competition for building Twitter clients (ba-dum-dum). I did learn some things about Silverlight I didn’t know (like support for threading), but overall, I just don’t care that much about it yet.</p>
<p><strong>The Bad</strong></p>
<p>IE8. OK, IE8 isn’t so bad, but until IE6 is dead, it’s completely irrelevant. Slices? Yawn. Accelerators? Yawn. I don’t want to write browser-specific code anymore. <a href="http://www.youtube.com/watch?v=GsMFyo8DWs4" target="_blank">The IE intro video</a> was pretty funny though.</p>
<p><strong>Was it worth the trip?</strong></p>
<p>Absolutely. If you’re a MS web dev or a designer that works with them, you should be at MIX. You’ll learn a lot from other people and the sessions. You’ll have a chance to talk directly to the people who build the tools that are the basis for your profession and give them feedback and ideas from the real world. You’ll have fun because it’s in Vegas. Try to make it next year. You won’t regret it.</p>
]]></content:encoded>
			<wfw:commentRss>http://john-sheehan.com/blog/post-mix-thoughts/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>How I Use SubSonic, Part 3: Caching and Query Auditing</title>
		<link>http://john-sheehan.com/blog/how-i-use-subsonic-part-3-caching-and-query-auditing/</link>
		<comments>http://john-sheehan.com/blog/how-i-use-subsonic-part-3-caching-and-query-auditing/#comments</comments>
		<pubDate>Wed, 21 Jan 2009 02:06:12 +0000</pubDate>
		<dc:creator>John</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[SubSonic]]></category>
		<category><![CDATA[Tips]]></category>

		<guid isPermaLink="false">http://john-sheehan.com/blog/how-i-use-subsonic-part-3-caching-and-query-auditing/</guid>
		<description><![CDATA[In Part 1 I covered how I created a ControllerBase class that all my SubSonic queries run through. Once I had a central point for processing queries, I wanted to add two features. Request-length caching and the ability to see how long a query was taking to execute. Adding Request-length Caching First off, this will [...]]]></description>
			<content:encoded><![CDATA[<p>In <a href="http://john-sheehan.com/blog/how-i-use-subsonic-part-1/">Part 1</a> I covered how I created a <a href="http://john-sheehan.com/blog/wp-content/uploads/controllerbase.txt">ControllerBase</a> class that all my SubSonic queries run through. Once I had a central point for processing queries, I wanted to add two features. Request-length caching and the ability to see how long a query was taking to execute.</p>
<p><strong>Adding Request-length Caching</strong></p>
<p>First off, this will only work as shown with web applications due to a dependency on HttpContext.Items. You could easily modify this to work without this dependency.</p>
<p><a href="http://john-sheehan.com/blog/how-i-use-subsonic-part-2/">The way my templates are structured</a> gives me access to related objects through lazy-loaded properties on my domain objects. All of these properties use the Get(id) method on their respective Controller. Throughout the length of a single request, there’s no reason to retrieve a given entity from the database more than once. Using my <a href="http://john-sheehan.com/blog/pluggable-aspnet-cachemanager/">CacheManager</a> I added the following to the ControllerBase.Get() method:</p>
<pre>public static ItemType Get(object id)
{
    if (id == null)
        return default(ItemType);

    CacheManager cache = new CacheManager(new RequestProvider());
    string cacheToken = string.Format("{0}_{1}", typeof(ItemType), id);

    ItemType item = cache.Get(cacheToken);

    if (item == null)
    {
        item = DB.Get(id);

        // subsonic returns a new item if a get by ID fails
        // but we want a null object
        if (item.IsNew)
        {
            return default(ItemType);
        }
        else
        {
            cache.Store(cacheToken, item);
        }
    }

    return item;
}</pre>
<p>The cache is first checked for an existing object matching the type and ID. If it’s not found, the entity is retrieved from the database and stored in the cache. If it is found, the database hit is skipped. There’s also a section in there to handle how SubSonic deals with .Get() calls that don’t find a record. I prefer to return null in this case, but your preference may vary.</p>
<p>I don’t yet cache the results of collections, only single objects. Caching the results of collections is an intriguing problem that I may revisit in the future.</p>
<p><strong>Query Auditing</strong></p>
<p>After caching reduced the number of times I hit the database on each request, I wanted to find out how long individual queries were taking so I could optimize where needed. I also wanted a way to print out a list of every query called with the SubSonic-generated SQL.</p>
<p>First up was creating the Auditor class to handle creating and storing entries. I don’t want to spend time on the internals, so you can <a href="http://john-sheehan.com/blog/wp-content/uploads/subsonicauditor.txt" target="_blank">view the source if you want to get a sense of how it works</a>. Briefly, the heart of the Auditor is the CreateEntry method that takes a SubSonic SqlQuery, Query or StoredProcedure and stores it for display later. There’s also Auditor.StartTiming() and Auditor.EndTiming() for determining how long the query took to execute. Each of the methods in ControllerBase that execute queries get the Auditor mixed in like so:</p>
<pre>public static ListType GetCollection(SqlQuery q)
{
    Auditor.StartTiming();
    ListType coll = q.ExecuteAsCollection
();
    TimeSpan exTime = Auditor.StopTiming();

    Auditor.CreateEntry(q, Action.Fetch, coll.Count, exTime);

    return coll;
}</pre>
<p>And the updated Get() method:</p>
<pre>public static ItemType Get(object id)
{
    if (id == null)
        return default(ItemType);

    CacheManager cache = new CacheManager(new RequestProvider());
    string cacheToken = string.Format("{0}_{1}", typeof(ItemType), id);

    ItemType item = cache.Get(cacheToken);

    if (item == null)
    {
        Auditor.StartTiming();
        item = DB.Get(id);

        // subsonic returns a new item if a get by ID fails
        // but we want a null object
        if (item.IsNew)
        {
            Auditor.CreateEntry(cacheToken, Action.Fetch, 0, null, Auditor.StopTiming());
            return default(ItemType);
        }
        else
        {
            Auditor.CreateEntry(cacheToken, Action.Fetch, 1, null, Auditor.StopTiming());
            cache.Store(cacheToken, item);
        }
    }
    else
    {
        Auditor.CreateEntry(cacheToken, Action.LoadFromCache, 1, null, TimeSpan.Zero);
    }

    return item;
}</pre>
<p>The Auditor stores the query stats in a List&lt;Entry&gt; in HttpContext.Current.Items. To display these entries, I wrote the following Webforms UserControl (have not yet migrated this to MVC).</p>
<pre>&lt;%@ Control Language="C#" AutoEventWireup="true" CodeFile="Auditor.ascx.cs" Inherits="AuditorControl" %&gt;
&lt;asp:Repeater ID="rItems" runat="server" Visible="false" OnItemDataBound="rItems_ItemDataBound"&gt;
    &lt;HeaderTemplate&gt;
        &lt;table class="list" style="font-size: 11px;"&gt;
            &lt;tr class="header"&gt;
                &lt;th&gt;Type&lt;/th&gt;
                &lt;th&gt;Count&lt;/th&gt;
                &lt;th&gt;Time&lt;/th&gt;
                &lt;th class="left"&gt;Description&lt;/th&gt;
                &lt;th class="left"&gt;Params&lt;/th&gt;
            &lt;/tr&gt;
    &lt;/HeaderTemplate&gt;
    &lt;ItemTemplate&gt;
        &lt;tr class="item"&gt;
            &lt;td class="center top" style="width: 30px;"&gt;&lt;%# Eval("Action") %&gt;&lt;/td&gt;
            &lt;td class="center top" style="width: 30px;"&gt;&lt;%# Eval("ResultCount") %&gt;&lt;/td&gt;
            &lt;td class="center top" style="width: 30px;"&gt;&lt;%# ((TimeSpan)Eval("ExecutionLength")).Milliseconds %&gt;ms&lt;/td&gt;
            &lt;td class="top"&gt;&lt;%# Eval("DescriptionHtml") %&gt;&lt;/td&gt;
            &lt;td class="top" style="width: 150px;"&gt;
                &lt;asp:Repeater ID="rParams" runat="server"&gt;
                    &lt;ItemTemplate&gt;
                        &lt;strong&gt;&lt;%# Eval("Key") %&gt;:&lt;/strong&gt;
                        &lt;span style="white-space: nowrap;"&gt;&lt;%# Eval("Value") %&gt;&lt;/span&gt;&lt;br /&gt;
                    &lt;/ItemTemplate&gt;
                &lt;/asp:Repeater&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/ItemTemplate&gt;
    &lt;FooterTemplate&gt;
        &lt;/table&gt;
    &lt;/FooterTemplate&gt;
&lt;/asp:Repeater&gt;</pre>
<p>And the code behind:</p>
<pre>using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using SubSonicAuditor;

public partial class AuditorControl : System.Web.UI.UserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (Auditor.Entries.Count &gt; 0)
        {
            rItems.DataSource = Auditor.Entries;
            // or to exclude cache retrieval:
            // rItems.DataSource = Auditor.Entries.Where(en =&gt; en.Action != Action.LoadFromCache);
            rItems.DataBind();
            rItems.Visible = true;
        }
    }

    protected void rItems_ItemDataBound(object sender, RepeaterItemEventArgs e)
    {
        if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
        {
            Repeater rParams = (Repeater)e.Item.FindControl("rParams");
            Entry entry = (Entry)e.Item.DataItem;

            rParams.DataSource = entry.Parameters;
            rParams.DataBind();
        }
    }
}</pre>
<p>Put this user control on any page you want to test (or your site’s master page), make sure you’re running in Debug mode and you should get a list of all the queries executed and how long they took. <a href="http://john-sheehan.com/blog/wp-content/uploads/auditorexample.jpg" target="_blank">Here’s a (heavily-blurred for security) example of the output</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://john-sheehan.com/blog/how-i-use-subsonic-part-3-caching-and-query-auditing/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>How I Use SubSonic, Part 2</title>
		<link>http://john-sheehan.com/blog/how-i-use-subsonic-part-2/</link>
		<comments>http://john-sheehan.com/blog/how-i-use-subsonic-part-2/#comments</comments>
		<pubDate>Sun, 26 Oct 2008 22:46:46 +0000</pubDate>
		<dc:creator>John</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[SubSonic]]></category>
		<category><![CDATA[Tips]]></category>

		<guid isPermaLink="false">http://john-sheehan.com/blog/index.php/how-i-use-subsonic-part-2/</guid>
		<description><![CDATA[In Part 1, I covered building a ControllerBase class to use with SubSonic 2.1’s new RepositoryRecord entity base class. In order to get the hybrid API (RepostoryRecord + Foreign Key lazy-loaded properties) I like, I had to make some changes to the code generation templates. Here’s what I do. First off, go into Program Files\SubSonic [...]]]></description>
			<content:encoded><![CDATA[<p>In <a target="_blank" href="http://john-sheehan.com/blog/index.php/how-i-use-subsonic-part-1/">Part 1</a>, I covered building a ControllerBase class to use with SubSonic 2.1’s new RepositoryRecord entity base class. In order to get the hybrid API (RepostoryRecord + Foreign Key lazy-loaded properties) I like, I had to make some changes to the code generation templates. Here’s what I do.</p>
<p>First off, go into Program Files\SubSonic 2.1 Final\src\CodeGeneration\Templates and copy the CS_ templates to a new folder. I put them in the root of my project so that I can keep them in under version control. Then, in your app.config or web.config, add the following to make sure that future generations will use the modified copy of the templates:</p>
<div class="csharpcode">
<pre><span class="lnum">   1:  </span>&lt;SubSonicService defaultProvider=<span class="str">&quot;NorthwindProvider&quot;</span></pre>
<pre><span class="lnum">   2:  </span>                 templateDirectory=<span class="str">&quot;C:\Full_Path_To\SubSonicTemplates&quot;</span>&gt;</pre>
<pre><span class="lnum">   3:  </span>    &lt;providers&gt;</pre>
<pre><span class="lnum">   4:  </span>        &lt;clear/&gt;</pre>
<pre><span class="lnum">   5:  </span>        &lt;add ... /&gt;</pre>
<pre><span class="lnum">   6:  </span>    &lt;/providers&gt;</pre>
<pre><span class="lnum">   7:  </span>&lt;/SubSonicService&gt;</pre>
</div>
<style type="text/css">
<p>.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
</p>
<p>Another thing you should know before we continue is an important naming convention I make sure to use for foreign key fields. My foreign key fields ALWAYS end in ‘ID’. That’s pretty standard. But when I have a table that has multiple foreign key fields that relate to the same table, I make sure the field name represents what the relation is, even if the field name doesn’t match the foreign table name. For example, my goal with this is to be able to do this:</p>
<div class="csharpcode">
<pre><span class="lnum">   1:  </span><span class="rem">// News.Author is a User object</span></pre>
<pre><span class="lnum">   2:  </span><span class="kwrd">string</span> authorName = News.Author.DisplayName;</pre>
<pre><span class="lnum">   3:  </span><span class="rem">// News.Editor is also a User object</span></pre>
<pre><span class="lnum">   4:  </span><span class="kwrd">string</span> editorName = News.Editor.DisplayName;</pre>
</div>
<p>The default SubSonic templates don’t handle this situation very well. The first FK it encounters is named News.User and the second gets a funky name I don’t even recall. It can be very confusing to use. Since I always make sure my columns are named a specific way, I decided that I wanted my property names to just lop off the ‘ID’ suffix and use whatever was left. Since a table can’t have two columns with the same name, I never have naming conflicts. Updating the CS_ClassTemplate.aspx template to handle this is straightforward:</p>
<div class="csharpcode">
<pre><span class="lnum">   1:  </span><span class="rem">// replace this section</span></pre>
<pre><span class="lnum">   2:  </span><span class="kwrd">string</span> fkClass = fk.ClassName;</pre>
<pre><span class="lnum">   3:  </span><span class="kwrd">string</span> fkClassQualified = provider.GeneratedNamespace + <span class="str">&quot;.&quot;</span> + fkClass;</pre>
<pre><span class="lnum">   4:  </span><span class="kwrd">string</span> fkMethod = fk.ClassName;</pre>
<pre><span class="lnum">   5:  </span><span class="kwrd">string</span> fkID = tbl.GetColumn(fk.ColumnName).PropertyName;</pre>
<pre><span class="lnum">   6:  </span><span class="kwrd">string</span> fkColumnID = fk.ColumnName;</pre>
<pre><span class="lnum">   7:  </span>&#160;</pre>
<pre><span class="lnum">   8:  </span><span class="rem">// with this section</span></pre>
<pre><span class="lnum">   9:  </span><span class="kwrd">string</span> fkClass = fk.ClassName;</pre>
<pre><span class="lnum">  10:  </span><span class="kwrd">string</span> fkClassQualified = provider.GeneratedNamespace + <span class="str">&quot;.&quot;</span> + fkClass;</pre>
<pre><span class="lnum">  11:  </span><span class="kwrd">string</span> fkID = tbl.GetColumn(fk.ColumnName).PropertyName;</pre>
<pre><span class="lnum">  12:  </span><span class="kwrd">string</span> fkMethod = fkID.Substring(0, fkID.Length - 2);</pre>
<pre><span class="lnum">  13:  </span><span class="kwrd">string</span> fkColumnID = fk.ColumnName;</pre>
</div>
<p>There’s a few code blocks that immediately follow this to check for relations to itself and duplicate method/property names. I remove those checks because my naming convention never allow for those conflicts to exist.</p>
<p>Because I’m using the RepositoryRecord base class, when these FK properties are called, I need to make sure they call the .Get method on the correct controller. Again, SubSonic makes this easy.</p>
<p>Replace this section:</p>
<div class="csharpcode">
<pre><span class="lnum">   1:  </span><span class="rem">/// &lt;summary&gt;</span></pre>
<pre><span class="lnum">   2:  </span><span class="rem">/// Returns a &lt;%=fkClass%&gt; ActiveRecord object related to this &lt;%=className%&gt;</span></pre>
<pre><span class="lnum">   3:  </span><span class="rem">/// </span></pre>
<pre><span class="lnum">   4:  </span><span class="rem">/// &lt;/summary&gt;</span></pre>
<pre><span class="lnum">   5:  </span><span class="kwrd">public</span> &lt;%=fkClassQualified%&gt; &lt;%=fkMethod%&gt;</pre>
<pre><span class="lnum">   6:  </span>{</pre>
<pre><span class="lnum">   7:  </span>    get { <span class="kwrd">return</span> &lt;%=fkClassQualified%&gt;.FetchByID(<span class="kwrd">this</span>.&lt;%=fkID%&gt;); }</pre>
<pre><span class="lnum">   8:  </span>    set { SetColumnValue(<span class="str">&quot;&lt;%=fkColumnID%&gt;&quot;</span>, <span class="kwrd">value</span>.&lt;%=fkTbl.PrimaryKey.PropertyName%&gt;); }</pre>
<pre><span class="lnum">   9:  </span>}</pre>
</div>
<p>With this:</p>
<div class="csharpcode">
<pre><span class="lnum">   1:  </span><span class="rem">/// &lt;summary&gt;</span></pre>
<pre><span class="lnum">   2:  </span><span class="rem">/// Returns a &lt;%=fkClass%&gt; ActiveRecord object related to this &lt;%=className%&gt;</span></pre>
<pre><span class="lnum">   3:  </span><span class="rem">/// </span></pre>
<pre><span class="lnum">   4:  </span><span class="rem">/// &lt;/summary&gt;</span></pre>
<pre><span class="lnum">   5:  </span><span class="kwrd">protected</span> &lt;%=fkClassQualified%&gt; m_&lt;%=fkMethod%&gt; = <span class="kwrd">null</span>;</pre>
<pre><span class="lnum">   6:  </span><span class="kwrd">public</span> &lt;%=fkClassQualified%&gt; &lt;%=fkMethod%&gt;</pre>
<pre><span class="lnum">   7:  </span>{</pre>
<pre><span class="lnum">   8:  </span>&lt;% <span class="kwrd">if</span> (baseClass != <span class="str">&quot;ActiveRecord&quot;</span>) { %&gt;</pre>
<pre><span class="lnum">   9:  </span>    get { </pre>
<pre><span class="lnum">  10:  </span>        <span class="kwrd">if</span> (m_&lt;%=fkMethod%&gt; == <span class="kwrd">null</span>)</pre>
<pre><span class="lnum">  11:  </span>             m_&lt;%=fkMethod%&gt; = &lt;%=fkClassQualified%&gt;Controller.Get(<span class="kwrd">this</span>.&lt;%=fkID%&gt;); </pre>
<pre><span class="lnum">  12:  </span>        <span class="kwrd">return</span> m_&lt;%=fkMethod%&gt;;</pre>
<pre><span class="lnum">  13:  </span>    }</pre>
<pre><span class="lnum">  14:  </span>&lt;% } <span class="kwrd">else</span> { %&gt;</pre>
<pre><span class="lnum">  15:  </span>    get { <span class="kwrd">return</span> &lt;%=fkClassQualified%&gt;.FetchByID(<span class="kwrd">this</span>.&lt;%=fkID%&gt;); }</pre>
<pre><span class="lnum">  16:  </span>&lt;% } %&gt;</pre>
<pre><span class="lnum">  17:  </span>    set { SetColumnValue(<span class="str">&quot;&lt;%=fkColumnID%&gt;&quot;</span>, <span class="kwrd">value</span>.&lt;%=fkTbl.PrimaryKey.PropertyName%&gt;); }</pre>
<pre><span class="lnum">  18:  </span>}</pre>
</div>
<p>Not only are we now using the Controller to retrieve the item, we’re also storing it in a member variable so every time we call that property for this instance, we only hit the database once.</p>
<p>The last change you need to make to CS_ClassTemplate.aspx is to remove the checks for ActiveRecord so that foreign key properties are still generated even if you select RepositoryRecord. Download the files at the end of the post to see this in action.</p>
<p>There’s also a small change that needs to be added to CS_StructsTemplate.aspx to support my ControllerBase.Delete(int id) customization. Add this between the existing Delete and Destroy methods:</p>
<div class="csharpcode">
<pre><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> Delete&lt;T&gt;(<span class="kwrd">int</span> keyId) <span class="kwrd">where</span> T : RepositoryRecord&lt;T&gt;, <span class="kwrd">new</span>() </pre>
<pre><span class="lnum">   2:  </span>{</pre>
<pre><span class="lnum">   3:  </span>    Repository.Delete&lt;T&gt;(keyId);</pre>
<pre><span class="lnum">   4:  </span>}</pre>
<pre><span class="lnum">   5:  </span><span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> Destroy&lt;T&gt;(<span class="kwrd">int</span> keyId) <span class="kwrd">where</span> T : RepositoryRecord&lt;T&gt;, <span class="kwrd">new</span>() </pre>
<pre><span class="lnum">   6:  </span>{</pre>
<pre><span class="lnum">   7:  </span>    Repository.Destroy&lt;T&gt;(keyId);</pre>
<pre><span class="lnum">   8:  </span>}</pre>
</div>
<p>If you use GUIDs or something else for your key, you’ll have to adjust accordingly (HOWEVER, I am working on committing some new methods to the SubSonic core to allow deleting by key for all data types…stay tuned).</p>
<p>To use these customizations in your own projects, <a target="_blank" href="http://john-sheehan.com/blog/wp-content/uploads/subsonictemplates.zip">download my templates here</a>.</p>
<p>Coming soon is Part 3 which will cover using the ControllerBase to easily add request-length (or longer) caching and query performance auditing. If you have any comments or feedback, I’d love to hear it below!</p>
]]></content:encoded>
			<wfw:commentRss>http://john-sheehan.com/blog/how-i-use-subsonic-part-2/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>How I Use SubSonic, Part 1</title>
		<link>http://john-sheehan.com/blog/how-i-use-subsonic-part-1/</link>
		<comments>http://john-sheehan.com/blog/how-i-use-subsonic-part-1/#comments</comments>
		<pubDate>Thu, 23 Oct 2008 03:54:09 +0000</pubDate>
		<dc:creator>John</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[SubSonic]]></category>

		<guid isPermaLink="false">http://john-sheehan.com/blog/index.php/how-i-use-subsonic-part-1/</guid>
		<description><![CDATA[I started heavily using SubSonic right around the time Rob Conery released his poorly-named ‘MVC Templates’. I was never a fan of the ActiveRecord pattern, but I really liked the Repository pattern used in the MVC Templates. The controllers generated by these templates were partial classes that inherited a base class that offered some common [...]]]></description>
			<content:encoded><![CDATA[<p>I started heavily using SubSonic right around the time Rob Conery released his poorly-named ‘<a target="_blank" href="http://blog.wekeroad.com/2007/07/17/subsonic-mvc-templates-available-and-a-security-update/">MVC Templates</a>’. I was never a fan of the ActiveRecord pattern, but I really liked the Repository pattern used in the MVC Templates. The controllers generated by these templates were partial classes that inherited a base class that offered some common methods like List, Get, Delete, Save, etc. For each project, I would build up a pretty substantial set of controllers and I would have all my data access code in a nice centralized library.</p>
<p>The only place I made any real changes was with the templates themselves. Rob’s shipping version didn’t include lazy-loaded properties or methods for foreign keys like ActiveRecord. I really liked this feature, so I added them back to the templates using the controllers’ Get methods to call the correct item.</p>
<p>This worked great for awhile until I wanted to extend the base class. Despite repeatedly asking Rob for the source to his unofficial branch (and never getting an email back), I was stuck with what was there for awhile. Then along came SubSonic 2.1 and the new <a target="_blank" href="http://blog.wekeroad.com/2008/01/16/subsonic-21-pakala-preview-part-2/">RepositoryRecord</a> base class.</p>
<p>I really wanted to use the new SqlQuery capabilities so off I went to migrate my existing Controllers. In Part 1, I’ll cover recreating the ControllerBase class. In Part 2, I’ll outline my changes to the code gen templates. In Part 3, I’ll cover some caching and query metrics this architecture let me easily add.</p>
<p>This is the class definition I needed to replicate:</p>
<p><img style="border-bottom: 0px; border-left: 0px; border-top: 0px; border-right: 0px" title="Old SubSonic ActiveController" border="0" alt="Old SubSonic ActiveController" src="http://john-sheehan.com/blog/wp-content/uploads/20081022-2201.png" width="634" height="352" /></p>
<p>The methods I used most frequently were:</p>
<ul>
<li><strong>Delete(object keyID): </strong>In my controllers, I would add a <strong>Delete(ItemType item)</strong> method, handle any pre-delete logic there, and then call Delete(keyID) within my method.</li>
<li><strong>Get(object key):</strong> This method was called extensively in my generated objects when loading foreign key properties. Also used whenever I need a single item.</li>
<li><strong>List(): </strong>Rarely used since it’s the equivalent of &quot;SELECT * FROM Table&quot; which isn’t very useful except for in my utility classes. Still used however.</li>
<li><strong>List(IDataReader rdr)</strong>: I used this with my StoredProcedures to get a strongly-typed collection from the results of calling the sprocs.</li>
<li><strong>List(Query q):</strong> All other non-sproc collection loading was done here by passing a Query object from my Controllers.</li>
<li><strong>Save(ItemType item, string, userName):</strong> In my controllers, I would add a <strong>Save(ItemType item)</strong> method overload, handle all the saving logic and validation, then call this method when I needed to finalize the changes. (Yes, this ended up with a lot of business-logic leaking into my DAL, but that was my fault, not SubSonic’s and it is currently being remedied).</li>
</ul>
<p>My new ControllerBase needed to support all of the above scenarios and work with the new SqlQuery object.</p>
</p>
</p>
</p>
</p>
</p>
<p>I started with the easiest methods to replicate:</p>
<div class="csharpcode">
<pre><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">class</span> ControllerBase&lt;ItemType, ListType&gt;</pre>
<pre><span class="lnum">   2:  </span>    <span class="kwrd">where</span> ItemType : RepositoryRecord&lt;ItemType&gt;, <span class="kwrd">new</span>()</pre>
<pre><span class="lnum">   3:  </span>    <span class="kwrd">where</span> ListType : RepositoryList&lt;ItemType, ListType&gt;, <span class="kwrd">new</span>()</pre>
<pre><span class="lnum">   4:  </span>{</pre>
<pre><span class="lnum">   5:  </span>    <span class="kwrd">public</span> <span class="kwrd">static</span> ListType List()</pre>
<pre><span class="lnum">   6:  </span>    {</pre>
<pre><span class="lnum">   7:  </span>        <span class="kwrd">return</span> DB.Select().From&lt;ItemType&gt;().ExecuteAsCollection&lt;ListType&gt;();</pre>
<pre><span class="lnum">   8:  </span>    }</pre>
<pre><span class="lnum">   9:  </span>&#160;</pre>
<pre><span class="lnum">  10:  </span>    <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> Delete(<span class="kwrd">int</span> id)</pre>
<pre><span class="lnum">  11:  </span>    {</pre>
<pre><span class="lnum">  12:  </span>        DB.Delete&lt;ItemType&gt;(id);</pre>
<pre><span class="lnum">  13:  </span>    }</pre>
<pre><span class="lnum">  14:  </span>&#160;</pre>
<pre><span class="lnum">  15:  </span>    <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> Save(ItemType item, <span class="kwrd">string</span> username)</pre>
<pre><span class="lnum">  16:  </span>    {</pre>
<pre><span class="lnum">  17:  </span>        DB.Save(item, username);</pre>
<pre><span class="lnum">  18:  </span>    }</pre>
<pre><span class="lnum">  19:  </span>}</pre>
</div>
<style type="text/css">
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<p>SubSonic pros will know there’s no DB.Delete(int id) method in SubSonicRepository. You’ll have to download the source and add it yourself if you want to replicate this solution exactly. Here’s the code to add to SubSonicRepository.cs (you’ll also need to update ISubSonicRepository):</p>
<div class="csharpcode">
<pre><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">void</span> Delete&lt;T&gt;(<span class="kwrd">int</span> itemId) <span class="kwrd">where</span> T : RepositoryRecord&lt;T&gt;, <span class="kwrd">new</span>()</pre>
<pre><span class="lnum">   2:  </span>{</pre>
<pre><span class="lnum">   3:  </span>    T item = <span class="kwrd">new</span> T();</pre>
<pre><span class="lnum">   4:  </span>    TableSchema.Table tbl = item.GetSchema();</pre>
<pre><span class="lnum">   5:  </span>    <span class="kwrd">string</span> pkColumn = tbl.PrimaryKey.ColumnName;</pre>
<pre><span class="lnum">   6:  </span>    Delete&lt;T&gt;(pkColumn, itemId);</pre>
<pre><span class="lnum">   7:  </span>}</pre>
</div>
<p>OK, back to ControllerBase. Next up was replicating the List overloads for building a collection from a Query object and a Stored Procedure.</p>
<div class="csharpcode">
<pre><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">static</span> ListType List(Query query)</pre>
<pre><span class="lnum">   2:  </span>{</pre>
<pre><span class="lnum">   3:  </span>    ListType coll = GetCollectionFromReader(query.ExecuteReader());</pre>
<pre><span class="lnum">   4:  </span>    <span class="kwrd">return</span> coll;</pre>
<pre><span class="lnum">   5:  </span>}</pre>
<pre><span class="lnum">   6:  </span>&#160;</pre>
<pre><span class="lnum">   7:  </span><span class="kwrd">public</span> <span class="kwrd">static</span> ListType List(StoredProcedure s)</pre>
<pre><span class="lnum">   8:  </span>{</pre>
<pre><span class="lnum">   9:  </span>    ListType coll = GetCollectionFromReader(s.GetReader());</pre>
<pre><span class="lnum">  10:  </span>    <span class="kwrd">return</span> coll;</pre>
<pre><span class="lnum">  11:  </span>}</pre>
<pre><span class="lnum">  12:  </span>&#160;</pre>
<pre><span class="lnum">  13:  </span><span class="kwrd">protected</span> <span class="kwrd">static</span> ListType GetCollectionFromReader(IDataReader rdr)</pre>
<pre><span class="lnum">  14:  </span>{</pre>
<pre><span class="lnum">  15:  </span>    ListType coll = <span class="kwrd">new</span> ListType();</pre>
<pre><span class="lnum">  16:  </span>    coll.LoadAndCloseReader(rdr);</pre>
<pre><span class="lnum">  17:  </span>    <span class="kwrd">return</span> coll;</pre>
<pre><span class="lnum">  18:  </span>}</pre>
</div>
<p>And the Get method:</p>
<div class="csharpcode">
<pre><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">static</span> ItemType Get(<span class="kwrd">object</span> id)</pre>
<pre><span class="lnum">   2:  </span>{</pre>
<pre><span class="lnum">   3:  </span>    <span class="kwrd">if</span> (id == <span class="kwrd">null</span>)</pre>
<pre><span class="lnum">   4:  </span>        <span class="kwrd">return</span> <span class="kwrd">default</span>(ItemType);</pre>
<pre><span class="lnum">   5:  </span>&#160;</pre>
<pre><span class="lnum">   6:  </span>    ItemType item = DB.Get&lt;ItemType&gt;(id);</pre>
<pre><span class="lnum">   7:  </span>&#160;</pre>
<pre><span class="lnum">   8:  </span>    <span class="kwrd">return</span> item;</pre>
<pre><span class="lnum">   9:  </span>}</pre>
</div>
<p>Supporting the new SqlQuery object was trivial:</p>
<div class="csharpcode">
<pre><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">static</span> ListType List(SqlQuery q)</pre>
<pre><span class="lnum">   2:  </span>{</pre>
<pre><span class="lnum">   3:  </span>    ListType coll = q.ExecuteAsCollection&lt;ListType&gt;();</pre>
<pre><span class="lnum">   4:  </span>    <span class="kwrd">return</span> coll;</pre>
<pre><span class="lnum">   5:  </span>}</pre>
</div>
<p>That was all I needed for backwards compatibility. I then added a new method with overloads for Query, SqlQuery and StoredProcedure to return a single item (thanks to Rob for responding to my feature request in the forums and implementing ExecuteSingle&lt;T&gt;()):</p>
<div class="csharpcode">
<pre><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">static</span> ItemType GetFirst(SqlQuery q)</pre>
<pre><span class="lnum">   2:  </span>{</pre>
<pre><span class="lnum">   3:  </span>    <span class="kwrd">return</span> q.ExecuteSingle&lt;ItemType&gt;();</pre>
<pre><span class="lnum">   4:  </span>}</pre>
<pre><span class="lnum">   5:  </span>&#160;</pre>
<pre><span class="lnum">   6:  </span><span class="kwrd">public</span> <span class="kwrd">static</span> ItemType GetFirst(Query q) <span class="rem">// also created an overload for StoredProcedure</span></pre>
<pre><span class="lnum">   7:  </span>{</pre>
<pre><span class="lnum">   8:  </span>    ListType coll = List(q);</pre>
<pre><span class="lnum">   9:  </span>&#160;</pre>
<pre><span class="lnum">  10:  </span>    <span class="kwrd">if</span> (coll.Count == 0)</pre>
<pre><span class="lnum">  11:  </span>    {</pre>
<pre><span class="lnum">  12:  </span>        <span class="kwrd">return</span> <span class="kwrd">default</span>(ItemType);</pre>
<pre><span class="lnum">  13:  </span>    }</pre>
<pre><span class="lnum">  14:  </span>    <span class="kwrd">else</span></pre>
<pre><span class="lnum">  15:  </span>    {</pre>
<pre><span class="lnum">  16:  </span>        <span class="kwrd">return</span> coll[0];</pre>
<pre><span class="lnum">  17:  </span>    }</pre>
<pre><span class="lnum">  18:  </span>}</pre>
</div>
<p>And there you have it. A backwards-compatible controller base class that lets you use the new features of SubSonic 2.1. You can <a target="_blank" href="http://john-sheehan.com/blog/wp-content/uploads/controllerbase.txt">download the complete class</a> for use in your own projects. Part 2 (hopefully tomorrow) will cover my SubSonic template customizations.</p>
]]></content:encoded>
			<wfw:commentRss>http://john-sheehan.com/blog/how-i-use-subsonic-part-1/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
