<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" version="2.0">

<channel>
	<title>Where's Lou</title>
	
	<link>http://whereslou.com</link>
	<description>It works on my machine</description>
	<pubDate>Mon, 26 Oct 2009 04:39:25 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/WheresLou" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
		<title>Injecting an ILogger property with Autofac</title>
		<link>http://whereslou.com/2009/10/25/injecting-an-ilogger-property-with-autofac</link>
		<comments>http://whereslou.com/2009/10/25/injecting-an-ilogger-property-with-autofac#comments</comments>
		<pubDate>Mon, 26 Oct 2009 04:39:25 +0000</pubDate>
		<dc:creator>Louis</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[autofac]]></category>

		<category><![CDATA[IoC]]></category>

		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://whereslou.com/?p=672</guid>
		<description><![CDATA[I&#8217;ve always liked the Castle.Core ILogger and ILoggerFactory abstraction. I don&#8217;t know why but I&#8217;ve never been a fan of log4net so I like to keep direct dependencies to it at arm&#8217;s length.
Looking into Autofac recently, I was trying to find a way of getting a logger property assigned as a component is created from [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve always liked the Castle.Core ILogger and ILoggerFactory abstraction. I don&#8217;t know why but I&#8217;ve never been a fan of log4net so I like to keep direct dependencies to it at arm&#8217;s length.</p>
<p>Looking into <a href="http://code.google.com/p/autofac/">Autofac</a> recently, I was trying to find a way of getting a logger property assigned as a component is created from the container in the same way as <a href="http://www.castleproject.org/container/index.html">Windsor</a>&#8217;s <a href="http://www.castleproject.org/container/facilities/trunk/logging/index.html">logging facility</a>. The Autofac container has a <a href="http://code.google.com/p/autofac/wiki/StructuringWithModules">Module/IModule</a> extensibility which works well for the tasks a facility would have done.</p>
<p>Here&#8217;s the type of code I&#8217;m used to seeing from logging. </p>
<pre class="brush: csharp;">
using Castle.Core.Logging;

namespace LoggingStudy {
    public interface IFoo {
        void Bar();
    }

    public class Foo : IFoo {
        public Foo() {
            Logger = NullLogger.Instance;
        }

        public ILogger Logger { get; set; }

        public void Bar() {
            Logger.Info(&quot;Bar called&quot;);
        }
    }
}
</pre>
<p><span id="more-672"></span><br />
And here&#8217;s how you&#8217;d add a logging module to an Autofac builder.</p>
<pre class="brush: csharp;">
using Autofac.Builder;

namespace LoggingStudy {

    class Program {
        static void Main(string[] args) {
            var builder = new ContainerBuilder();
            builder.RegisterModule(new LoggingModule());
            builder.Register&lt;Foo&gt;().As&lt;IFoo&gt;();

            var container = builder.Build();

            using (var scope = container.CreateInnerContainer()) {
                var foo = scope.Resolve&lt;IFoo&gt;();
                foo.Bar();
            }
        }
    }
}
</pre>
<p>And here&#8217;s an implementation of a LoggingModule that will use Castle&#8217;s ILoggerFactory to assign the ILogger typed public properties. Some of the code is based on a few threads in the discussion group.</p>
<pre class="brush: csharp;">
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Autofac;
using Autofac.Builder;
using Castle.Core.Logging;

namespace LoggingStudy {
    public class LoggingModule : Autofac.Builder.Module {
        protected override void Load(ContainerBuilder moduleBuilder) {
            // by default, use Castle's TraceSource based logger factory
            moduleBuilder.Register&lt;TraceLoggerFactory&gt;().As&lt;ILoggerFactory&gt;().ContainerScoped();

            // call CreateLogger in response to the request for an ILogger implementation
            moduleBuilder.Register((ctx, ps) =&gt; CreateLogger(ctx, ps)).As&lt;ILogger&gt;().FactoryScoped();
        }

        protected override void AttachToComponentRegistration(IContainer container, IComponentRegistration registration) {
            var implementationType = registration.Descriptor.BestKnownImplementationType;

            // build an array of actions on this type to assign loggers to member properties
            var injectors = BuildLoggerInjectors(implementationType).ToArray();

            // if there are no logger properties, there's no reason to hook the activated event
            if (!injectors.Any())
                return;

            // otherwise, whan an instance of this component is activated, inject the loggers on the instance
            registration.Activated += (s, e) =&gt; {
                foreach (var injector in injectors)
                    injector(e.Context, e.Instance);
            };
        }

        private static IEnumerable&lt;Action&lt;IContext, object&gt;&gt; BuildLoggerInjectors(Type componentType) {
            // Look for settable properties of type &quot;ILogger&quot;
            var loggerProperties = componentType
                .GetProperties(BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance)
                .Select(p =&gt; new {
                    PropertyInfo = p,
                    p.PropertyType,
                    IndexParameters = p.GetIndexParameters(),
                    Accessors = p.GetAccessors(false)
                })
                .Where(x =&gt; x.PropertyType == typeof(ILogger)) // must be a logger
                .Where(x =&gt; x.IndexParameters.Count() == 0) // must not be an indexer
                .Where(x =&gt; x.Accessors.Length != 1 || x.Accessors[0].ReturnType == typeof(void)); //must have get/set, or only set

            // Return an array of actions that resolve a logger and assign the property
            foreach (var entry in loggerProperties) {
                var propertyInfo = entry.PropertyInfo;

                yield return (ctx, instance) =&gt; {
                    var propertyValue = ctx.Resolve&lt;ILogger&gt;(new TypedParameter(typeof(Type), componentType));
                    propertyInfo.SetValue(instance, propertyValue, null);
                };
            }
        }

        private static ILogger CreateLogger(IContext context, IEnumerable&lt;Parameter&gt; parameters) {
            // return an ILogger in response to Resolve&lt;ILogger&gt;(componentTypeParameter)
            var loggerFactory = context.Resolve&lt;ILoggerFactory&gt;();
            var containingType = parameters.TypedAs&lt;Type&gt;();
            return loggerFactory.Create(containingType);
        }
    }
}
</pre>
<p>The TraceLoggerFactory is added as a default ILoggerFactory. It&#8217;s my favorite one and because it&#8217;s based on System.Diagnostics TraceSource it doesn&#8217;t require additional assemblies.</p>
<p>If you expect to Resolve<ILogger> from a container you&#8217;ll need to add a TypedParameter for typeof(Type), because the logger factory needs that information. It also doesn&#8217;t work to provide an ILogger constructor parameter as it&#8217;s written, but if ILogger properties are what you&#8217;re looking for it should do the job.</p>
<img src="http://feeds.feedburner.com/~r/WheresLou/~4/QC-5wUY5D4g" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://whereslou.com/2009/10/25/injecting-an-ilogger-property-with-autofac/feed</wfw:commentRss>
		</item>
		<item>
		<title>Herding Code podcast about Spark</title>
		<link>http://whereslou.com/2009/09/24/herding-code-podcast-about-spark</link>
		<comments>http://whereslou.com/2009/09/24/herding-code-podcast-about-spark#comments</comments>
		<pubDate>Thu, 24 Sep 2009 18:47:01 +0000</pubDate>
		<dc:creator>Louis</dc:creator>
		
		<category><![CDATA[opensource]]></category>

		<category><![CDATA[spark]]></category>

		<category><![CDATA[geek]]></category>

		<category><![CDATA[podcast]]></category>

		<category><![CDATA[tech]]></category>

		<guid isPermaLink="false">http://whereslou.com/?p=668</guid>
		<description><![CDATA[ The Herding Code 60: Spark View Engine with Louis DeJardin podcast just went up. Really fun group of guys. Interesting process they use to record also and seemed to work really well. I can just never get used to the sound of my own voice.
]]></description>
			<content:encoded><![CDATA[<p><a href="http://herdingcode.com/?p=216"><img src="http://whereslou.com/wp-content/uploads/2009/09/herdingcode-165px.png" alt="Herding Code" title="Herding Code" width="165" height="165" class="alignright size-full wp-image-669" /></a> The <a href="http://herdingcode.com/?p=216">Herding Code 60: Spark View Engine with Louis DeJardin</a> podcast just went up. Really fun group of guys. Interesting process they use to record also and seemed to work really well. I can just never get used to the sound of my own voice.</p>
<img src="http://feeds.feedburner.com/~r/WheresLou/~4/w5htLkqPPog" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://whereslou.com/2009/09/24/herding-code-podcast-about-spark/feed</wfw:commentRss>
		</item>
		<item>
		<title>Memory pressure and scale</title>
		<link>http://whereslou.com/2009/09/18/memory-pressure-and-scale</link>
		<comments>http://whereslou.com/2009/09/18/memory-pressure-and-scale#comments</comments>
		<pubDate>Fri, 18 Sep 2009 16:34:44 +0000</pubDate>
		<dc:creator>Louis</dc:creator>
		
		<category><![CDATA[tech]]></category>

		<category><![CDATA[question]]></category>

		<guid isPermaLink="false">http://whereslou.com/?p=505</guid>
		<description><![CDATA[This is an open question really for people that make, use, or host ASP.NET apps&#8230; When you&#8217;re choosing a technology stack how important are memory pressure concerns?
So if you&#8217;re looking at adding automapper, or nhiberbate, or ioc xyz, you&#8217;re obviously going to be thinking about impact to CPU and memory.
And there are two type of [...]]]></description>
			<content:encoded><![CDATA[<p>This is an open question really for people that make, use, or host ASP.NET apps&#8230; When you&#8217;re choosing a technology stack how important are memory pressure concerns?</p>
<p>So if you&#8217;re looking at adding automapper, or nhiberbate, or ioc xyz, you&#8217;re obviously going to be thinking about impact to CPU and memory.</p>
<p>And there are two type of memory impacts: load-and-hold and burn-rate (or memory pressure). The first is relatively easy to say you&#8217;re using ten megs of one-time cost memory in each appdomain once it&#8217;s initialized and warmed up. The other&#8217;s a bit more subtle - if a tool goes through a two megs of object, string, collection, buffer memory in a request - and say you&#8217;re tooling along with bursts of 25 req/sec - then 50meg/sec means you&#8217;ve given the garbage collector a gig of ram to recycle every 20 seconds. Numbers and needs vary but you get the idea that high burn rates end up causing a CPU tax to be paid affecting the net power availabe. </p>
<p>But on the other hand dotnet is a high level language, and a lot of there types of things are developer productivity tools - not performance tool - so they will *always* have measurable increase in cost. But in the most extreme cases, like from he point of view of a hosting company, you could almost assume that memory efficiency is directly proportional to hardware, space, and power costs per client&#8230; </p>
<p>Not that it&#8217;s a black and white situation, of course, but at what point are the conveniences and strengths of a library outweighed by the cost of using it? Of course it&#8217;s always difficult to weigh something subjective against something quantifiable. </p>
<p>But what&#8217;s your take on that? </p>
<img src="http://feeds.feedburner.com/~r/WheresLou/~4/w5zd6twZfmc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://whereslou.com/2009/09/18/memory-pressure-and-scale/feed</wfw:commentRss>
		</item>
		<item>
		<title>Building 42</title>
		<link>http://whereslou.com/2009/09/16/building-42</link>
		<comments>http://whereslou.com/2009/09/16/building-42#comments</comments>
		<pubDate>Thu, 17 Sep 2009 02:51:26 +0000</pubDate>
		<dc:creator>Louis</dc:creator>
		
		<category><![CDATA[tech]]></category>

		<category><![CDATA[microsoft]]></category>

		<guid isPermaLink="false">http://whereslou.com/?p=651</guid>
		<description><![CDATA[ The first blog post was keyed in from a mobile phone before new employee orientation, so I thought I would take a moment to write a more thoughtful post about the first few days. Well, maybe not more thoughtful&#8230; But at least a post that has some links and images in it.
For example, Building [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://whereslou.com/wp-content/uploads/2009/09/ms_net_rgb_web.jpg" alt="ms_net_rgb_web" title="ms_net_rgb_web" width="328" height="80" class="alignright size-full wp-image-656" /> The first blog post was keyed in from a mobile phone before new employee orientation, so I thought I would take a moment to write a more thoughtful post about the first few days. Well, maybe not more thoughtful&#8230; But at least a post that has some links and images in it.</p>
<p>For example, <a href="http://www.bing.com/maps/default.aspx?v=2&#038;FORM=LMLTCP&#038;cp=ry5vpx4tp0cf&#038;style=b&#038;lvl=1&#038;tilt=-90&#038;dir=0&#038;alt=-1000&#038;phx=0&#038;phy=0&#038;phscl=1&#038;scene=3689071&#038;encType=1&#038;cid=B387831F07F582B4!529">Building 42</a>! My new home. I swear walking into the campus this morning I couldn&#8217;t keep the grin off my face.</p>
<p><a href="http://www.bing.com/maps/default.aspx?v=2&#038;FORM=LMLTCP&#038;cp=ry5vpx4tp0cf&#038;style=b&#038;lvl=1&#038;tilt=-90&#038;dir=0&#038;alt=-1000&#038;phx=0&#038;phy=0&#038;phscl=1&#038;scene=3689071&#038;encType=1&#038;cid=B387831F07F582B4!529"><img src="http://whereslou.com/wp-content/uploads/2009/09/building42.png" alt="building42" title="building42" width="478" height="476" class="size-full wp-image-652" /></a></p>
<p>Let&#8217;s see&#8230; What else is there. Ah! There are people in the building! To name a few there&#8217;s <a href="http://weblogs.asp.net/bleroy/archive/2009/08/27/walking-the-tight-rope.aspx">Bertrand Le Roy</a>, Renaud Paquay, Bradley Millington&#8230; Ah, well. I&#8217;m not having much luck finding a public internet presence for a lot of people so I&#8217;ll leave off with the naming of names in case they prefer anonymity. There&#8217;s also people like <a href="http://weblogs.asp.net/scottgu/">Scott Guthrie</a> and <a href="http://haacked.com/">Phil Haack</a> but that would be like pointing out the fact there are roads and trees around the building.</p>
<p>I&#8217;m actually feeling really good about the decision to join Microsoft. Met the team, surrounded by blindingly smart people, workstation fully installed, two beautiful monitors showed up today, getting a handle on where the project is at and where it&#8217;s going. End of the second day and it&#8217;s time to head home now.</p>
<img src="http://feeds.feedburner.com/~r/WheresLou/~4/2XYC0NMTn98" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://whereslou.com/2009/09/16/building-42/feed</wfw:commentRss>
		</item>
		<item>
		<title>Huge changes. Thrilling and stressful</title>
		<link>http://whereslou.com/2009/09/14/huge-changes-thrilling-and-stressful</link>
		<comments>http://whereslou.com/2009/09/14/huge-changes-thrilling-and-stressful#comments</comments>
		<pubDate>Mon, 14 Sep 2009 14:57:36 +0000</pubDate>
		<dc:creator>Louis</dc:creator>
		
		<category><![CDATA[tech]]></category>

		<category><![CDATA[job]]></category>

		<category><![CDATA[microsoft]]></category>

		<guid isPermaLink="false">http://whereslou.com/?p=647</guid>
		<description><![CDATA[It&#8217;s another one of those self-titled Where&#8217;s Lou posts today! So - where&#8217;s Lou now? New employee orientation in Washington! And Brenda&#8217;s still in Florida at the moment so the DeJardin household is about as geographically distributed as we&#8217;ve ever been. :)
The big news today is I&#8217;ve accepted a position at Microsoft, which is the [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s another one of those self-titled Where&#8217;s Lou posts today! So - where&#8217;s Lou now? New employee orientation in Washington! And Brenda&#8217;s still in Florida at the moment so the DeJardin household is about as geographically distributed as we&#8217;ve ever been. :)</p>
<p>The big news today is I&#8217;ve accepted a position at Microsoft, which is the final realization of an ambition of mine which started a year and a half ago. What hooked me then was watching the open style of development the ASP.NET MVC team was embracing and the great results and positive community feedback they were getting. I though to myself, if there was someplace you could choose to work that would be it.</p>
<p>I should add I&#8217;m not on the MVC team, but since I don&#8217;t know what&#8217;s public knowledge yet or not - please forgive me being vague. </p>
<p>Plus if anyone&#8217;s curious this doesn&#8217;t change the status of Spark regarding license, source, distribution, etc. </p>
<p>But yeah! Exciting! I have to finish up now and grab some coffee and prepare myself for a day of paperwork and hr presentations. Woohoo!  </p>
<img src="http://feeds.feedburner.com/~r/WheresLou/~4/bsU_hkyN5Tc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://whereslou.com/2009/09/14/huge-changes-thrilling-and-stressful/feed</wfw:commentRss>
		</item>
		<item>
		<title>GenCon 2009</title>
		<link>http://whereslou.com/2009/08/13/gencon-2009</link>
		<comments>http://whereslou.com/2009/08/13/gencon-2009#comments</comments>
		<pubDate>Thu, 13 Aug 2009 23:31:54 +0000</pubDate>
		<dc:creator>Louis</dc:creator>
		
		<category><![CDATA[family]]></category>

		<category><![CDATA[gaming]]></category>

		<category><![CDATA[geek]]></category>

		<category><![CDATA[gencon]]></category>

		<guid isPermaLink="false">http://whereslou.com/?p=644</guid>
		<description><![CDATA[Where&#8217;s Lou at the moment? Indianapolis! Specifically GenCon 2009.
Today was the first of four days. Played a BattleTech bootcamp with Alex, some nostalgia there for me because that&#8217;s a game I the old group in high school used to play as well. He loved it - we&#8217;re going to be getting the intro box set [...]]]></description>
			<content:encoded><![CDATA[<p>Where&#8217;s Lou at the moment? <a href="http://maps.google.com/maps?q=indianapolis&#038;oe=utf-8&#038;client=firefox-a&#038;ie=UTF8&#038;split=0&#038;gl=us&#038;ei=Up-ESsOzEIniMKqowe4E&#038;z=10&#038;iwloc=A">Indianapolis</a>! Specifically <a href="http://www.gencon.com/2009/indy/default.aspx">GenCon 2009</a>.</p>
<p>Today was the first of four days. Played a <a href="http://en.wikipedia.org/wiki/BattleTech">BattleTech</a> bootcamp with Alex, some nostalgia there for me because that&#8217;s a game I the old group in high school used to play as well. He loved it - we&#8217;re going to be getting the intro box set when we get home.</p>
<p>Also signed up for an interactive action game <a href="http://www.terrorwerks.com/">TerrorWerks</a>. Lots of fun. Three groups of five players armed with the soft yellow pellet assault rifles on an mission in a background that reminds you of the Aliens movies. I was an engineer (or course) and near the end of the mission was severely wounded and out of ammo, and eventually died trying to pull someone back from the end of a corridor where he was bleeding to death. Yay!</p>
<p>Going to run now to and catch an anime &#8220;Berserk&#8221; being screened. :)</p>
<img src="http://feeds.feedburner.com/~r/WheresLou/~4/e6-UsvKNx4A" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://whereslou.com/2009/08/13/gencon-2009/feed</wfw:commentRss>
		</item>
		<item>
		<title>Beginning ASP.NET MVC 1.0</title>
		<link>http://whereslou.com/2009/08/10/beginning-aspnet-mvc-10</link>
		<comments>http://whereslou.com/2009/08/10/beginning-aspnet-mvc-10#comments</comments>
		<pubDate>Mon, 10 Aug 2009 18:20:13 +0000</pubDate>
		<dc:creator>Louis</dc:creator>
		
		<category><![CDATA[tech]]></category>

		<category><![CDATA[aspnetmvc]]></category>

		<category><![CDATA[books]]></category>

		<category><![CDATA[programming]]></category>

		<category><![CDATA[wrox]]></category>

		<guid isPermaLink="false">http://whereslou.com/?p=635</guid>
		<description><![CDATA[
I had the opportunity the other day to read through Beginning ASP.NET MVC 1.0 written by Simone Chiaretta and Keyvan Nayyeri. I like how it&#8217;s structured if you may be learning about the concepts from scratch.
The first I had heard about the book was quite a while ago when Simone sent me a few questions [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.amazon.com/Beginning-ASP-NET-MVC-Simone-Chiaretta/dp/047043399X/ref=sr_1_1?ie=UTF8&#038;s=books&#038;qid=1249923140&#038;sr=1-1"><img src="http://whereslou.com/wp-content/uploads/2009/08/beginning-aspnet-mvc.jpg" alt="beginning-aspnet-mvc" title="beginning-aspnet-mvc" width="190" height="239" class="alignright size-full wp-image-636" /></a></p>
<p>I had the opportunity the other day to read through <a href="http://www.amazon.com/Beginning-ASP-NET-MVC-Simone-Chiaretta/dp/047043399X/ref=sr_1_1?ie=UTF8&#038;s=books&#038;qid=1249923140&#038;sr=1-1">Beginning ASP.NET MVC 1.0</a> written by <a href="http://codeclimber.net.nz/">Simone Chiaretta</a> and <a href="http://nayyeri.net/">Keyvan Nayyeri</a>. I like how it&#8217;s structured if you may be learning about the concepts from scratch.</p>
<p>The first I had heard about the book was quite a while ago when Simone sent me a few questions about Spark. In the later chapters about extending ASP.NET MVC there&#8217;s a small section that describes various alternate view engines. I have to admit that&#8217;s the first place I flipped to. :)</p>
<p>I especially the fact that after covering the basics early on almost sixty pages are dedicated to unit testing concepts and it&#8217;s implementation for MVC applications. A lot of times in demos and articles even though the importance of testing or TDD is stressed it seems like you don&#8217;t walk away with something actionable if you&#8217;re new to those practices.</p>
<p>Also ends with some real-world samples&#8230; Ah - and all of the code is downloadable from <a href="http://wrox.com">wrox.com</a>. Very nice.</p>
<img src="http://feeds.feedburner.com/~r/WheresLou/~4/1Gr8sWpez2Q" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://whereslou.com/2009/08/10/beginning-aspnet-mvc-10/feed</wfw:commentRss>
		</item>
		<item>
		<title>Spark output caching</title>
		<link>http://whereslou.com/2009/07/28/spark-output-caching</link>
		<comments>http://whereslou.com/2009/07/28/spark-output-caching#comments</comments>
		<pubDate>Tue, 28 Jul 2009 19:23:52 +0000</pubDate>
		<dc:creator>Louis</dc:creator>
		
		<category><![CDATA[spark]]></category>

		<category><![CDATA[aspnetmvc]]></category>

		<category><![CDATA[caching]]></category>

		<category><![CDATA[internet]]></category>

		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://whereslou.com/?p=617</guid>
		<description><![CDATA[Just finished writing the documentation for the most recent feature added to Spark. It provides output caching for sections of a template that could be costly in terms of rendering or data acquisition.
Part of this comes back to Phil&#8217;s blog post about Donut Hole Caching in ASP.NET MVC. Especially below where he writes, as he&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://whereslou.com/wp-content/uploads/2009/07/scales.png" alt="scales" title="scales" width="320" height="282" class="alignright size-full wp-image-622" />Just finished writing the <a href="http://sparkviewengine.com/documentation/caching">documentation for the most recent feature</a> added to <a href="http://sparkviewengine.com">Spark</a>. It provides output caching for sections of a template that could be costly in terms of rendering or data acquisition.</p>
<p>Part of this comes back to Phil&#8217;s blog post about <a href="http://haacked.com/archive/2009/05/12/donut-hole-caching.aspx">Donut Hole Caching in ASP.NET MVC</a>. Especially below where he writes, as he&#8217;s thinking out loud, &#8220;This would have to work in tandem with some means to specify that the bit of view data intended for the partial view is only recreated when the output cache is expired for that partial view, so we don’t incur the cost of creating it on every request.&#8221;</p>
<p>I have to admit I&#8217;m not necessarily a huge fan of the built-in ASP.NET page caching directives&#8230; Also didn&#8217;t particularly care for the forced alignment of partial-boundaries and cache-boundaries. I would hate to have a larger number of smaller files on disk simply because that&#8217;s the breakdown at which I wanted to cache the individual parts. In an ideal world I would like to be able to quickly and easily mark an expensive bit as cacheable, and provide the caching details that relate specifically to that bit, and be done with it.<br />
<span id="more-617"></span><br />
So - enter Spark caching:</p>
<pre class="brush: xml;">
stuff
&lt;cache key=&quot;employeeId&quot; expires=&quot;300&quot;&gt;
  this is stuff about the employee
&lt;/cache&gt;
stuff
</pre>
<p>Kind of simple, really. The key works like the &lt;%@OutputCache%&gt; VaryByParam value, but it can be a comma delimited csharp expressions of anything which makes the cached information unique. </p>
<p>There&#8217;s a ICacheSignal interface which takes the place of custom CacheDependency classes in the ASP.NET caching framework.</p>
<pre class="brush: xml;">
public interface ICacheSignal
{
    event EventHandler Changed;
}
</pre>
<p>If you want fine-grained control to clear out-of-date cached data you would provide an instance of your implementation of this signal, or you can use the built-in ChangeSignal class. So that could be something as simple as:</p>
<pre class="brush: xml;">
stuff
&lt;cache key=&quot;employeeId&quot; signal=&quot;MyApp.Signals.EmployeeTables&quot;&gt;
  this is stuff about the employee
&lt;/cache&gt;
stuff
</pre>
<pre class="brush: csharp;">
public static class Signals
{
  public static ChangeSignal EmployeeTables = new ChangeSignal();
}
</pre>
<p>You app would need to provide the glue to watch the tables and call <code>Signals.EmployeeTables.FireChanged()</code> of course. It does require a bit more effort, but you&#8217;re free to implement your signaling down to whatever level of granularity you would like. If you cache all of the comment html on a blog post, for example, you could keep a dictionary of change signals per-post-id around to drop exactly the correct amount of cached information when a comment is added or removed.</p>
<p>The implementation was a bit tricky in parts, but it should support the all of the cases where once attributes and named content are used inside or around cache elements.</p>
<p>Ah, yes! Back to the original need for avoiding the cost of gathering view data when the related bit of the view is cached. For that you&#8217;d use a trick with a ValueHolder class which enables you to keep your data acquisition code in the controller&#8217;s action, yet enables a cache hit to avoid the cost of that data acquisition.</p>
<pre class="brush: csharp;">
public ActionResult Details(int id)
{
    var data = new NorthwindDataContext();

    ViewData[&quot;employeeId&quot;] = id;

    ViewData[&quot;employee&quot;] = ValueHolder.For(
        () =&gt; data.Employees.Single(x =&gt; x.EmployeeID == id));

    return View();
}
</pre>
<p>In that case for example you could have a cache key=&#8221;employeeId&#8221; and only use the employee.Value property inside that cache. That way if the html for that section (for that employeeId) has already been created and stored, then the second time through .Value property will never be used and the lambda will never be executed. For example:</p>
<pre class="brush: xml;">
&lt;viewdata employeeId=&quot;int&quot; employee=&quot;ValueHolder[[Employee]]&quot; /&gt;
&lt;cache key=&quot;employeeId&quot;&gt;
  &lt;h3&gt;${employee.Value.FirstName} ${employee.Value.LastName}&lt;/h3&gt;
  this is stuff about employee number ${employee.Value.EmployeeID}.
&lt;/cache&gt;
</pre>
<p>So that&#8217;s a kind of nice way to cut out WCF and SQL costs without violating MVC best practices by having your views fetch data. After all it&#8217;s almost never the rendering costs that are the real problem in the first place.</p>
<p>There&#8217;s also a trick you can use with &lt;viewdata&gt; to get rid of the .Value. when you&#8217;re using the object inside a ValueHolder.</p>
<pre class="brush: xml;">
&lt;viewdata employeeId=&quot;int&quot; employee.Value=&quot;Employee employee&quot; /&gt;
&lt;cache key=&quot;employeeId&quot;&gt;
  &lt;h3&gt;${employee.FirstName} ${employee.LastName}&lt;/h3&gt;
  this is stuff about employee number ${employee.EmployeeID}.
&lt;/cache&gt;
</pre>
<p><ins datetime="2009-07-29T15:06:59+00:00">Updated, in answer to Adam&#8217;s question in the comments</ins></p>
<p>A value holder can also by used inside of a strongly typed model, like this.</p>
<pre class="brush: csharp;">
public class EmployeeDetailsModel
{
    // lazy-loaded data
    public ValueHolder&lt;int, Employee&gt; EmployeeHolder {get;set;}

    // aliasing .Key and .Value
    public int EmployeeID {get {return EmployeeHolder.Key;} }
    public Employee Employee {get {return EmployeeHolder.Value;} }
}

public ActionResult Details(int id)
{
    var data = new NorthwindDataContext();

    var model = new EmployeeDetailsModel
    {
        EmployeeHolder = ValueHolder.For(id,
            key =&gt; data.Employees.Single(x =&gt; x.EmployeeID == key))
    };

    return View(model);
}
</pre>
<p>And the usage in the view is about what you would expect.</p>
<pre class="brush: xml;">
&lt;viewdata model=&quot;EmployeeDetailsModel&quot; /&gt;
&lt;cache key=&quot;Model.EmployeeID&quot;&gt;
  &lt;h3&gt;${Model.Employee.FirstName} ${Model.Employee.LastName}&lt;/h3&gt;
  this is stuff about employee number ${Model.Employee.EmployeeID}.
&lt;/cache&gt;
</pre>
<img src="http://feeds.feedburner.com/~r/WheresLou/~4/tN3lEzgdu6I" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://whereslou.com/2009/07/28/spark-output-caching/feed</wfw:commentRss>
		</item>
		<item>
		<title>Retrofit ASP.NET Aspx Urls with System.Web.Routing</title>
		<link>http://whereslou.com/2009/07/08/retrofit-aspnet-aspx-urls-with-systemwebrouting</link>
		<comments>http://whereslou.com/2009/07/08/retrofit-aspnet-aspx-urls-with-systemwebrouting#comments</comments>
		<pubDate>Wed, 08 Jul 2009 14:30:55 +0000</pubDate>
		<dc:creator>Louis</dc:creator>
		
		<category><![CDATA[internet]]></category>

		<category><![CDATA[tech]]></category>

		<category><![CDATA[asp.net]]></category>

		<category><![CDATA[programming]]></category>

		<category><![CDATA[routing]]></category>

		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://whereslou.com/?p=600</guid>
		<description><![CDATA[Here&#8217;s a sample of a technique that might be of general interest. It came up retrofitting a particular url structure onto an existing ASP.NET application originally built with the Web Client Software Factory. I came into the project fairly late in the game and the ROI for migrating to MVC would be nearly zero, so [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a sample of a technique that might be of general interest. It came up retrofitting a particular url structure onto an existing ASP.NET application originally built with the <a href="http://websf.codeplex.com/">Web Client Software Factory</a>. I came into the project fairly late in the game and the ROI for migrating to MVC would be nearly zero, so instead a technique was used which welds System.Web.Routing onto a web forms app in a fairly transparent fashion.</p>
<div id="attachment_603" class="wp-caption alignright" style="width: 220px"><img src="http://whereslou.com/wp-content/uploads/2009/07/lipstick-210x300.jpg" alt="Putting Lipstick on a Web Site" title="lipstick" width="210" height="300" class="size-medium wp-image-603" /><p class="wp-caption-text">Putting Lipstick on a Web Site</p></div>
<p>To start with there are a few ground rules and goals to establish. One is that a 301 permanent redirect is desirable from older urls onto new routed urls. Another is that not all urls in the app need to be fixed &#8220;in place&#8221; in the original html response assuming the 301 redirects will keep the resulting urls canonical. Third is that it&#8217;s highly desirable to be able to calculate the new route given an old url server-side, for such things as the site map and updating the links on pages which are particularly significant.<br />
<span id="more-600"></span><br />
Another consideration is that if a site is currently using Request.QueryString values and relies on postback, both of those should continue to work transparently. A final consideration is the range of possible values in a piece of the route could be driven by a database or source which is non-static or has a huge number of possible distinct values. At least a number too large for adding multiple routes or combining into regex restriction.</p>
<p>Downloads: <a href='http://whereslou.com/wp-content/uploads/2009/07/retrofit.zip'>retrofit.zip</a> source code and sample project.</p>
<p>It turns out the System.Web.Routing module is particularly well suited for this, especially because of the bidirectional nature of it&#8217;s routes. The attached solution has a sample web app and a class library named Retrofit.Routing which provides an example of using System.Web.Routing in this way.</p>
<p>First of all is the class Retrofit.Routing.WebFormsRouteHandler which implements IRouteHandler. You&#8217;ll find in it&#8217;s implementation the method GetHttpHandler which will use BuildManager.CreateInstanceFromVirtualPath to obtain an instance of the targetted web page. The web page is targetted with the RouteData Value parameter named &#8220;VirtualPath&#8221;, much like in an MVC app the controller is targetted with a RouteData Value named &#8220;Controller&#8221;. The other thing this class does is call HttpContext.RewritePath to extend the number of values present on the QueryString. </p>
<p>You won&#8217;t use the WebFormsRouteHandler directly, instead you&#8217;ll create an instance of WebFormsRoute. This WebFormsRoute is a descendant of the standard Route class and is used in almost exactly the same way.</p>
<pre class="brush: csharp;">

public static void RegisterRoutes(RouteCollection routes)
{
    // enable routing of existing files so WebFormsRoute has the chance redirect old urls
    routes.RouteExistingFiles = true;

    // matches customer with a data-driven constraint
    routes.Add(new WebFormsRoute(
        &quot;Customer/{*CompanyName}&quot;,
        new RouteValueDictionary(new {VirtualPath = &quot;~/Contacts/Customer.aspx&quot;}),
        new RouteValueDictionary(new {CompanyName = new ValidCompanyNameConstraint()})
    ));

    // matches orders requests
    routes.Add(new WebFormsRoute(
        &quot;Customer/Orders/{OrderID}&quot;,
        new RouteValueDictionary(new {VirtualPath = &quot;~/Orders/Details.aspx&quot;})
    ));

}
</pre>
<p>As we can see defaults can be provided, which is how the value for VirtualPath is defaulted in when a request pattern is matched. The values like {CompanyName} and {OrderID} which are matched above will become CompanyName= and OrderID= querystring parameters passed to the aspx page as it runs, so the code behind does not need to be modified for those cases.</p>
<p>There&#8217;s even an example above of how you would provide an IRouteConstraint class if you would like to dynamically restrict the set of urls a route is allowed to match.</p>
<pre class="brush: csharp;">
public class ValidCompanyNameConstraint : IRouteConstraint
{
    public ValidCompanyNameConstraint()
    {
        // pre-load valid company names
        // in a real app this would be queries each call to match,
        // or it would be re-cached when the data had changed.

        var data = new NorthwindDataContext();
        CachedNames = data.Customers.ToDictionary(x =&gt; x.CompanyName, x =&gt; x.CustomerID);
    }

    private Dictionary&lt;string, string&gt; CachedNames { get; set; }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        var parameterValue = Convert.ToString(values[parameterName]);
        return CachedNames.ContainsKey(parameterValue);
    }
}
</pre>
<p>It&#8217;s a contrived example, but it is just a sample after all.</p>
<p>And the WebFormsRoute is performing one other task related to the need for 301 redirects. As requests are coming in it&#8217;s not only matching the request against the new url pattern, it&#8217;s also testing the request url against the old virtual path and query string parameters needed. </p>
<pre class="brush: csharp;">
    // do the work to check if the incoming request could also produce
    // a meaningful route to redirect towards
    var probeVirtualPathData = TestVirtualPath(httpContext, virtualPath);
    if (probeVirtualPathData == null)
        return null;

    // the request is on a page which this route controls, 301 redirect
    // onto the correct location
    return new RouteData(this, new PermanentRewriteHandler(probeVirtualPathData.VirtualPath));
}
</pre>
<p>If the incoming request is match for the old url structure then it takes advantage System.Web.Routing&#8217;s ability to calculate the correct url in the new pattern. This new url is used as the parameter of a handler which will return a 301 permanent redirect to keep the browser&#8217;s address bar clean-looking and to ensure web crawlers are indexing the site with at this single, canonical location.</p>
<p>The rewrite handler itself is a pretty simple device.</p>
<pre class="brush: csharp;">
public class PermanentRewriteHandler : IRouteHandler, IHttpHandler
{
    private readonly string _path;

    public PermanentRewriteHandler(string path)
    {
        _path = path;
    }

    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        return this;
    }

    public bool IsReusable
    {
        get { return false; }
    }

    public void ProcessRequest(HttpContext context)
    {
        context.Response.Buffer = true;
        context.Response.Redirect(&quot;~/&quot; + _path, false);
        context.Response.StatusCode = 301;
        context.Response.StatusDescription = &quot;Moved Permanently&quot;;
    }
}
</pre>
<p>At this point nearly all of the goals are met. You can route incoming requests on new urls onto existing WebForms pages, it will 301 redirect incoming old urls onto the new location, the route values are converted to querystring values transparently, and POST to the WebForms life-cycle will pass through unimpeded on the old or new urls.</p>
<p>The final piece of the puzzle is the need to return the new urls in links returned from pages on the server without relying on the 301 redirects. That&#8217;s done easily enough with an extension method Page.ResolveRouteUrl that is used in the same way as Page.ResolveUrl.</p>
<pre class="brush: csharp;">
public static string ResolveRouteUrl(this Page page, string relativeUrl)
{
    var url = relativeUrl;

    var virtualPathData = GetVirtualPathData(relativeUrl);
    if (virtualPathData != null)
    {
        url = &quot;~/&quot; + virtualPathData.VirtualPath;
    }

    return page.ResolveUrl(url);
}
</pre>
<p>And it&#8217;s used like this:</p>
<pre class="brush: xml;">
Company: &lt;asp:HyperLink ID=&quot;HyperLink1&quot; runat=&quot;server&quot;
                NavigateUrl='&lt;%# Page.ResolveRouteUrl(&quot;~/Contacts/Customer.aspx?CompanyName=&quot; + Eval(&quot;CompanyName&quot;)) %&gt;' Text='&lt;%# Eval(&quot;CompanyName&quot;) %&gt;'&gt;&lt;/asp:HyperLink&gt;
</pre>
<p>Downloads: <a href='http://whereslou.com/wp-content/uploads/2009/07/retrofit.zip'>retrofit.zip</a> source code and sample project.</p>
<img src="http://feeds.feedburner.com/~r/WheresLou/~4/iZn1xp_Odgo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://whereslou.com/2009/07/08/retrofit-aspnet-aspx-urls-with-systemwebrouting/feed</wfw:commentRss>
		</item>
		<item>
		<title>Camping weekend</title>
		<link>http://whereslou.com/2009/07/05/camping-weekend</link>
		<comments>http://whereslou.com/2009/07/05/camping-weekend#comments</comments>
		<pubDate>Mon, 06 Jul 2009 03:55:51 +0000</pubDate>
		<dc:creator>Louis</dc:creator>
		
		<category><![CDATA[family]]></category>

		<category><![CDATA[camping]]></category>

		<category><![CDATA[fireworks]]></category>

		<category><![CDATA[spam]]></category>

		<category><![CDATA[vacation]]></category>

		<guid isPermaLink="false">http://whereslou.com/?p=593</guid>
		<description><![CDATA[Lots of fun this weekend camping with Brenda. It was a scramble with some light grocery shopping and packing beforehand so some of the food was improvised. One thing which turned out surprisingly well was the Spam and cheese sandwiches.
In a nutshell - duct tape a tongs to the end of a spatula for length. [...]]]></description>
			<content:encoded><![CDATA[<p>Lots of fun this weekend camping with Brenda. It was a scramble with some light grocery shopping and packing beforehand so some of the food was improvised. One thing which turned out surprisingly well was the Spam and cheese sandwiches.</p>
<p><a href="http://www.spam.com/"><img src="http://whereslou.com/wp-content/uploads/2009/07/spam-150x150.jpg" alt="spam" title="spam" width="150" height="150" class="alignright size-medium wp-image-594" /></a>In a nutshell - duct tape a tongs to the end of a spatula for length. Use the spatula to slice spam into 8mm slices. Place single slice on spatula and wrap around with tin foil, twisting like hard candy wrapper. Cook liberally over fire, unwrap carefully, put on hamburger bun and spray with pressurized cheese in a can. Enjoy.</p>
<p>Brenda swore by them. A warning however - have only one without an antacid on hand.</p>
<p><img src="http://whereslou.com/wp-content/uploads/2009/07/fireworks3-225x300.jpg" alt="fireworks3" title="fireworks3" width="225" height="300" class="alignleft size-medium wp-image-595" />There was a brilliant fireworks display on the fourth with dozens of cakes of two- and three-inch mortars. Long story short Brenda&#8217;s cousin was involved in the show and I was enlisted to be perimeter security. So with flashlights in hand as Brenda and I watched for anyone who would may have wandered up to the launching area and we had point blank view of the show. Didn&#8217;t get hit by much debris at all. :)</p>
<img src="http://feeds.feedburner.com/~r/WheresLou/~4/dKGyD4i-vfs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://whereslou.com/2009/07/05/camping-weekend/feed</wfw:commentRss>
		</item>
	</channel>
</rss>
