tag:blogger.com,1999:blog-307488782024-03-13T15:06:11.189+11:00Add coffee, and shake wellA mixture of posts on computers, photography, cats and holidays. In other words, all the things that interest me most.David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.comBlogger102125tag:blogger.com,1999:blog-30748878.post-61500392402254133072017-03-07T17:56:00.001+11:002017-12-22T12:07:53.680+11:00Writing plugins for Octopus<p>Following on from my <a href="http://davidkeaveny.blogspot.com.au/2017/02/writing-plugins-for-exceptionless.html">previous post about writing plug-ins</a>, here’s the next installment of what may or may not become an irregular feature.</p> <p>I’ve been using <a href="https://octopus.com/">Octopus Deploy</a> at work for several years now, and it is a great tool for automating the deployment of software; in my case, it turned a 20-page manual checklist that took 40 minutes to work through into a five minute fire-and-forget exercise. However, there are still little steps here and there that can’t be automated out-of-the-box, and that’s where we pick up our story.</p> <p>We track our work-in-progress using <a href="https://www.atlassian.com/software/jira">JIRA</a>, and one of those tedious post-release tasks is to update all the tickets, setting their status to Released and so on. So, given that JIRA exposes an API, and Octopus supports custom steps or step templates written in <a href="https://github.com/powershell/powershell">Powershell</a>, why not combine the two and cross another manual step off the list?!</p> <h4>Show me the code!</h4> <p>Actually, I’m not going to post any code snippets this time – rather, I’ve <a href="https://github.com/davidkeaveny/octopus-deploy-library">published the source code to GitHub</a> (something else I’m learning, after 15 years of <a href="https://subversion.apache.org/">Subversion</a>), so go ahead and fork it. There’s not a whole lot of error handling in there at the moment, but it seems to do the trick. There are two files:</p> <ul> <li>the original Powershell file, which you can open up and run in the Powershell IDE;</li> <li>the Octopus Deploy step template, which wraps up the Powershell in a bit and parameterises it to make the code more reusable</li></ul>David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com2tag:blogger.com,1999:blog-30748878.post-75570975800929913612017-02-14T15:39:00.001+11:002017-02-14T15:54:17.987+11:00Writing plugins for Exceptionless<a href="https://exceptionless.com/">Exceptionless</a> is one of those tools that no developer should be without; it integrates with your application (currently .NET and NodeJS platforms are supported, with the promise of more to come), captures your unhandled exceptions, and provides you all sorts of tools to manage these exceptions.<br />
<img height="334" src="https://exceptionless.com/assets/dashboard-2-1024x594.png" width="571" /><br />
The project itself is <a href="https://github.com/exceptionless">open source</a>, and you can set up your own on-premise server to run the service, or you can use their cloud service if you don’t want the hassle of maintaining YADS (Yet Another D**n Server). <br />
Their support is also very good; I’ve been working on a number of different scenarios (e.g. creating custom reports using the API to query for data, at least until they implement custom dashboards). The scenario that prompted this post was simple – when we deploy a new version of our API, we run a suite of automated regression tests to make sure we haven’t broken anything for our customers, but these regression tests include a large number of expected failure tests, which result in a large number of false positives being reported. So time to break open the coding tools and fix that…<br />
<h4>
Show me the code</h4>
The Exceptionless client provides a number of extension points, and after talking to <a href="http://blakeniemyjski.com/">Blake Niemyjski</a>, who seems to be the main point of contact for enquiries, I whipped up the following plugin:<br />
<pre class="brush: csharp">[Priority(5)]
public class SquelchExpectedExceptionsPlugin : IEventPlugin
{
public void Run(EventPluginContext context)
{
var exception = context.ContextData.GetException();
var httpContext = context.ContextData.GetHttpContext();
if (ApiExceptionClassifier.IsAnExpectedException(exception, httpContext.Request.Headers))
{
context.Cancel = true;
}
}
}
internal static class ExceptionlessExtensions
{
internal static HttpActionContext GetHttpContext(this IDictionary<string, object> data)
{
if (!data.ContainsKey("HttpActionContext")) return null;
return data["HttpActionContext"] as HttpActionContext;
}
internal static Exception GetException(this IDictionary<string, object> data)
{
if (!data.ContainsKey("@@_Exception")) return null;
return data["@@Exception"] as Exception;
}
</pre>
I had to add the extension methods as these are currently internal to the Exceptionless.Net library, while the ApiExceptionClassifier is a bit of business logic which checks for a specific header the the request to determine what sort of HTTP status code a given exception should result in (e.g. we want all ValidationExceptions to result in a 400 Bad Request). The plugin priority needs to be set to a low value so that it gets executed as early as possible – there’s not much point in gathering all sorts of data if we’re just going to throw it all away when the Cancel method gets called.<br />
Once that was done, all that is left is to register the plugin in the API’s startup routine:<br />
<pre class="brush: csharp">ExceptionlessClient.Default.Configuration.AddPlugin<SquelchExpectedExceptionsPlugin>();
</pre>
And now, my regression tests don’t fill the Exceptionless reports with noise, unless an actual exception occurs during the process.David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com0tag:blogger.com,1999:blog-30748878.post-21226344823181150212017-02-14T14:47:00.001+11:002017-02-14T14:47:26.781+11:00Back from hiatus<p>It’s been quite a while since I last posted, so it’s probably about time I got back into the habit. More to follow shortly!</p>David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com0tag:blogger.com,1999:blog-30748878.post-38718600369700222412012-09-10T09:41:00.001+10:002012-09-10T09:41:07.412+10:00Surrealism<p>I can’t believe I’ve never heard this joke before today, but it makes me smile:</p> <blockquote> <p>Two penguins are sitting on an ice floe, drifting helplessly north into warmer waters. The penguins are quite fond of each other, but they don’t speak English very well. Suddenly, cra-a-a-a-a-ck, the ice floe splits in two, right between the penguins. As they drift apart, one penguin sadly waves a flipper and calls out, “Chocolate milk!”.</p> </blockquote> <p>Happy Monday!</p> David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com3tag:blogger.com,1999:blog-30748878.post-33882198265582604432012-08-17T15:01:00.001+10:002012-08-17T15:17:26.155+10:00NDoc3 - a modern-day LazarusBack in the early days, the <a href="http://ndoc.sourceforge.net/">nDoc</a> utility was the go-to solution for auto-generating API documentation for .NET applications. The build engine would parse the XML comments that the developer decorated class members with, and nDoc would take those results and produce MSDN-style web pages based on it. As an open source product, it attracted quite a following.<br />
However, with the release of .NET Framework v2, nDoc <a href="http://weblogs.asp.net/fmarguerie/archive/2006/02/16/ndoc-project-stalled-no-version-2-microsoft.aspx">failed to make the jump</a> and instead imploded, being at the time quite a <a href="http://web.archive.org/web/20060819173307/http://johnsbraindump.blogspot.com/2006/07/ndoc-20-is-dead.html">high-profile example</a> of the risks of running an open source project:<br />
<ul>
<li>the community might love your product, but if they don’t contribute something back (whether code, time or money) then it may not be possible for you to continue to develop it; </li>
<li> <div align="left">
the vendor whose environment you are working in (in this case, Microsoft, but it could easily be another company. Apple, anyone?) can <a href="http://weblogs.asp.net/fmarguerie/archive/2006/07/31/Sandcastle-alpha-available-NDoc-discontinued.aspx">move into your space</a> and deliver something that is good enough to draw mindshare away from your target audience. Actually, <a href="http://sandcastle.codeplex.com/">Sandcastle</a> has never really been as good as, nor as easy to use as, nDoc, but the damage was done;</div>
</li>
</ul>
Fast-forward to the near-present time, and while Sandcastle continues to be unwieldy, the open source community is once again <a href="http://eeichinger.blogspot.com.au/2009/03/ndoc-is-dead-long-live-ndoc3.html">picking up the nDoc baton</a>, this time in the form of <a href="http://sourceforge.net/projects/ndoc3/">nDoc3</a>. In its current state, nDoc3 brings to the table support for .NET 3.5, but if you’re prepared to download the source code and build it yourself, you can get .NET 4 support as well. Of course, Microsoft moved the goalposts slightly this week with the <a href="http://blogs.msdn.com/b/jasonz/archive/2012/08/15/visual-studio-2012-and-net-framework-4-5-released-to-the-web.aspx">release of .NET 4.5</a>, so the cycle continues!<br />
If you do want to try getting .NET 4 support, these are the steps that I had to go through (and a few hoops that I needed to jump through):<br />
<ol>
<li>Download the <a href="http://ndoc3.svn.sourceforge.net/viewvc/ndoc3/trunk/">source code from Sourceforge</a>, and extract the tarball to the file system; </li>
<li>Rather than opening in VS2008 as the README file directs, I fired up VS2010; </li>
<li>Building threw up a whole host of warnings, so I decided to try the provided NAnt build scripts; </li>
<li>Building threw up a whole host of warnings, mostly about missing NAnt targets; in the end, I had to hack the NAnt.build file to pieces, first commenting out the references to the JavaDoc, Latex and LinearHtml documenters which, though references in the build file, don’t exist in the source code; I also had to comment out all the code related to testing, as again it referred to folders and/or files that don’t exist; </li>
<li>I also needed to remove a duplicate AssemblyVersion attribute from Core\AssemblyInfo.cs; </li>
<li>This at least allowed me to compile and run the application; however, when I tried to get it to document one of my own pieces of code, it quickly threw an exception which I traced back to an <a href="http://sourceforge.net/tracker/?func=detail&aid=3303504&group_id=212352&atid=1021403">already-reported issue</a>; fortunately, the user who raised the issue also submitted a patch, which while it has not been applied to the source tree, at least fixes the problem. </li>
</ol>
So now I have nDoc3 happily spitting out documentation for me; perhaps if time allows, I will look into writing a Wiki-format documenter.David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com0tag:blogger.com,1999:blog-30748878.post-34275828805969542222012-08-02T23:18:00.000+10:002012-08-02T23:18:28.856+10:00That didn't take longI've been a devotee of the <a href="http://sprw.me/">Sparrow</a> mail app for Mac since it first came out. Its clean interface and seamless integration with GMail put it head-and-shoulders above Apple's own Mail application.<br />
<br />
Unfortunately, those days are numbered - Google's <a href="http://www.macrumors.com/2012/07/20/alternative-email-client-sparrow-acquired-by-google/">recent acquisition of Sparrow</a> is a near-guarantee that the application will receive no further work, beyond promised bug fixes. The timing couldn't be worse - with Apple having just released OS X Mountain Lion, there are bound to be problems with third-party applications, and it seems that Sparrow is already showing some.<br />
<br />
I've been finding the UI locks up on me when composing or sending emails; labelling emails I want to keep isn't happening, nor is the deleting of emails that I don't. I can receive emails OK, so it's not a problem with my network or account. Quitting the application tends to cause it to hang, until I kill its process with extreme prejudice. And it's not just me who's seeing this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyJ2ePAPuNn_qlxWaEad03KGoELHIJGiUudbIZTMV6Xesmmn5Y0SBZNoPAQgXu2VQ1X8qQCxqoBrrdDUVx9oDfOdhofk1KR9LJ0_3D-VGtybXfx4kK9lxh2dWk8uskgK3H-bYdUA/s1600/Screen+Shot+2012-08-02+at+11.09.25+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="139" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyJ2ePAPuNn_qlxWaEad03KGoELHIJGiUudbIZTMV6Xesmmn5Y0SBZNoPAQgXu2VQ1X8qQCxqoBrrdDUVx9oDfOdhofk1KR9LJ0_3D-VGtybXfx4kK9lxh2dWk8uskgK3H-bYdUA/s320/Screen+Shot+2012-08-02+at+11.09.25+PM.png" width="320" /></a></div>
<br />
<br />
All in all, the sort of experience that third-party developers would be rushing to fix; but with Google now calling the shots, how quickly will this happen? I'm not holding my breath.<br />
<br />
Meanwhile, in the interest of actually Getting Things Done, I'm making do with Mail again.David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com0tag:blogger.com,1999:blog-30748878.post-77534335424141652242012-01-27T17:24:00.001+11:002012-01-27T17:24:29.867+11:00A nice little trick with FluentAssertions<p>I love using <a href="http://fluentassertions.codeplex.com">FluentAssertions</a> when writing tests for my code, it just makes the code so expressive in plain language. Recently I’ve been working on tests which involve the testing of lots of properties on a test result, and was looking for a way to remove a lot of the repetition involved.</p> <p>Usually when asserting the properties on a test result, you can do it in three different ways. If I have my test class defined as below:</p> <div class="csharpcode"> <pre class="alt">[TestFixture]</pre>
<pre><span class="kwrd">public</span> <span class="kwrd">class</span> MyTestFixture</pre>
<pre class="alt">{</pre>
<pre> <span class="kwrd">private</span> MyClass _subject; </pre>
<pre class="alt"> <span class="kwrd">private</span> MyOtherClass _result;</pre>
<pre> </pre>
<pre class="alt"> [SetUp]</pre>
<pre> <span class="kwrd">public</span> <span class="kwrd">void</span> ExecuteTest() </pre>
<pre class="alt"> { </pre>
<pre> _subject = <span class="kwrd">new</span> MyClass(); </pre>
<pre class="alt"> _subject.Initialise(<span class="rem">/*.. Some parameters here ..*/</span>); </pre>
<pre> _result = _subject.SomeOperation();</pre>
<pre class="alt"> }</pre>
<pre>}</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>Then I can test the results as follows:</p>
<p><strong>A. Assert all the properties in a test method</strong></p>
<div class="csharpcode">
<pre class="alt"> [Test]</pre>
<pre> <span class="kwrd">public</span> <span class="kwrd">void</span> ThePropertiesAreSet()</pre>
<pre class="alt"> {</pre>
<pre> _result.First.Should().Be(<span class="str">"Paula Bean"</span>);</pre>
<pre class="alt"> _result.Second.Should().Be(<span class="str">"Brillant!"</span>);</pre>
<pre> }</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>This is probably the usual way people do this. However, if the first test fails, the second test will never run, and we'll never know if our test method set the second result correctly or not, so we are lacking information as to the overall state of the test. Secondly, as the number of properties to test increases, you end up with a lot of visual noise, although Intellisense will at least take some of the effort out of creating the noise.</p>
<p><strong>B. Assert the properties in a test method per property</strong></p>
<div class="csharpcode">
<pre class="alt"> [Test]</pre>
<pre> <span class="kwrd">public</span> <span class="kwrd">void</span> TheFirstPropertyIsSet()</pre>
<pre class="alt"> {</pre>
<pre> _result.First.Should().Be(<span class="str">"Paula Bean"</span>);</pre>
<pre class="alt"> }</pre>
<pre> </pre>
<pre class="alt"> [Test]</pre>
<pre> <span class="kwrd">public</span> <span class="kwrd">void</span> TheSecondPropertyIsSet()</pre>
<pre class="alt"> {</pre>
<pre> _result.Second.Should().Be(<span class="str">"Brillant!"</span>);</pre>
<pre class="alt"> }</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>With this approach, we now know if the setting of _result.Second was successful, even if _result.First failed. This extra information does come at the expense of more visual noise (the addition of another test method). Also, it allows you to really game the system if you get rewarded for the number of tests in your project :-)</p>
<p><strong>C. Implement IEquatable</strong></p>
<p>As the number of properties on MyOtherClass go up, you'll find a lot of code appearing in the test method. You can remove this by implemeting IEquatable<MyOtherClass> on MyOtherClass:</p>
<div class="csharpcode">
<pre class="alt"><span class="kwrd">public</span> <span class="kwrd">class</span> MyOtherClass : IEquatable<MyOtherClass></pre>
<pre>{</pre>
<pre class="alt"> <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">bool</span> Equals(MyOtherClass other)</pre>
<pre> {</pre>
<pre class="alt"> <span class="kwrd">return</span> <span class="kwrd">this</span>.First == other.First && <span class="kwrd">this</span>.Second == other.Second;</pre>
<pre> }</pre>
<pre class="alt">}</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>(please note you should also really implement Object.Equals and Object.GetHashCode if you're going to use IEquatable, and for brevity, I've missed out a lot of the basic implementation of IEquatable<T>)</p>
<p>The result of this is that our test method now becomes:</p>
<div class="csharpcode">
<pre class="alt"> [Test]</pre>
<pre> <span class="kwrd">public</span> <span class="kwrd">void</span> TheFirstPropertyIsSet()</pre>
<pre class="alt"> {</pre>
<pre> MyOtherClass expected = <span class="kwrd">new</span> MyOtherClass { First = <span class="str">"Paula Bean"</span>, Second = <span class="str">"Brillant!"</span> };</pre>
<pre class="alt"> _result.Should().Be(expected);</pre>
<pre> }</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>Much cleaner and very expressive, and you'll probably find your code benefits elsewhere from having implementations of IEquatable<T>; but you do have to write that implementation (and perhaps unit test it too!). Yet more code...</p>
<p>This finally leads me to my point: </p>
<p><strong>D. Use anonymous classes and FluentAssertion's AllProperties</strong></p>
<p>How's this for simplicity?</p>
<pre class="csharpcode"> [Test]
<span class="kwrd">public</span> <span class="kwrd">void</span> TheFirstPropertyIsSet()
{
_result.ShouldHave().AllProperties().EqualTo(<span class="kwrd">new</span> { First = <span class="str">"Paula Bean"</span>, Second = <span class="str">"Brillant!"</span> });
}</pre>
<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>ShouldHave().AllProperties() does all the hard work of checking the properties. You can also use SharedProperties() if you only need to test a subset of the properties, and add IncludeNestedObjects if you have a more complex object model.</p>
<p>P.S. I love the story of <a href="http://thedailywtf.com/Articles/The_Brillant_Paula_Bean.aspx">the Brillant Paula Bean</a>. It confirms all your prejudices about contractors.</p> David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com0tag:blogger.com,1999:blog-30748878.post-21693863453223619362012-01-11T14:22:00.001+11:002012-01-11T15:33:01.507+11:00Adobe Lightroom 4 Beta is out!<p><a href="http://lh6.ggpht.com/-Sm3k4a-bAsM/Tw0Q0r9amMI/AAAAAAAAAaQ/_3rC5PmLrUQ/s1600-h/images%25255B6%25255D.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px 10px 5px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top: 0px; border-right: 0px; padding-top: 0px" title="Adobe Lightroom 4" border="0" alt="Adobe Lightroom 4" align="left" src="http://lh4.ggpht.com/-jJ0jwkJQp0o/Tw0Q1sR4ZoI/AAAAAAAAAaY/0tUPLmqTvCU/images_thumb%25255B2%25255D.jpg?imgmax=800" width="122" height="122" /></a>I’m <a href="http://lightroomkillertips.com/2012/lightroom-4-beta-is-here/">looking forward to this</a>. I’ve been a user of Lightroom since it first came out as version one, and it’s been indispensible for managing my growing photo collection (I passed the 10000 mark last year). </p> <p>I’m particularly excited by the long-awaited introduction of proper geocoding support. I bought a GPS logger a year or two ago, and use Dirk Stichling’s <a href="http://itunes.apple.com/au/app/mytracks/id403100976?mt=12">My Tracks</a> to add geotag my photos prior to importing them into Lightroom. When I export from Lightroom to iPhoto, the geotags are picked up and displayed nicely in the Places section of iPhoto (and on the iPhone and iPad). However, this only works when importing photos – existing photos cannot be geotagged. Jeffrey Friedl has written <a href="http://regex.info/blog/lightroom-goodies/gps">a plugin for Lightroom</a> that achieves this, after a fashion, but I prefer my metadata to reside within embedded metadata, rather than in shadow files which are then written on export; and although My Tracks is a good application, I would prefer to have fewer steps in the overall process.</p> <p>Of course, the ideal would be for Canon to release an accessory that geotags photos when they are taken, but for the moment, they seem to be preferring to take the third-party route.</p> David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com0tag:blogger.com,1999:blog-30748878.post-57846233009116385302012-01-06T11:33:00.003+11:002012-01-17T13:25:47.582+11:00New Year, New Resolutions<p><span>よいお年をお迎えください。</span></p> <p>In other words, happy new year! </p> <p>As far as making and keeping new resolutions go, I’d already failed miserably by January 2nd, probably setting a new low. The resolution was to take a photograph everyday and upload it to Flickr/Facebook, but that just didn’t happen. In fact, I haven’t picked up my camera for a week or two, and only used the camera in my phone to play around with <a href="http://photosynth.net/">Photosynth</a>, which looks completely out of place on an iPhone, having been built for a Windows-based phone with no effort made to translate the UI design, but nevertheless, works very well.</p> <p>However, the new year does afford me the chance to indulge in some spring cleaning, even if we are in the early throes of summer here in the Lucky Country. In particular, now that I am back at work, it means opening up the computer case, and having some fun with a rather large air compressor to remove all the dust that has accumulated since the PC was assembled. It also means that I can finally give it a good formatting and install everything afresh, something which every PC user should do at least annually.</p> <p><a href="http://lh5.ggpht.com/-XCzowU2YjAM/TwZBSngcj3I/AAAAAAAAAaA/KP7lHPc-3S0/s1600-h/cleanallthethings-550x4122.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 10px 0px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Clean ALL the things!" border="0" alt="Clean ALL the things!" align="left" src="http://lh6.ggpht.com/-S1LOJvFHZaI/TwZBThX97mI/AAAAAAAAAaI/bKMZ20Ya5vI/cleanallthethings-550x412_thumb.png?imgmax=800" width="244" height="184" /></a>This of course reminds me just how many applications I have downloaded and installed in the past year. Just installing Windows 7 with all the layers upon layers of patches takes about half a day, and our internet connection at work feels much slower than my home internet connection. </p> <p>To give you an idea of just how much stuff your typical Windows developer needs to make it through the day, here’s an approximate list. So far it’s taken me a whole day to download and install this lot, and I’m still finding those useful little apps that you forget aren’t included out-of-the-box.</p> <h4>System</h4> <ul> <li><a href="http://www.7-zip.org/">7-Zip</a> – beats WinZip for compression any day; </li> <li><a href="http://www.dropbox.com/">DropBox</a> – file synchronisation across almost any device; </li> <li><a href="https://www.google.com/chrome">Google Chrome</a> – the choice of most developers; </li> <li><a href="http://www.mozilla.org/en-US/firefox/new/">Mozilla Firefox</a> – the chose of most other developers; </li> <li><a href="http://www.skype.com/">Skype</a> – for keeping in touch with our other offices around the world; </li> <li><a href="http://www.slysoft.com/en/virtual-clonedrive.html">Virtual CloneDrive</a> – for mounting all those application installation ISOs; </li> <li><a href="http://explore.live.com/windows-live-essentials">Windows Live Essentials</a> – Mail, Messenger, and of course, Writer (which no self-respecting blogger should be without – definitely one of the most useful products to come out of Redmond); </li> </ul> <h3>Business Applications</h3> <ul> <li><a href="http://office.microsoft.com/en-au/?CTT=97">Microsoft Office</a> – of course; </li> <li><a href="http://office.microsoft.com/en-au/visio/">Microsoft Visio</a> – when a diagram is worth a thousand words; </li> <li><a href="http://www.getpaint.net/">Paint.NET</a> – this should be in the base Windows installation; </li> </ul> <h3>Developer Tools</h3> <ul> <li><a href="http://www.scootersoftware.com/">Beyond Compare</a> – the best diff tool that I’ve tried (<a href="http://winmerge.org/">WinMerge</a> is free and also very good, but I just prefer BC); </li> <li><a href="http://www.cruisecontrolnet.org/projects/ccnet/wiki">CruiseControl.NET</a> – nothing inspires confidence in your day’s work like a row of green lights confirming that it compiles, the tests ran successfully, and the installation package is ready to be shipped; </li> <li><a href="http://www.fiddler2.com/fiddler2/">Fiddler</a> – if you have to send data across the network, you need this tool; </li> <li><a href="http://notepad-plus-plus.org/">Notepad++</a> – syntax highlighting for almost every language out there, and tabbed windows too; </li> <li><a href="http://smtp4dev.codeplex.com/">Smtp4Dev</a> - for testing the sending of emails; </li> <li><a href="http://blogs.msdn.com/b/sqlservercompact/archive/2011/01/12/microsoft-sql-server-compact-4-0-is-available-for-download.aspx">SQL Server Compact</a> – for when the application you are developing will not need a full-blown database server; </li> <li><a href="http://www.microsoft.com/sqlserver/en/us/editions/express.aspx">SQL Server Express</a> – for when application you are developing will need a full-blown database server; <ul><!--EndFragment--></ul> </li> <li>Subversion (<a href="http://www.collab.net/downloads/subversion/">command-line</a>, <a href="http://tortoisesvn.tigris.org/">GUI</a>, and <a href="http://ankhsvn.open.collab.net/">IDE</a> integration) – who wants to be a tightrope walker without a safety net? </li> <li><a href="http://www.microsoft.com/visualstudio/">Visual Studio</a> – where I spend 95% of my time: <ul> <li><a href="http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=1491">ASP.NET MVC3</a> - the way to go for building web apps;</li> <li><a href="http://visualstudiogallery.msdn.microsoft.com/7211bcac-091b-4a32-be2d-e797be0db210">CSS Intellisense Schema</a> – syntax highlighting for and Intellisense for CSS3; </li> <li><a href="http://visualstudiogallery.msdn.microsoft.com/46a20578-f0d5-4b1e-b55d-f001a6345748">GhostDoc</a> – generate XML comments for methods based on name and parameters; </li> <li><a href="http://visualstudiogallery.msdn.microsoft.com/27077b70-9dad-4c64-adcf-c7cf6bc9970c">NuGet</a> – essential for adding third-party libraries; </li> <li><a href="http://visualstudiogallery.msdn.microsoft.com/d0d33361-18e2-46c0-8ff2-4adea1e34fef">Productivity Power Tools</a> – the bits Microsoft forgot; </li> <li><a href="http://www.jetbrains.com/resharper/">Resharper</a> – makes refactoring and code maintenance much more bearable; </li> <li><a href="http://visualstudiogallery.msdn.microsoft.com/0e313dfd-be80-4afb-b5e9-6e74d369f7a1">SQL Server Compact Toolbox</a> – for working with SQL Server Compact; </li> <li><a href="http://stylecop.codeplex.com/">StyleCop</a> – because well-presented code is much more readable and maintainable; </li> <li><a href="http://www.devexpress.com/">DevExpress</a> – our main third-party toolset; </li> </ul> </li> <li><a href="http://www.microsoft.com/download/en/details.aspx?id=8279">Windows 7 SDK</a> – essential developer tools;</li> <li><a href="http://www.silverlight.net/">Silverlight</a> – for rich web client development;</li> <li><a href="http://silverlight.codeplex.com/">Silverlight Toolkit</a> – the bits that Microsoft forgot in Silverlight</li> <li><a href="http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=3062">Expression Blend SDK</a> – another set of bits that Microsoft forgot in Silverlight</li> </ul> David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com0tag:blogger.com,1999:blog-30748878.post-8691591244211216882011-03-25T16:43:00.003+11:002012-01-06T11:52:05.256+11:00A craftsman knows his tools<p>Those who have worked with me for any length of time will know that I’m always looking for ways to improve my ability as a programmer. It may be in researching the latest available tool libraries (my current new favourite is <a href="http://storyq.codeplex.com/">StoryQ</a>, which is great for developing <a href="http://dannorth.net/introducing-bdd/">BDD-style tests</a>, and <a href="http://nsubstitute.github.com/">NSubstitute</a>, which is as easy to use as <a href="http://code.google.com/p/moq/">Moq</a>, but without those annoying calls to <code>.Object</code>), or how to write better, more reliable, build scripts. Either way, learning new skills and refining existing skills is an essential part of any craft (I’m deliberately steering clear of the ongoing <a href="http://www.thoughtclusters.com/2009/07/the-problem-with-the-software-craftsmanship-concept/">“software development isn’t a craft”</a>/<a href="http://www.skorks.com/2009/07/in-defense-of-the-software-craftsmanship-concept/">“oh yes it is</a><a href="http://www.skorks.com/2009/07/in-defense-of-the-software-craftsmanship-concept/">”</a> argument – this still applies to trades and scientific disciplines).</p> <p>This week I have been focusing on knowing my tools, and being a developer who works with Microsoft technologies, those tools inevitably centre around <a href="http://www.microsoft.com/visualstudio/en-us/">Visual Studio</a>. One way to increase your productivity is to reduce the time you spend doing pointless activities, or rather, when faced with two ways of achieving something, to choose the quicker way. The most obvious form for a programmer is to learn to let go of the mouse; a little strange maybe, especially in an operating system that defines itself around the use of the mouse, but it really does act as a great big brake on your productivity. When I first started playing guitar, it would take me several seconds to visualise the necessary finger patterns in my head, and then position my fingers on the fret board. Now after much practising, I can see an F# minor chord written down and play it without having to even think about it.</p> <p>The first step was to <a href="http://www.secretgeek.net/vs_toolbar_st.asp">get rid of all the toolbars and icons</a>. If there are no icons on screen, there’s not much point using the mouse to click them! The commands are still all there, and they can be accessed via the menu bar if I get really stuck. As a bonus, suddenly I have much more viewable area to concentrate on what really matters – the code.</p> <p>So my first shortcut to learn was how to stop a debug session. I knew F5 to launch the debugger, but I always clicked on the Stop icon to stop it; well, it turns out that Shift-F5 was my new best friend. So far, so easy, and not too much time saved. </p><p>The next useful one was the Surround-with snippet; this is part of the excellent <a href="http://www.jetbrains.com/resharper/">Resharper</a> which really takes the heavy lifting out of Windows programming). I was working with code which was throwing exceptions, and there was no exception handler. Before, I would have used the mouse to click just above the offending line of code, then typed in the standard try/catch blocks, then selected the offending line of code and cut’n’paste it into the try {} block, then clicked into the catch {} and add the exception handling. That’s a lot of pointless mouse and keyboard work. Now, using the keyboard, I would select the line of text (Shift-End to select to the end of the line), then Ctrl-K,S to bring up the Surround-with snippets, then type try and press Enter to surround my code with a try/catch block and automatically position the cursor in the catch {} block ready to select my exception type. Intellisense camel-case matching helped, so I only had to type in CE to match the ConstraintException I was trying to catch, hit Enter, and job done.</p><p>There are only so many hours in the day - reclaim yours by learning how to use the tools you have to get more done in less time.</p>David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com0tag:blogger.com,1999:blog-30748878.post-11838427118708493052011-03-24T08:39:00.001+11:002011-03-24T08:39:59.510+11:00Synchronicity Part 2<p>Last year, it was <a href="http://davidkeaveny.blogspot.com/2010/05/synchronicity.html">Flash crashing Safari</a> while I was trying to read an article about the problems with Flash. This time, it’s <a href="http://www.google.com/chrome">Google Chrome</a> crashing while I’m trying to read about why the <a href="http://blog.mozilla.com/blog/2011/03/22/mozilla-launches-firefox-4-and-delivers-a-fast-sleek-and-customizable-browsing-experience-to-more-than-400-million-users-worldwide-2/">newly-released Firefox 4</a> is the new hotness.</p> <p><a href="http://lh3.ggpht.com/_lMyetu2DK1E/TYpoq_1dwqI/AAAAAAAAAZ4/bkp5FednOOE/s1600-h/image%5B3%5D.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_lMyetu2DK1E/TYporqXNZJI/AAAAAAAAAZ8/UOpCmAyQZGY/image_thumb%5B1%5D.png?imgmax=800" width="414" height="209" /></a></p> <p>Coincidence or conspiracy?</p> David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com0tag:blogger.com,1999:blog-30748878.post-76790099786240188162011-03-22T13:51:00.001+11:002011-03-22T13:51:45.045+11:00Unity and log4net<p>In my current project at <a href="http://www.touchstar.com.au">TouchStar</a>, I’ve had the opportunity to play with <a href="http://unity.codeplex.com/">Unity</a>, Microsoft’s Inversion-of-Control container. Previously I’ve used <a href="http://structuremap.net/structuremap/">StructureMap</a>, which is very popular, but I wanted to broaden my experience of different containers, and given that my project involved a WPF client, Unity seemed to be a good choice.</p> <p>One of the first problems was how to configure <a href="http://logging.apache.org/log4net/">log4net</a> using Unity. Usually, log4net is called from within a class thusly:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> MyClassWithLogger()</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> private <span style="color: #0000ff">static</span> readonly ILog Logger = LogManager.GetLogger(typeof(this));</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span>  </pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> <span style="color: #0000ff">public</span> void DoAction()</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> Logger.Debug("Hello world");</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> DoSomeOtherAction();</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> }</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span>  </pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> private void DoSomeOtherAction()</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13"> 13:</span> Logger.Debug("Still here");</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum14"> 14:</span> }</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum15"> 15:</span> }</pre>
<!--CRLF--></div>
</div>
<p>Which, depending on how you’ve configured your appenders, would produce an output something like this:</p>
<div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
<div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> MyClassWithLogger [DEBUG] - Hello world</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> MyClassWithLogger [DEBUG] - Still here</pre>
<!--CRLF--></div>
</div>
<p>So far, so vanilla, and the sort of code that anyone whose used log4net will have written thousands of times; but what happens if we want to apply good <a href="http://www.lostechies.com/blogs/chad_myers/archive/2008/03/07/pablo-s-topic-of-the-month-march-solid-principles.aspx">SOLID design principles</a> and inject the log4net dependency into the class, rather than have the class create the instance itself. I prefer constructor injection for this, as it makes it very explicit what the dependencies are, and you can’t accidentally forget to set one without getting a compile-time error. The class would then become:</p>
<div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
<div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> MyClassWithLoggerDependency()</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">readonly</span> ILog Logger;</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span>  </pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> <span style="color: #0000ff">public</span> MyClassWithLoggerDependency(ILog logger)</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> Logger = logger;</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> }</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span>  </pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> DoAction()</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> Logger.Debug(<span style="color: #006080">"Hello world"</span>);</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13"> 13:</span> DoSomeOtherAction();</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum14"> 14:</span> }</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum15"> 15:</span>  </pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum16"> 16:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> DoSomeOtherAction()</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum17"> 17:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum18"> 18:</span> Logger.Debug(<span style="color: #006080">"Still here"</span>);</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum19"> 19:</span> }</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum20"> 20:</span> }</pre>
<!--CRLF--></div>
</div>
<p>We’re now ready to apply some IoC magic with Unity to create the instance of ILog that our class will use. Since log4net uses its own factory class to instantiate itself, we have to jump through a hoop or two to get Unity to set things up properly:</p>
<div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
<div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> Program</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> Main(<span style="color: #0000ff">string</span>[] args)</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> var container = <span style="color: #0000ff">new</span> UnityContainer()</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> .Register<ILog>(<span style="color: #0000ff">new</span> InjectionFactory(x => LogManager.GetLogger(<span style="color: #0000ff">typeof</span>(<span style="color: #0000ff">this</span>))));</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> .Register<MyClassWithLoggerDependency>()</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span>  </pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> var myClass = <span style="color: #0000ff">new</span> container.Resolve<MyClassWithLoggerDependency>();</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> myClass.DoStuff();</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> }</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> }</pre>
<!--CRLF--></div>
</div>
<p>Which produces an output like this:</p>
<div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
<div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> Program [DEBUG] - Hello world</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> Program [DEBUG] - Still here</pre>
<!--CRLF--></div>
</div>
<p>See the problem? Now the logger is using the context of the code where Unity was configured to log from, rather than the context that the logger is being called from. I’ve seen plenty of questions asked about this, but it was only today that I stumbled upon <a href="http://unity.codeplex.com/discussions/203744">the answer to this problem</a>, hidden in a discussion on the Unity forums. A developer named <a href="http://www.codeplex.com/site/users/view/marcoerni">Marco</a> posted his solution, which was to create two extensions – the first being a BuildTracking extension, and the second being a LogCreation extension. The build tracking extension keeps tabs on what types are being built up, and then calls out to the log creation extension to create the logger component in the context of the class which is asking for it. Another developer, <a href="http://www.codeplex.com/site/users/view/ThunderEagle">Scott</a>, then posted his amendments that took care of some breaking API changes from the earlier version of Unity that Marco was using, together with an enhancement to improve detection of the calling class name when log4net is not being used with dependency injection.</p>
<p>My small contribution to the discussion was to provide the actual implementation code, which is as follows:</p>
<div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
<div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> Program</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> Main(<span style="color: #0000ff">string</span>[] args)</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> {</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> var container = <span style="color: #0000ff">new</span> UnityContainer()</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> .AddNewExtension<BuildTracking>()</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> .AddNewExtension<LogCreation>()</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> .Register<MyClassWithLoggerDependency>()</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span>  </pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> var myClass = <span style="color: #0000ff">new</span> container.Resolve<MyClassWithLoggerDependency>();</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> myClass.DoStuff();</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> }</pre>
<!--CRLF-->
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13"> 13:</span> }</pre>
<!--CRLF--></div>
</div>
Now that in my eyes is a much tidier piece of code. Gone is the explicit registration of the ILog type with its rather ungainly use of the InjectionFactory to create the appropriate implementation, and instead we have the two new extensions registered.
<p>This is a great little bit of code, and big thanks go to Marco and Scott for sharing their contributions with us. I’m sure that many other developers will find this useful.</p> David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com8tag:blogger.com,1999:blog-30748878.post-61959547578808512922011-03-21T13:17:00.002+11:002011-03-21T13:34:34.737+11:00Watching Ideas Take Flight<p>In my last entry, I mentioned <a href="http://davidkeaveny.blogspot.com/2011/03/publishing-net-applications.html">an idea I’d had before</a> on how to make it easier to package .NET applications when run as part of an automated build. It solved a problem for me, and I thought it worth sharing, firstly as an <em>aide mémoire</em> for myself, and secondly because it seems the sort of thing that other people would find useful.</p> <p><a href="http://ferventcoder.com/">Rob Reynolds</a> came across my post, and he obviously found it useful. In fact, he liked it so much that he has put together a <a href="http://www.nuget.org/List/Packages/PublishedApplications">NuGet package</a> to make the set-up of _PublishedApplications even easier, together with a demo of how easy it is to use.</p> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:22542ece-6bdb-4347-9c9b-ed5b9451b16f" class="wlWriterEditableSmartContent"><div id="41f61892-757c-4cb3-82a9-5498f59e6f60" style="margin: 0px; padding: 0px; display: inline;"><div><object width="448" height="252"><param name="movie" value="http://www.youtube.com/v/-oPtsb11vBU?hl=en&hd=1"></param><embed src="http://www.youtube.com/v/-oPtsb11vBU?hl=en&hd=1" type="application/x-shockwave-flash" width="448" height="252"></embed></object></div></div><div style="width:448px;clear:both;font-size:.8em">Demo of _PublishedApplications at work</div></div> <p>I’m thrilled to see this getting out there – a big thanks to Rob for really getting this off the ground, as well as giving it more exposure.</p>David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com1tag:blogger.com,1999:blog-30748878.post-28314650478142619092011-03-10T11:22:00.001+11:002011-03-10T11:22:27.028+11:00Publishing .NET Applications<p>This is a problem I came across in my previous job at <a href="www.fairfaxdigital.com.au">Fairfax Digital</a>, when setting up automated builds; now that I am working at <a href="www.touchstar.com.au">TouchStar</a>, I’m facing the same problem, but couldn’t remember what I did the first time round.</p> <p>The problem is this: when building ASP.NET web applications using TFS or some other continuous integration solution (I’m using <a href="http://code.google.com/p/uppercut/">UppercuT</a> at TouchStar), the <a href="http://msdn.microsoft.com/en-us/library/wea2sca5(v=vs.90).aspx">MSBuild</a> engine very conveniently creates a _PublishedWebsites folder in your output folder, and then creates a subfolder in that folder for each website that you are creating. So far, so good. However, when building executable applications, such as console apps, WPF applications or Windows services (and I’m building all three at TouchStar) then it just throws everything into one directory, and leaves it to you to pick out the bits you need. “If only you could export your build results to a _PublishedApplications folder!”, I hear you cry.</p> <p>Well, that’s essentially my solution. I took a copy of the <code>Microsoft.WebApplication.targets</code> file that is referenced in the ASP.NET project file, renamed it to <code>Microsoft.Application.targets</code> and saved it to <code>C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Applications</code>. I then tweaked it, renaming variables and such to match the type of content, and removing any references to /bin folders. I then reference the new file in the Visual Studio project file by adding the following line:</p> <pre>  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\Applications\Microsoft.Application.targets" /></pre>
<p>And voila! I now have one folder per application in the _PublishedApplications folder when run as part of an automated build. If I build from within Visual Studio, outputs are still sent to their usual location (e.g. <code>/bin/Debug/</code>). I’ve included a link to the file below.</p>
<p>[<a href="https://docs.google.com/leaf?id=0BzmthFqo65VlMmZkNWNlNDYtM2RhMi00MjdhLTk1ZTYtMmFkODQ1ZGJlNzAx&hl=en">Download Microsoft.Application.targets</a>]</p> David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com4tag:blogger.com,1999:blog-30748878.post-88854521434846323552010-08-12T09:06:00.001+10:002010-08-12T09:06:41.339+10:00Mixing TFS 2008 and VS 2010<p>At work, we’re in the early phases of migrating our TFS 2008 setup to TFS 2010. However, since some teams have already started work on the new hotness that is VS 2010 and .NET 4, there was a need for us to get their automated builds up and running immediately. We “requisitioned” a desktop that was already running builds for another semi-defunct project using CruiseControl.NET, and installed Team Build on it.</p> <p>It took a few tweaks to get the code compiling, but something was wrong with the testing phase – the tests would run, but the test runner would then report a failure, resulting in a yellow warning lights rather than nice green success lights. The error message was:</p> <pre><p>MSBUILD : warning MSB6003: The specified task executable "MSTest.exe" could not be run. The system cannot find the file specified [D:\Source\CommonPlatform\Common Platform Development CI Build\BuildType\TFSBuild.proj]</p><p>
</p></pre>
<p>So the tests all passed, but then Team Build couldn’t find the testrunner that it had just used! We tracked down another user with the same complaint on <a href="http://stackoverflow.com/questions/3353414/build-vs2010-solution-on-team-build-2008-mstest-failed-to-run/" target="_blank">StackOverflow</a>, but they were shouting in the dark, with no response to their question. </p>
<p>After much head-scratching alternated with banging our heads against the wall and wondering why Microsoft products are sometimes to great and sometimes so plain awful (often in the space of just five minutes), we eventually found the solution to our problem tucked away <a href="http://social.msdn.microsoft.com/forums/en-US/tfsbuild/thread/950929ca-7996-4a13-a1ab-76a72cc4bf1f" target="_blank">in forum on MSDN</a>. The TeamBuild targets file which imports the TestToolsTask has an invalid path reference:</p>
<pre><UsingTask TaskName="TestToolsTask" AssemblyFile="$(MSTestRefPath)\Microsoft.VisualStudio.QualityTools.MSBuildTasks.dll"
Condition="'$(ProjectFileVersion)' == '2'" /></pre>
<p>since <code>MSTestRefPath</code> doesn’t appear to be defined in VS 2010. By changing it to the correct path, the test runner can be found again, and the error disappeared.</p>
<p>Quite why Microsoft implemented it so that the tests would run but then fail afterwards I don’t know, but at least our builds are all happy, and the developers are happy. Hopefully we can now get back to migrating TFS 2008 to 2010, and we can see the back of this problem.</p> David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com2tag:blogger.com,1999:blog-30748878.post-38280126230287566452010-05-12T14:51:00.001+10:002010-05-12T14:51:10.058+10:00Synchronicity<p>Apple and Adobe seem to be having a bit of a dummy spit over Flash at the moment, which is polarising the developer community. Well, I opened up Google Reader to read Richard Banks’s <a href="http://richardsbraindump.blogspot.com/2010/05/life-without-flash-acrobat-air-and.html" target="_blank">latest thoughts on the subject</a>, and as I do that, bam! Safari crashes with a Flash error.</p> <p><a href="http://lh5.ggpht.com/_lMyetu2DK1E/S-ozudptu5I/AAAAAAAAAYg/E5fxxLfsd6Q/s1600-h/Flash%20Irony%5B5%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Flash Irony" border="0" alt="Flash Irony" src="http://lh3.ggpht.com/_lMyetu2DK1E/S-ozvPGMo7I/AAAAAAAAAYk/aNYsR94sX7E/Flash%20Irony_thumb%5B6%5D.png?imgmax=800" width="433" height="296" /></a></p> <p>(the Flash app was running in a different tab, not as part of Google Reader).</p> David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com0tag:blogger.com,1999:blog-30748878.post-6135684591884254492010-05-05T09:37:00.001+10:002010-05-05T09:37:24.823+10:00Baseless suggestion<p>I’ve been spending the past few days cleaning up a messy situation at work, where one of our source control branches in TFS 2008 has not been properly merged back into trunk for several months. In trying to tidy things up, I kept getting the following error:</p> <p><font size="1" face="Courier New">TF14087: Cannot undelete '$/MyCareer/Trunk/build/NightlyBuild/TFSBuild.rsp' because not all of the deletion is being undeleted.</font></p> <p>The problem was that the folder NightlyBuild had been renamed in both the source and destination branch, but there was still a reference to it in this old changeset. Using <em>tf merge /discard</em> reported that there were no changes to make, which left me stuck for a bit, until one quick application of <a href="http://www.urbandictionary.com/define.php?term=google-fu" target="_blank">Google-fu</a>, and I found <a href="http://social.msdn.microsoft.com/Forums/en-US/tfsversioncontrol/thread/2f6faa6d-1c2b-408f-8ff4-6d5183b7409b" target="_blank">the solution to my problem</a>. By performing a baseless merge, the offending file is accepted:</p> <p><font size="1" face="Courier New">tf merge /discard /baseless /version:C13494~C13494 $/MyCareer/Branches/Maintenance $/MyCareer <br />/Trunk /recursive <br />Resolved D:\Source\MyCareer\Trunk\build\DailyBuild\TFSBuild.rsp as AcceptYours</font></p> <p>Hope that helps!</p> David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com0tag:blogger.com,1999:blog-30748878.post-3571036606875615152010-02-25T12:24:00.001+11:002010-02-25T12:24:22.189+11:00Lightroom and CS3<p>I recently upgraded my camera from an ageing <a href="http://www.usa.canon.com/consumer/controller?act=ModelInfoAct&fcategoryid=139&modelid=12929" target="_blank">Canon EOS 30D</a> to the newly-released <a href="http://www.canon.com.au/en-AU/For-You/Digital-Cameras/EOS-Digital-SLR-Cameras/7D" target="_blank">EOS 7D</a>. Jumping from 8 megapixels to 18, and adding HD video recording, as well as niceties such as Auto ISO, are real plusses for me.</p> <p>However, I soon found an annoying problem: I use Adobe Lightroom 2 to manage my rapidly-growing photo collection (just a handful shy of 10000 now) and Adobe Photoshop CS3 to do clever stuff like panorama stitching. However, CS3 doesn’t recognise the RAW format that Canon uses in the 7D, although Lightroom 2 does, so I can’t load photos taken with the 7D in Photoshop. Bummer.</p> <p>Adobe’s ideal solution is that I upgrade to Photoshop CS4, which will be several hundred dollars. However, the solution I came across was to use Adobe’s own tools to work around the limitation. Lightroom can convert RAW images to its preferred DNG format, and that format <strong>can</strong> be opened in CS3. Usually I convert my RAW images to DNG as the last step in my development process, but this is a neat little workaround, saving me a big chunk of cash at the same time.</p> David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com0tag:blogger.com,1999:blog-30748878.post-30049685662069815032009-11-05T11:44:00.001+11:002009-11-05T11:44:26.001+11:00Working with bugs<p><a title="A Swallow Bug" href="http://www.ext.colostate.edu/PUBS/INSECT/insimg/Swallow%20Bug.%20%20Photograph%20courtesy%20Ken%20Gray%20Collection.jpg" target="_blank"><img style="margin: 0px 10px 0px 0px; display: inline" align="left" src="http://www.ext.colostate.edu/PUBS/INSECT/insimg/Swallow Bug. Photograph courtesy Ken Gray Collection.jpg" width="240" height="169" /></a> No, this is not a post on <a href="http://en.wikipedia.org/wiki/Entomology">entymology</a>; rather, it’s a bit of a lament on the lost art of filing bug reports. Though they may bestride the programming world like a colossus, even the best programmers will eventually leave bugs in their code. Sooner or later, some poor user will fall foul of it.</p> <p>You then have a number of solutions, depending on where the product came from. For a commercial product, you can:</p> <ol> <li>ignore it and hope it goes away; </li> <li>file a bug report, and hope that the provider will fix it; </li> <li>find some sort of workaround, or just learn to live with it; </li> <li>vote with your wallet, and switch to a competitor’s product </li> </ol> <p>For an open-source product,, you have an extra option:</p> <ol start="start"> <li>download the source code, and fix it yourself, and preferably submitting your fix back to the community. </li> </ol> <p>In my case, it was a bug in a Microsoft development tool, the succinctly named <a href="http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=bb3ad767-5f69-4db9-b1c9-8f55759846ed">Microsoft Visual Studio Team System 2008 Database Edition GDR R2</a>. As an aside, let me say that I’ve been using it for all of 2 days, and I absolutely love its functionality. It finally makes versioning and deploying databases a delight rather than a painful chore. There is now no excuse for organisations not to have their databases under version control, or for having painful manual deployment processes.</p> <p>Anyway, it has a bug in it which is holding up a particular project at work. I searched for a solution, and found someone who had reported <a href="https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=449762">the same issue</a> some 9 months ago. Unfortunately the bug report that they filed was so lacking of information that Microsoft promptly closed the bug as Not Reproducible. In fact, it’s not 100% certain that the bug relates to my issue because it is so light on details – it just reports the same error message.</p> <p>As it happens, the steps required to reproduce the bug were incredibly trivial, so I <a href="https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=508336#details">opened a new bug</a>, and gave the sort of details that a developer trying to fix a bug needs to see – in other words, I described what I was doing, what I expected to see happening, and what actually was happening. More to the point, I list the steps that the developer should take to make the same thing happen for them.</p> <p>The first step to being able to resolve a bug is to be able to reproduce it. If you can’t reproduce it, how can you work out what is going wrong, and how can you prove that you’ve fixed the bug? And if the bug reporter doesn’t tell you how to reproduce the bug, what chance do you have of being able to fix it?</p> <p>So please – if you want your bug to be fixed, consider the poor developer who has to fix it, and tell them what they need to know to get the job done. Anything less, and you’ll have a 9 month wait before someone else with the same problem files the same issue again.</p> David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com0tag:blogger.com,1999:blog-30748878.post-13375440076290535412009-09-23T06:39:00.003+10:002009-11-04T01:05:10.766+11:00Weird Sydney morning weatherThe joys of parenthood include many early mornings. This is what awaited me this morning when Samuel woke us up. Most freaky!
<a href="http://www.flickr.com/photos/davidkeaveny/3944995523/" title="photo sharing"><img src="http://farm3.static.flickr.com/2535/3944995523_cccb2bd988_m.jpg" alt="" style="border: 2px solid rgb(0, 0, 0); width: 401px; height: 271px;" /></a>
Any ideas what's causing this?<div>
</div><div><b>Update</b> : apparently it's a dust storm. Western Australia is missing several hundred tonnes of dust and topsoil.</div>David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com0tag:blogger.com,1999:blog-30748878.post-5468434139620600302009-06-29T23:38:00.003+10:002009-06-29T23:43:48.368+10:00iPhone on 3When the iPhone 3G was originally released in Australia, I and many others complained that 3, who provide some of the best 3G data plans in the country, did not sell it. There were <a href="http://davidkeaveny.blogspot.com/2008/08/getting-iphone-in-australia-with-3.html">ways around it</a>,which kind of suggest that it was a problem at Apple's end rather than 3's, but it seems that with the release of the updated iPhone 3GS, users of the 3 network are finally <a href="http://store.three.com.au/Apple-iPhone-3G-Coming-Soon">getting some Apple love</a>.
And of course, it's at this point that I notice that my elderly Nokia N95 8Gb is finally fully supported by OS X, including syncing from iTunes and iPhoto. Now where was that a year ago when I really needed it?
Never mind; just as soon as I can sell a kidney on Ebay, I'll have his'n'hers iPhone 3GS's, and the Nokia can go in the phone recycling bin.David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com1tag:blogger.com,1999:blog-30748878.post-81185156894655855992009-05-20T10:44:00.002+10:002009-05-21T08:01:35.123+10:00SvnRevisionLabeller makes its v2 release<p>Recently Thoughtworks started to make available <a href="http://confluence.public.thoughtworks.org/display/CCNET/2009/05/10/CruiseControl.NET+1.4.4+RC2+Released" target="_blank">release candidates for version 1.4.4</a> of CruiseControl.NET. Tucked away inside there though are some changes to some of the core components, that break compatibility with <a href="http://code.google.com/p/svnrevisionlabeller/" target="_blank">SvnRevisionLabeller</a>.</p> <p>This gave me the proper motivation to find some time to finish off the packaging of a fairly major change to the way the labeller constructs build labels. The <a href="http://code.google.com/p/svnrevisionlabeller/issues/detail?id=3&can=1" target="_blank">real work</a> was actually done by another developer, <a href="http://code.google.com/u/fezguy/" target="_blank">fezguy</a> - I just had to integrate his patch, tweak it to the way I like things (hey, it is my project after all!), and finally start work on some automated tests. I like automated tests. </p> <p>Since the two changes combined do break backwards compatibility, it's good to take a step back and see where we are now.</p> <p>Before, SvnRevisionLabeller was quite opinionated about how it thought build labels should be structured. With version 1.1, it was <em>{major}.{minor}.{svnRevision}.{build}</em> - <em>{build}</em> would start at 0, then if you forced another build without another commit having taken place, it would be incremented by one. A commit would then reset <em>{build}</em> back to 0, so you had a good idea how often the build was being forced. I later added the ability to specify prefix and suffix text for the label.</p> <p>Version 1.3 saw me rethink things a bit, with the label now defaulting to <em>{major}.{minor}.{build}.{svnRevision}</em>; now, successive forced builds made no difference to the label. What it did give me was that when I deployed a hotfix to production (usually designated by the incremented <em>{build}</em> number), I could tell immediately which Subversion revision it was built with.</p> <p>So it obviously works the way I wanted it to - but what about other people? Version 2.0 makes the label scheme very flexible - some tokens are defined, and you just position the tokens wherever you want them in a string pattern. So for instance, if I set my configuration thusly:</p><pre class="csharpcode"><span class="kwrd"><</span><span class="html">labeller type="svnRevisionLabeller"</span><span class="kwrd">></span>
<span class="kwrd"><</span><span class="html">major</span><span class="kwrd">></span>1<span class="kwrd"></</span><span class="html">major</span><span class="kwrd">></span>
<span class="kwrd"><</span><span class="html">minor</span><span class="kwrd">></span>4<span class="kwrd"></</span><span class="html">minor</span><span class="kwrd">></span>
<span class="kwrd"><</span><span class="html">build</span><span class="kwrd">></span>2<span class="kwrd"></</span><span class="html">build</span><span class="kwrd">></span>
<span class="kwrd"><</span><span class="html">pattern</span><span class="kwrd">></span>Release v{major}.{minor}.{build} from {revision}<span class="kwrd"></</span><span class="html">pattern</span><span class="kwrd">></span>
<span class="kwrd"></</span><span class="html">labeller</span><span class="kwrd">></span></pre>
<style type="text/css">.csharpcode, .csharpcode pre<br />{<br /> font-size: small;<br /> color: black;<br /> font-family: consolas, "Courier New", courier, monospace;<br /> background-color: #ffffff;<br /> /*white-space: pre;*/<br />}<br />.csharpcode pre { margin: 0em; }<br />.csharpcode .rem { color: #008000; }<br />.csharpcode .kwrd { color: #0000ff; }<br />.csharpcode .str { color: #006080; }<br />.csharpcode .op { color: #0000c0; }<br />.csharpcode .preproc { color: #cc6633; }<br />.csharpcode .asp { background-color: #ffff00; }<br />.csharpcode .html { color: #800000; }<br />.csharpcode .attr { color: #ff0000; }<br />.csharpcode .alt <br />{<br /> background-color: #f4f4f4;<br /> width: 100%;<br /> margin: 0em;<br />}<br />.csharpcode .lnum { color: #606060; }<br /></style><p>then when revision 42 is committed, the build label will become <em>Release v1.4.2 from 42</em>. At work, I use the <em>{build}</em> number to represent the sprint number since we began working on the <em>{minor}</em> release.</p><p>Finally, I noticed that my project was not the only one to be caught out by CC.NET's upgrade - Codeplex's <a href="http://ccnetplugins.codeplex.com/" target="_blank">CC.NET Community Plugins</a> are also broken by the change; unfortunately, they have a little more work to do, as it's not just a question of updating their external libraries and recompiling. I'm rather underwhelmed by the amount of activity on the site: I <a href="http://ccnetplugins.codeplex.com/WorkItem/View.aspx?WorkItemId=4324" target="_blank">raised an issue</a> earlier this month, and then submitted a patch to fix the issue, and it still hasn't been acknowledged yet, let alone added to the repository. For the time being, I won't be upgrading to v1.4.4 at work, since we need that library for our deployments.</p>David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com3tag:blogger.com,1999:blog-30748878.post-10851014403938209072009-04-14T07:41:00.001+10:002009-04-14T07:41:47.432+10:00An afternoon at Lake Parramatta<p>The Easter weekend was a good opportunity to get out of the house for a while and enjoy some of what Sydney has to offer. Several friends have recommended Lake Parramatta, a small dam and reservoir less than 10 minutes from our house, but we've never been there before. It was built in the late 19th century to provide drinking water for Parramatta, but these days it's a recreation area. It's sometimes swimmable, I think they're still working on the general cleanliness of the water (lots of stormwater drains etc empty into the catchment area).</p> <p><a title="The reservoir of Lake Parramatta" href="http://www.flickr.com/photos/84306903@N00/3437386819/"><img height="267" alt="The reservoir of Lake Parramatta" src="http://static.flickr.com/3540/3437386819_672ee877c8.jpg" width="400" border="0"></a></p> <p>There's plenty of parking etc at the entrance, barbecue areas, covered seating, even a playground for the little 'uns. It was quite busy considering sunset was less than an hour away, lots of families having picnics and so on.</p> <p><a title="The dam wall of Lake Parramatta" href="http://www.flickr.com/photos/84306903@N00/3438196724/"><img height="242" alt="The dam wall of Lake Parramatta" src="http://static.flickr.com/3336/3438196724_d9870ee23b.jpg" width="400" border="0"></a></p> <p>We took a brief walk round the easy part of the reservoir, down to the dam wall itself. There's a small creek at the base of the dam, with some pretty lush vegetation from the water that trickles down from the dam (although the picture above doesn't explicitly show it, the wall is constantly damp, as the water finds its way through and down).</p> <p><a title="Stepping stones" href="http://www.flickr.com/photos/84306903@N00/3438197046/"><img alt="Stepping stones" src="http://static.flickr.com/3629/3438197046_9efb9220a9.jpg" border="0"></a></p> <p>The creek at the bottom is crossed with a line of stepping stones. There's a lot of brown algae in the water, so it doesn't look very pleasant, but I think I got enough of an angle above so that it doesn't show. The full circuit around the reservoir is about 4.2km (I did say it was a little reservoir!), and although some of it is paved and flat, some of it requires a bit of a scramble. We'll have to save that for another time, because we got there not long before sunshot, and also because Emily is a bit too pregnant to be climbing anything at the moment.</p> David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com0tag:blogger.com,1999:blog-30748878.post-82479976798398705192009-03-31T18:04:00.001+11:002009-03-31T18:04:53.258+11:00MassTransit<p>Earlier this month, <a href="http://davidkeaveny.blogspot.com/2009/03/topshelf.html" target="_blank">I mentioned the MassTransit project</a>, an open-source .NET Enterprise Service Bus implementation, a topic sure to break the ice at a many a party.</p> <p>We've been getting stuck into MassTransit at work for a major project, and had all sorts of problems along the way, mainly due to the youth of the project and the general lack of documentation. Where there were code samples, sometimes the code just plain didn't work.</p> <p><a title="Restaurant tram" href="http://www.flickr.com/photos/84306903@N00/3176042157/"><img style="margin: 0px 10px 0px 0px" height="138" alt="Blog postings need images, apparently; so here's one that's distantly related to the topic under discussion - it's a restaurant tram in Melbourne" src="http://static.flickr.com/3125/3176042157_955a94bc69.jpg" width="240" align="left" border="0"></a>The two main developers, Dru and Chris, have been a fountain of knowledge and general helpfulness, responding quickly to my sometimes continuous barrage of questions, not helped of course by our being on opposite sides of the planet. I've been able to chip in with the occasional patch, nothing to fancy at this stage, but at least enough for me to feel like it's not a completely one-way street.</p> <p>Anyway, congratulations to MassTransit for <a href="http://blog.phatboyg.com/2009/03/30/masstransit-06-release-candidate/" target="_blank">shipping their v0.6 release candidate</a>. I've been running it for a few days now, although without using some of the cooler pieces of new technology, such as the saga state machines. Hopefully with their help, I'll be able to get our project back on track and heading in the right direction.</p> David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com0tag:blogger.com,1999:blog-30748878.post-71884425405357866242009-03-19T15:46:00.001+11:002009-03-19T15:46:12.404+11:00Topshelf<p>At work, I'm currently working on a project which requires the integration of several different systems, some of them hosted on the internet, and some on different sides of the corporate firewalls. This means that we can expect to lose connections between systems, which naturally pointed us in the direction of message queues, which are designed for such scenarios. A chat with a former colleague pointed me in the direction of enterprise service buses as the core technology to take care of all the plumbing; and after comparing feature sets with our requirements, I downloaded <a href="http://code.google.com/p/masstransit/" target="_blank">MassTransit</a>.</p> <p>What interested me was a spin-off from the MassTransit project, called <a href="http://code.google.com/p/topshelf/" target="_blank">Topshelf</a>, which has a single and simple aim - to get rid of all the cruft associated with actually launching .NET programs, especially all the boilerplate code you have to come up with to run services.</p> <p>I ran into a few issues though: the first was that before, I had been using the <a href="http://wix.sourceforge.net/" target="_blank">WiX</a>'s <a href="http://wix.sourceforge.net/manual-wix3/wix_xsd_serviceinstall.htm" target="_blank">ServiceInstall</a> code to handle all the service registration, such as setting the service name, description and credentials. However, Topshelf provides its own code to do that, and the two aren't compatible. In the end, the solution I came up with was to remove the WiX code and use Topshelf's, which would be invoked by a custom action in the WiX script:</p><pre class="csharpcode"><CustomAction Id=<span class="str">"InstallService"</span> FileKey=<span class="str">"ServiceExe"</span> ExeCommand=<span class="str">"/install"</span> />
<InstallExecuteSequence>
<Custom Action=<span class="str">"InstallService"</span> After=<span class="str">"InstallFinalize"</span> />
</InstallExecuteSequence></pre>
<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>FileKey is just a reference to the Id of the executable for the service, and ExeCommand contains the parameter(s) to pass to it.</p>
<p>All well and good, but unfortunately, Topshelf's implementation currently launches the same dialog box that installutil does, and if you're trying to produce an unattended install file, a dialog box is the last thing you want. I've had a little play around with the source code and came up with something which would technically work, but was nowhere near as elegant as the rest of the code, so I'm not planning on submitting it.</p>
<p>I did add a few refactorings and documentation into the codebase, nothing clever or anything; I then submitted the changes as a patch to Dru, and within the hour, they had been committed to trunk. This really reminds me why I love open-source programming so much - if the application doesn't do quite what you want it to do, you can download the source code and modify it, and if it works well, you can contribute that change back to the community. Talk about a win-win situation. Non-open source companies have to think about every way that people will use their software, and then program all that functionality in, thus proving the 80-20 rule - 80% of your users are only using 20% of your application's functionality. Did you know that Microsoft Word has a Japanese Greeting dialog box, which allows you to select a greeting specific to the month of the year?! I wonder even how many Japanese people know it exists?</p>
<p><a href="http://lh4.ggpht.com/_lMyetu2DK1E/ScHODj8UdYI/AAAAAAAAAUo/J1-eFIMhJ_c/s1600-h/JapaneseGreetings%5B9%5D.gif"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="333" alt="Japanese Greeting dialog box from Microsoft Word 2003" src="http://lh6.ggpht.com/_lMyetu2DK1E/ScHOElNqb_I/AAAAAAAAAUs/6ShX8UEkxTM/JapaneseGreetings_thumb%5B7%5D.gif?imgmax=800" width="424" border="0"></a></p>
<p>Speaking of contributing to open source, I've accepted a couple of patches to my <a href="http://code.google.com/p/svnrevisionlabeller/" target="_blank">SvnRevisionLabeller</a> project, and should be releasing a new build soon, once I've figured how to get some good tests in there. You are testing your software, right?!</p> David Keavenyhttp://www.blogger.com/profile/07944978161341604262noreply@blogger.com0