<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;D0EMSX4-fSp7ImA9WhBbGUU.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205</id><updated>2013-05-19T10:48:08.055-07:00</updated><category term="Resharper" /><category term="Super Mario 3D Land" /><category term="Visual Studio" /><category term="Windows 8" /><category term="MVC" /><category term="OAuth" /><category term="MVC4" /><category term="Cache" /><category term="Sci-Fi" /><category term="Dependency Injection" /><category term="Future Queries" /><category term="Analyzer" /><category term="Review" /><category term="Selenium" /><category term="Combres" /><category term="Timeout" /><category term="Lucene.Net" /><category term="StackTrace.js" /><category term="MSTest" /><category term="JavaScriptErrorReporter" /><category term="XNA" /><category term="WebDriver" /><category term="ASP.NET" /><category term="Configuration" /><category term="WebClient" /><category term="BlockingCollection" /><category term="String.Split" /><category term="Code Generation" /><category term="Games" /><category term="TDD" /><category term="Foobar" /><category term="Farscape" /><category term="EDD" /><category term="Chrome" /><category term="NES" /><category term="DosBox Turbo" /><category term="ORM" /><category term="Bundle" /><category term="Unity" /><category term="Lazy" /><category term="Minification" /><category term="Routing" /><category term="Windows Service" /><category term="window.onerror" /><category term="BlockingQueue" /><category term="JSON" /><category term="SNES" /><category term="Data Driven Unit Test" /><category term="Android" /><category term="Master of Orion" /><category term="Unit Testing" /><category term="LinqToSql" /><category term="MvcBundleConfig" /><category term="ExtJS" /><category term="HttpWebRequest" /><category term="NUnit" /><category term="jQuery" /><category term="Object Orientation" /><category term="CSS" /><category term="Music" /><category term="MP3" /><category term="Battlestar Galactica" /><category term="Caching" /><category term="IIS" /><category term="Best Practices" /><category term="Presentations" /><category term="Emulators" /><category term="Theory" /><category term="Compression" /><category term="Big O Notation" /><category term="C#" /><category term="Exception Driven Development" /><category term="xUnit" /><category term="RavenDB" /><category term="CookieContainer" /><category term="NuGet" /><category term="ConnectionLimit" /><category term="CustomModelBinderAttribute" /><category term="Internet Explorer" /><category term="SPC" /><category term="GOG" /><category term="Television" /><category term="JavaScript" /><category term="OS" /><category term=".NET" /><category term="DOS" /><title>Tom DuPont .NET</title><subtitle type="html">I'm a tool, so you don't have to be.</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://www.tomdupont.net/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>88</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/tdupont750" /><feedburner:info uri="tdupont750" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:browserFriendly></feedburner:browserFriendly><entry gd:etag="W/&quot;DUcMRnszeyp7ImA9WhBbFEw.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-735687022245953548</id><published>2013-05-12T20:41:00.000-07:00</published><updated>2013-05-12T20:51:27.583-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-05-12T20:51:27.583-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Lucene.Net" /><category scheme="http://www.blogger.com/atom/ns#" term="Analyzer" /><category scheme="http://www.blogger.com/atom/ns#" term="RavenDB" /><title>Alphanumeric Lucene Analyzer for RavenDB</title><content type="html">&lt;img src="http://sites.google.com/site/tdupont750/RavenDB.png" style="float:right;margin-left:10px;width: 150px;"&gt;

&lt;p&gt;&lt;a href="http://ravendb.net/" target="_blank"&gt;RavenDB&lt;/a&gt;'s full text indexing uses &lt;a href="http://lucenenet.apache.org/" target="_blank"&gt;Lucene.Net&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RavenDB is a second generation document database. This means that you can to throw typeless documents into a data store, but the only way to query them is by indexes that are built with Lucene.Net. RavenDB is a wonderful product that's primary strength is it's simplicity and easy of use. In keeping with that theme, even when you need to customize RavenDB, it makes it relatively easy to do.&lt;/p&gt;

&lt;p&gt;So, let's talk about customizing your Lucene.Net analyzer in RavenDB!&lt;/p&gt;

&lt;p style="font-size:1.2em"&gt;&lt;b&gt;Available Analyzers&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;RavenDB comes equipped with all of the analyzers that are built into Lucene.Net. For the vast majority of use cases, these will do the job! Here are some examples:&lt;/p&gt;

&lt;ul style="list-style-type: none;"&gt;&lt;li&gt;
&lt;pre style="font-size:.9em;"&gt;"The fox jumped over the lazy dogs, Bob@hotmail.com 123432."&lt;/pre&gt;
&lt;/li&gt;&lt;/ul&gt;

&lt;ul&gt;&lt;li&gt;
&lt;b&gt;StandardAnalyzer&lt;/b&gt;, which is Lucene's default, will produce the following tokens:&lt;br&gt;
&lt;pre style="font-size:.9em;margin-top: 5px;"&gt;[fox] [jumped] [over] [lazy] [dog] [bob@hotmail.com] [123432]&lt;/pre&gt;
&lt;/li&gt;&lt;/ul&gt;

&lt;ul&gt;&lt;li&gt;
&lt;b&gt;SimpleAnalyzer&lt;/b&gt; will tokenize on all non-alpha characters, and will make all the tokens lowercase:&lt;br&gt;
&lt;pre style="font-size:.9em;margin-top: 5px;"&gt;[the] [fox] [jumped] [over] [the] [lazy] [dogs] [bob] [hotmail] [com]&lt;/pre&gt;
&lt;/li&gt;&lt;/ul&gt;

&lt;ul&gt;&lt;li&gt;
&lt;b&gt;WhitespaceAnalyzer&lt;/b&gt; will just tokenize on white spaces:&lt;br&gt;
&lt;pre style="font-size:.9em;margin-top: 5px;"&gt;[The] [fox] [jumped] [over] [the] [lazy] [dogs,] [Bob@hotmail.com]
[123432.]&lt;/pre&gt;
&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;In order to resolve an issue with indexing file names (details below), I found myself in need of an Alphanumeric analyzer. This analyzer would be similar to the SimpleAnalyzer, but would still respect numeric values.&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;
&lt;b&gt;AlphanumericAnalyzer&lt;/b&gt; will tokenize on the .NET framework's Char.IsDigitOrLetter:&lt;br&gt;
&lt;pre style="font-size:.9em;margin-top: 5px;"&gt;[fox] [jumped] [over] [lazy] [dogs] [bob] [hotmail] [com] [123432]&lt;/pre&gt;
&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Lucene.Net's base classes made this pretty easy to build...&lt;/p&gt;

&lt;p style="font-size:1.2em"&gt;&lt;b&gt;How to Implement a Custom Analyzer&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Grab all the code and more from GitHub:&lt;/p&gt;

&lt;p style="text-align:center;"&gt;&lt;a href="https://github.com/tdupont750/RavenExtensions" target="_blank"&gt;Raven.Extensions.AlphanumericAnalyzer on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A lucene analyzer is made of two basic parts, 1) a tokenizer, and 2) a series of filters. The tokenizer does the lions share of the work and splits the input apart, then the filters run in succession making additional tweaks to the tokenized output.&lt;/p&gt;

&lt;p&gt;To create the Alphanumeric Analyzer we need only create two classes, an analyzer and a tokenizer. After that the analyzer can use reuse the existing LowerCaseFilter and StopFilter classes.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;AlphanumericAnalyzer&lt;/b&gt;&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;sealed&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; AlphanumericAnalyzer : Analyzer&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; AlphanumericAnalyzer(Version matchVersion, ISet&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; stopWords)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        _enableStopPositionIncrements = StopFilter&lt;/pre&gt;
&lt;pre&gt;            .GetEnablePositionIncrementsVersionDefault(matchVersion);&lt;/pre&gt;
&lt;pre class="alt"&gt;        _stopSet = stopWords;&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; TokenStream TokenStream(String fieldName, TextReader reader)&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        TokenStream tokenStream = &lt;span class="kwrd"&gt;new&lt;/span&gt; AlphanumericTokenizer(reader);&lt;/pre&gt;
&lt;pre class="alt"&gt;        tokenStream = &lt;span class="kwrd"&gt;new&lt;/span&gt; LowerCaseFilter(tokenStream);&lt;/pre&gt;
&lt;pre&gt;        tokenStream = &lt;span class="kwrd"&gt;new&lt;/span&gt; StopFilter(&lt;/pre&gt;
&lt;pre class="alt"&gt;            _enableStopPositionIncrements, &lt;/pre&gt;
&lt;pre&gt;            tokenStream, &lt;/pre&gt;
&lt;pre class="alt"&gt;            _stopSet);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; tokenStream;&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;b&gt;AlphanumericTokenizer&lt;/b&gt;&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; AlphanumericTokenizer : CharTokenizer&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsTokenChar(&lt;span class="kwrd"&gt;char&lt;/span&gt; c)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; Char.IsLetterOrDigit(c);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;b&gt;How to Install Plugins in RavenDB&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Installing a custom plugin to RavenDB is unbelievably easy. Just compile your assembly, and then drop it into the Plugins folder at the root of your RavenDB server. You may then reference the analyzers in &lt;a href="http://ravendb.net/docs/client-api/querying/static-indexes/configuring-index-options" target="_blank"&gt;your indexes&lt;/a&gt; by using their fully assembly qualified names.&lt;/p&gt;

&lt;p&gt;Again, you can grab all of the code and more over on GitHub:&lt;/p&gt;

&lt;p style="text-align:center;"&gt;&lt;a href="https://github.com/tdupont750/RavenExtensions" target="_blank"&gt;Raven.Extensions.AlphanumericAnalyzer on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;a style="float:right" rev="vote-for" href="http://dotnetshoutout.com/Alphanumeric-Lucene-Analyzer-for-RavenDB"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Fwww.tomdupont.net%2F2013%2F05%2Falphanumeric-lucene-analyzer-for-ravendb.html" style="border:0px"/&gt;&lt;/a&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/735687022245953548/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2013/05/alphanumeric-lucene-analyzer-for-ravendb.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/735687022245953548?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/735687022245953548?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2013/05/alphanumeric-lucene-analyzer-for-ravendb.html" title="Alphanumeric Lucene Analyzer for RavenDB" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DUAMQ3k7eSp7ImA9WhBbEUs.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-5857083630120359505</id><published>2013-04-26T22:59:00.000-07:00</published><updated>2013-05-09T23:36:22.701-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-05-09T23:36:22.701-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="String.Split" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>String Extensions: Split Qualified</title><content type="html">&lt;p&gt;Splitting on a string is easy.&lt;br&gt;
Respecting qualified (quoted) strings can be hard.&lt;br&gt;
Identifying escaped characters in qualified strings is very tricky.&lt;br&gt;
Splitting on a qualified string that takes escape characters into account is really difficult!&lt;/p&gt;

&lt;p&gt;&lt;big&gt;&lt;b&gt;Unit Tests&lt;/b&gt;&lt;/big&gt;&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;[Theory]&lt;/pre&gt;
&lt;pre&gt;[InlineData(&lt;span class="kwrd"&gt;null&lt;/span&gt;,                   &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[0])]&lt;/pre&gt;
&lt;pre class="alt"&gt;[InlineData(&lt;span class="str"&gt;""&lt;/span&gt;,                     &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[0])]&lt;/pre&gt;
&lt;pre&gt;[InlineData(&lt;span class="str"&gt;"hello world"&lt;/span&gt;,          &lt;span class="kwrd"&gt;new&lt;/span&gt;[] { &lt;span class="str"&gt;"hello"&lt;/span&gt;, &lt;span class="str"&gt;"world"&lt;/span&gt; })]&lt;/pre&gt;
&lt;pre class="alt"&gt;[InlineData(&lt;span class="str"&gt;"hello   world"&lt;/span&gt;,        &lt;span class="kwrd"&gt;new&lt;/span&gt;[] { &lt;span class="str"&gt;"hello"&lt;/span&gt;, &lt;span class="str"&gt;"world"&lt;/span&gt; })]&lt;/pre&gt;
&lt;pre&gt;[InlineData(&lt;span class="str"&gt;"\"hello world\""&lt;/span&gt;,      &lt;span class="kwrd"&gt;new&lt;/span&gt;[] { &lt;span class="str"&gt;"\"hello world\""&lt;/span&gt; })]&lt;/pre&gt;
&lt;pre class="alt"&gt;[InlineData(&lt;span class="str"&gt;"\"hello  world\""&lt;/span&gt;,     &lt;span class="kwrd"&gt;new&lt;/span&gt;[] { &lt;span class="str"&gt;"\"hello  world\""&lt;/span&gt; })]&lt;/pre&gt;
&lt;pre&gt;[InlineData(&lt;span class="str"&gt;"hello \"goodnight moon\" world"&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt;[]&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="str"&gt;"hello"&lt;/span&gt;, &lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="str"&gt;"\"goodnight moon\""&lt;/span&gt;, &lt;/pre&gt;
&lt;pre&gt;    &lt;span class="str"&gt;"world"&lt;/span&gt;, &lt;/pre&gt;
&lt;pre class="alt"&gt;})]&lt;/pre&gt;
&lt;pre&gt;[InlineData(&lt;span class="str"&gt;"hello \"goodnight \\\" moon\" world"&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt;[]&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="str"&gt;"hello"&lt;/span&gt;, &lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="str"&gt;"\"goodnight \\\" moon\""&lt;/span&gt;, &lt;/pre&gt;
&lt;pre&gt;    &lt;span class="str"&gt;"world"&lt;/span&gt;, &lt;/pre&gt;
&lt;pre class="alt"&gt;})]&lt;/pre&gt;
&lt;pre&gt;[InlineData(&lt;span class="str"&gt;"hello \"goodnight \\\\\" moon\" world"&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt;[]&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="str"&gt;"hello"&lt;/span&gt;, &lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="str"&gt;"\"goodnight \\\\\""&lt;/span&gt;, &lt;/pre&gt;
&lt;pre&gt;    &lt;span class="str"&gt;"moon\""&lt;/span&gt;, &lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="str"&gt;"world"&lt;/span&gt;, &lt;/pre&gt;
&lt;pre&gt;})]&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SplitQualified(&lt;span class="kwrd"&gt;string&lt;/span&gt; input, IList&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; expected)&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; actual = input&lt;/pre&gt;
&lt;pre&gt;        .SplitQualified(&lt;span class="str"&gt;' '&lt;/span&gt;, &lt;span class="str"&gt;'"'&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;        .ToList();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    Assert.Equal(expected.Count, actual.Count);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; i = 0; i &amp;lt; actual.Count; i++)&lt;/pre&gt;
&lt;pre&gt;        Assert.Equal(expected[i], actual[i]);&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;big&gt;&lt;b&gt;String Extension Methods&lt;/b&gt;&lt;/big&gt;&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; IEnumerable&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; SplitQualified(&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;this&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; input, &lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;char&lt;/span&gt; separator, &lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;char&lt;/span&gt; qualifier, &lt;/pre&gt;
&lt;pre class="alt"&gt;    StringSplitOptions options = StringSplitOptions.RemoveEmptyEntries, &lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;char&lt;/span&gt; escape = '\\')&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (String.IsNullOrWhiteSpace(input))&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[0];&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; results = SplitQualified(input, separator, qualifier, escape);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; options == StringSplitOptions.None&lt;/pre&gt;
&lt;pre&gt;        ? results&lt;/pre&gt;
&lt;pre class="alt"&gt;        : results.Where(r =&amp;gt; !String.IsNullOrWhiteSpace(r));&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; IEnumerable&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; SplitQualified(&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;string&lt;/span&gt; input, &lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;char&lt;/span&gt; separator, &lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;char&lt;/span&gt; qualifier, &lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;char&lt;/span&gt; escape)&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; separatorIndexes = input&lt;/pre&gt;
&lt;pre class="alt"&gt;        .IndexesOf(separator)&lt;/pre&gt;
&lt;pre&gt;        .ToList();&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; qualifierIndexes = input&lt;/pre&gt;
&lt;pre class="alt"&gt;        .IndexesOf(qualifier)&lt;/pre&gt;
&lt;pre&gt;        .ToList();&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="rem"&gt;// Remove Escaped Qualifiers&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; i = 0; i &amp;lt; qualifierIndexes.Count; i++)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; qualifierIndex = qualifierIndexes[i];&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (qualifierIndex == 0)&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;continue&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (input[qualifierIndex - 1] != escape)&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;continue&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="rem"&gt;// Watch out for a series of escaped escape characters.&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; escapeResult = &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; j = 2; qualifierIndex - j &amp;gt; 0; j++)&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (input[qualifierIndex - j] == escape)&lt;/pre&gt;
&lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;continue&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            escapeResult = j % 2 == 1;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (qualifierIndex &amp;gt; 1 &amp;amp;&amp;amp; escapeResult)&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;continue&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        qualifierIndexes.RemoveAt(i);&lt;/pre&gt;
&lt;pre class="alt"&gt;        i--;&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="rem"&gt;// Remove Qualified Separators&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (qualifierIndexes.Count &amp;gt; 1)&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; i = 0; i &amp;lt; separatorIndexes.Count; i++)&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; separatorIndex = separatorIndexes[i];&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; j = 0; j &amp;lt; qualifierIndexes.Count - 1; j += 2)&lt;/pre&gt;
&lt;pre class="alt"&gt;            {&lt;/pre&gt;
&lt;pre&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (separatorIndex &amp;lt;= qualifierIndexes[j])&lt;/pre&gt;
&lt;pre class="alt"&gt;                    &lt;span class="kwrd"&gt;continue&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (separatorIndex &amp;gt;= qualifierIndexes[j + 1])&lt;/pre&gt;
&lt;pre&gt;                    &lt;span class="kwrd"&gt;continue&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;                separatorIndexes.RemoveAt(i);&lt;/pre&gt;
&lt;pre class="alt"&gt;                i--;&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="rem"&gt;// Split String On Separators&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; previousSeparatorIndex = 0;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; separatorIndex &lt;span class="kwrd"&gt;in&lt;/span&gt; separatorIndexes)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; startIndex = previousSeparatorIndex == 0&lt;/pre&gt;
&lt;pre&gt;            ? previousSeparatorIndex&lt;/pre&gt;
&lt;pre class="alt"&gt;            : previousSeparatorIndex + 1;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; endIndex = separatorIndex == input.Length - 1&lt;/pre&gt;
&lt;pre&gt;            || previousSeparatorIndex == 0&lt;/pre&gt;
&lt;pre class="alt"&gt;            ? separatorIndex - previousSeparatorIndex&lt;/pre&gt;
&lt;pre&gt;            : separatorIndex - previousSeparatorIndex - 1;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        yield &lt;span class="kwrd"&gt;return&lt;/span&gt; input.Substring(startIndex, endIndex);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        previousSeparatorIndex = separatorIndex;&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (previousSeparatorIndex == 0)&lt;/pre&gt;
&lt;pre&gt;        yield &lt;span class="kwrd"&gt;return&lt;/span&gt; input;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        yield &lt;span class="kwrd"&gt;return&lt;/span&gt; input.Substring(previousSeparatorIndex + 1);&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; IEnumerable&amp;lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt; IndexesOf(&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;this&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; input, &lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;char&lt;/span&gt; value)&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!String.IsNullOrWhiteSpace(input))&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; index = -1;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            index++;&lt;/pre&gt;
&lt;pre class="alt"&gt;            index = input.IndexOf(value, index);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (index &amp;gt; -1)&lt;/pre&gt;
&lt;pre&gt;                yield &lt;span class="kwrd"&gt;return&lt;/span&gt; index;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;                &lt;span class="kwrd"&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;        while (index &amp;lt; input.Length);&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;a style="float:right" rev="vote-for" href="http://dotnetshoutout.com/NET-String-Extensions-Split-Qualified"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Fwww.tomdupont.net%2F2013%2F04%2Fstring-extensions-split-qualified.html" style="border:0px"/&gt;&lt;/a&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/5857083630120359505/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2013/04/string-extensions-split-qualified.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/5857083630120359505?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/5857083630120359505?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2013/04/string-extensions-split-qualified.html" title="String Extensions: Split Qualified" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>1</thr:total></entry><entry gd:etag="W/&quot;CEMCRH49fip7ImA9WhBVEEU.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-2993727272931887434</id><published>2013-04-13T13:00:00.000-07:00</published><updated>2013-04-15T20:21:05.066-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-04-15T20:21:05.066-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="Exception Driven Development" /><category scheme="http://www.blogger.com/atom/ns#" term="window.onerror" /><category scheme="http://www.blogger.com/atom/ns#" term="JavaScriptErrorReporter" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><category scheme="http://www.blogger.com/atom/ns#" term="StackTrace.js" /><category scheme="http://www.blogger.com/atom/ns#" term="EDD" /><category scheme="http://www.blogger.com/atom/ns#" term="jQuery" /><title>Report Unhandled Errors from JavaScript</title><content type="html">&lt;p&gt;Logging and aggregating error reports is one of the most important things you can do when building software: &lt;a href="http://www.codinghorror.com/blog/2009/04/exception-driven-development.html" taget="_blank"&gt;80% of customer issues can be solved by fixing 20% of the top-reported bugs&lt;/a&gt;.&lt;/p&gt;

&lt;img style="float:right; width:170px; margin-left:10px; margin-bottom:10px;" src="https://sites.google.com/site/tdupont750/JavaScriptErrorReporter.PNG" /&gt;

&lt;p&gt;Almost all websites at least has some form of error logging on their servers, but what about the client side of those websites? People have a tendency to brush over best practices for client side web development because "it's just some scripts." That, is, WRONG! Your JavaScript is your client application, it is how users experience your website, and as such it needs the proper attention and maintenance as any other rich desktop application.&lt;/p&gt;

&lt;p&gt;So then, how do you actually know when your users are experiencing errors in their browser? If you are like the vast majority of websites out there...&lt;/p&gt;

&lt;p&gt;&lt;i&gt;You don't know about JavaScript errors, and it's time to fix that!&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;&lt;big&gt;window.onerror&lt;/big&gt;&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Browsers do offer a way to get notified of all unhandled exceptions, that is the &lt;b&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/DOM/window.onerror" target="_blank"&gt;window.onerror event handler&lt;/a&gt;&lt;/b&gt;. You can wire a listener up to this global event handler and get back three parameters: the error message, the URL of the file in which the script broke, and the line number where the exception was thrown.&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;window.onerror = function myErrorHandler(errorMsg, url, lineNumber) {&lt;/pre&gt;
&lt;pre&gt;  &lt;span class="rem"&gt;// TODO: Something with this exception!&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;  &lt;span class="rem"&gt;// Just let default handler run.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;  &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;b&gt;&lt;big&gt;StackTrace.js&lt;/big&gt;&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;JavaScript can throw exceptions like any other language; browser debugging tools often show you a full stack trace for unhandled exceptions, but gathering that information programmatically is a bit more tricky. To learn a bit more about the JavaScript language and how to gather this information yourself, I suggest taking a look at this &lt;a href="http://helephant.com/2007/05/12/diy-javascript-stack-trace/" target="_blank"&gt;article by Helen Emerson&lt;/a&gt;. However in practice I would strongly suggest you use a more robust tool...&lt;/p&gt;

&lt;p&gt;&lt;b&gt;&lt;a href="https://github.com/eriwen/javascript-stacktrace" target="_blank"&gt;StackTrace.js&lt;/a&gt;&lt;/b&gt; is a very powerful library that will build a fully detailed stack trace from an exception object. It has a simple API, cross browser support, it handles fringe cases, and is very light weight and unobtrusive to your other JS libraries.&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;try&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="rem"&gt;// error producing code&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;} &lt;span class="kwrd"&gt;catch&lt;/span&gt;(error) {&lt;/pre&gt;
&lt;pre&gt;   &lt;span class="rem"&gt;// Returns stacktrace from error!&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;   &lt;span class="kwrd"&gt;var&lt;/span&gt; stackTrace = printStackTrace({e: error});&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;b&gt;&lt;big&gt;Two Big Problems&lt;/big&gt;&lt;/b&gt;&lt;/p&gt;

&lt;b&gt;&lt;ol&gt;&lt;li&gt;The window.onerror callback does not contain the actual error object.&lt;/li&gt;&lt;/ol&gt;&lt;/b&gt;

&lt;p&gt;This is a big problem because without the error object you cannot rebuild the stack trace. The error message is always useful, but file names and line numbers will be completely useless once you have &lt;a href="http://www.tomdupont.net/2012/03/configuring-bundles-in-mvc-4.html" target="_blank"&gt;minified your code&lt;/a&gt; in production. Currently, the only way you can bring additional information up to the onerror callback is to try catch any exceptions that you can and store the error object in a closure or global variable.&lt;/p&gt;

&lt;b&gt;&lt;ol start="2"&gt;&lt;li&gt;If you globally try catch event handlers it will be harder to use a debugger.&lt;/li&gt;&lt;/ol&gt;&lt;/b&gt;

&lt;p&gt;It would not be ideal to wrap every single piece of code that you write in an individual try catch block, and if you try to wrap your generic event handling methods in try catches then those catch blocks will interrupt your debugger when you are working with code in development.&lt;/p&gt;

&lt;p&gt;Currently my suggestion is to go with the latter option, but only deploy those interceptors with your minified or production code.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;&lt;big&gt;jQuery Solution&lt;/big&gt;&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;This global error handling implementation for jQuery and ASP.NET MVC is only 91 lines of JavaScript and 62 lines of C#.&lt;/p&gt;

&lt;p style="text-align:center;"&gt;&lt;b&gt;&lt;a href="https://github.com/tdupont750/JavaScriptErrorReporter" target="_blank"&gt;Download JavaScriptErrorReporter from GitHub&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;To get as much information as possible, you need to wire up to three things:&lt;br&gt;
&lt;i&gt;(Again, I suggest that you only include this when your code is minified!)&lt;/i&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;window.onerror&lt;/li&gt;
&lt;li&gt;$.fn.ready&lt;/li&gt;
&lt;li&gt;$.event.dispatch&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the meat of those wireups:&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt; lastStackTrace,&lt;/pre&gt;
&lt;pre&gt;    reportUrl = &lt;span class="kwrd"&gt;null&lt;/span&gt;,&lt;/pre&gt;
&lt;pre class="alt"&gt;    prevOnError = window.onerror,&lt;/pre&gt;
&lt;pre&gt;    prevReady = $.fn.ready,&lt;/pre&gt;
&lt;pre class="alt"&gt;    prevDispatch = $.&lt;span class="kwrd"&gt;event&lt;/span&gt;.dispatch;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="rem"&gt;// Send global methods with our wrappers.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;window.onerror = onError;&lt;/pre&gt;
&lt;pre class="alt"&gt;$.fn.ready = readyHook;&lt;/pre&gt;
&lt;pre&gt;$.&lt;span class="kwrd"&gt;event&lt;/span&gt;.dispatch = dispatchHook;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;function onError(error, url, line) {&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; result = &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;try&lt;/span&gt; {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="rem"&gt;// If there was a previous onError handler, fire it.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;typeof&lt;/span&gt; prevOnError == &lt;span class="str"&gt;'function'&lt;/span&gt;) {&lt;/pre&gt;
&lt;pre class="alt"&gt;            result = prevOnError(error, url, line);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="rem"&gt;// If the report URL is not loaded, load it.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (reportUrl === &lt;span class="kwrd"&gt;null&lt;/span&gt;) {&lt;/pre&gt;
&lt;pre class="alt"&gt;            reportUrl = $(document.body).attr(&lt;span class="str"&gt;'data-report-url'&lt;/span&gt;) || &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="rem"&gt;// If there is a rport URL, send the stack trace there.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (reportUrl !== &lt;span class="kwrd"&gt;false&lt;/span&gt;) {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; stackTrace = getStackTrace(error, url, line, lastStackTrace);&lt;/pre&gt;
&lt;pre&gt;            report(error, stackTrace);&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;    } &lt;span class="kwrd"&gt;catch&lt;/span&gt; (e) {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="rem"&gt;// Something went wrong, log it.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (console &amp;amp;&amp;amp; console.log) {&lt;/pre&gt;
&lt;pre class="alt"&gt;            console.log(e);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;    } &lt;span class="kwrd"&gt;finally&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="rem"&gt;// Clear the wrapped stack so it does get reused.&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;        lastStackTrace = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; result;&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;function readyHook(fn) {&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="rem"&gt;// Call the original ready method, but with our wrapped interceptor.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; prevReady.call(&lt;span class="kwrd"&gt;this&lt;/span&gt;, fnHook);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    function fnHook() {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;try&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;            fn.apply(&lt;span class="kwrd"&gt;this&lt;/span&gt;, arguments);&lt;/pre&gt;
&lt;pre class="alt"&gt;        } &lt;span class="kwrd"&gt;catch&lt;/span&gt; (e) {&lt;/pre&gt;
&lt;pre&gt;            lastStackTrace = printStackTrace({ e: e });&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;throw&lt;/span&gt; e;&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;function dispatchHook() {&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="rem"&gt;// Call the original dispatch method.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;try&lt;/span&gt; {&lt;/pre&gt;
&lt;pre class="alt"&gt;        prevDispatch.apply(&lt;span class="kwrd"&gt;this&lt;/span&gt;, arguments);&lt;/pre&gt;
&lt;pre&gt;    } &lt;span class="kwrd"&gt;catch&lt;/span&gt; (e) {&lt;/pre&gt;
&lt;pre class="alt"&gt;        lastStackTrace = printStackTrace({ e: e });&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;throw&lt;/span&gt; e;&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;b&gt;&lt;big&gt;Identifying Duplicate Errors&lt;/big&gt;&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;One last thing to mention is that when your stack trace arrives on the server it will contain file names and line numbers. The inconsistency of these numbers will make it difficult to identify duplicate errors. I suggest that you "clean" the stack traces by removing this extra information when trying to create a unique error hash.&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; Regex LineCleaner&lt;/pre&gt;
&lt;pre&gt;    = &lt;span class="kwrd"&gt;new&lt;/span&gt; Regex(&lt;span class="str"&gt;@"\([^\)]+\)$"&lt;/span&gt;, RegexOptions.Compiled);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; GetUniqueHash(&lt;span class="kwrd"&gt;string&lt;/span&gt;[] stackTrace)&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; sb = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder();&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; stackLine &lt;span class="kwrd"&gt;in&lt;/span&gt; stackTrace)&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; cleanLine = LineCleaner&lt;/pre&gt;
&lt;pre class="alt"&gt;            .Replace(stackLine, String.Empty)&lt;/pre&gt;
&lt;pre&gt;            .Trim();&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!String.IsNullOrWhiteSpace(cleanLine))&lt;/pre&gt;
&lt;pre class="alt"&gt;            sb.AppendLine(cleanLine);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; sb&lt;/pre&gt;
&lt;pre class="alt"&gt;        .ToString()&lt;/pre&gt;
&lt;pre&gt;        .ToLowerInvariant()&lt;/pre&gt;
&lt;pre class="alt"&gt;        .GetHashCode();&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;b&gt;&lt;big&gt;Integration Steps&lt;/big&gt;&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;This article was meant to be more informational than tutorial; but if you are interested in trying to apply this to your site, here are the steps that you would need to take:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download &lt;a href="https://github.com/tdupont750/JavaScriptErrorReporter" target="_blank"&gt;JavaScriptErrorReporter from GitHub&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Include StackTrace.js as a resource in your website.&lt;/li&gt;
&lt;li&gt;
Include ErrorReporter.js as a resource in your website.
&lt;ul&gt;
&lt;li&gt;&lt;i&gt;Again, to prevent it interfering with your JavaScript debugger, I suggest only including this resource when your scripts are being minified.&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Add a report error action to an appropriate controller. (Use the ReportError action on the HomeController as an example.)&lt;/li&gt;
&lt;li&gt;Add a "data-report-url" attribute with the fully qualified path to your report error action to the body tag of your pages.&lt;/li&gt;
&lt;li&gt;Log any errors that your site reports!&lt;/li&gt;
&lt;/ol&gt;

&lt;a style="float:right" rev="vote-for" href="http://dotnetshoutout.com/Report-Unhandled-Errors-from-JavaScript"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Fwww.tomdupont.net%2F2013%2F04%2Freport-unhandled-errors-from-javascript.html" style="border:0px"/&gt;&lt;/a&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/2993727272931887434/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2013/04/report-unhandled-errors-from-javascript.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/2993727272931887434?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/2993727272931887434?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2013/04/report-unhandled-errors-from-javascript.html" title="Report Unhandled Errors from JavaScript" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>3</thr:total></entry><entry gd:etag="W/&quot;CEQESXc6cCp7ImA9WhBWGEU.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-3685694206332645377</id><published>2013-03-28T22:38:00.001-07:00</published><updated>2013-04-13T12:45:08.918-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-04-13T12:45:08.918-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="Windows Service" /><title>Run Multiple Tasks in a Windows Service</title><content type="html">&lt;p&gt;ServicesBase.Run(ServiceBase[] services) ...that sure made me think you could run multiple implementations of ServiceBase in a single Windows Service; &lt;a href="http://stackoverflow.com/questions/2567905/c-windows-services-servicebase-run-with-several-services-of-the-same-type" target="_blank"&gt;but that is not how it works&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;One Service, Multiple Tasks&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;I often have a very simple use case: I needed to run multiple tasks in a single windows service. For example, one task to poll some email notifications, and one task to listen to HTTP requests that might trigger those same notifications.&lt;/p&gt;

&lt;p&gt;I like the basic setup of OnStart, Run, and OnStop, but after authoring several windows services I got tired of writing the same code over and over again. Thus I created the WindowServiceTasks library. Now whenever I need to do another task in a service, I just implement the WindowsServiceTaskBase or WindowsServiceLoopBase class, and my code is all ready to go!&lt;/p&gt;

&lt;p&gt;&lt;b&gt;WindowsServiceTasks&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Run multiple tasks in a single WindowsService, and let the base library do all of the work setup and tear down for you. The WindowsServiceTasks NuGet package is simple, flexible, and extremely light weight.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;b&gt;&lt;a href="https://nuget.org/packages/WindowsServiceTasks/1.1.0" target="_blank"&gt;NuGet Package&lt;/a&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href="https://github.com/tdupont750/WindowsServiceTasks" target="_blank"&gt;Source on GitHub&lt;/a&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b&gt;Example&lt;/b&gt;&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Program&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Main(&lt;span class="kwrd"&gt;params&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[] args)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; logger = &lt;span class="kwrd"&gt;new&lt;/span&gt; Logger(&lt;span class="str"&gt;"Demo.log"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; emailTask = &lt;span class="kwrd"&gt;new&lt;/span&gt; EmailServiceTask(logger);&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; failTask = &lt;span class="kwrd"&gt;new&lt;/span&gt; FailServiceTask(logger);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; service = &lt;span class="kwrd"&gt;new&lt;/span&gt; Service1(logger, emailTask, failTask);&lt;/pre&gt;
&lt;pre&gt;        service.Start(args);&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; EmailServiceTask : WindowsServiceLoopBase&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; ILogger _logger;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; EmailServiceTask(ILogger logger)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        _logger = logger;&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; LoopMilliseconds&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;get&lt;/span&gt; { &lt;span class="kwrd"&gt;return&lt;/span&gt; 2000; }&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; HandleException(Exception exception)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        _logger.Log(exception);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RunLoop()&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="rem"&gt;// TODO Send Email!&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;        _logger.Log(&lt;span class="str"&gt;"EmailServiceTask.RunLoop - Sending an email"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnStart(&lt;span class="kwrd"&gt;string&lt;/span&gt;[] args)&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        _logger.Log(&lt;span class="str"&gt;"EmailServiceTask.OnStart"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnStop()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        _logger.Log(&lt;span class="str"&gt;"EmailServiceTask.OnStop"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; DisposeResources()&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;a style="float:right" rev="vote-for" href="http://dotnetshoutout.com/Run-Multiple-Tasks-in-a-Windows-Service"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Fwww.tomdupont.net%2F2013%2F03%2Fmultiple-tasks-in-windows-service.html" style="border:0px"/&gt;&lt;/a&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/3685694206332645377/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2013/03/multiple-tasks-in-windows-service.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/3685694206332645377?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/3685694206332645377?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2013/03/multiple-tasks-in-windows-service.html" title="Run Multiple Tasks in a Windows Service" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>3</thr:total></entry><entry gd:etag="W/&quot;DEMDRX0yeCp7ImA9WhBQFU0.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-8670465773792337151</id><published>2013-03-17T00:46:00.000-07:00</published><updated>2013-03-17T00:47:54.390-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-03-17T00:47:54.390-07:00</app:edited><title>Castlevania 3DS - Demo Review</title><content type="html">&lt;p&gt;&lt;i&gt;TL;DR - After only 5 minutes, it's pretty terrible.&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;I had the privilege of attending E3 last year and seeing the premier footage of Castlevania: Lords of Shadow - Mirror of Fate. At the time, was I excited! Enjoy a good Castlevania game, my favorites being &lt;a href="http://en.wikipedia.org/wiki/Castlevania_III:_Dracula%27s_Curse" target="_blank"&gt;Dracula's Curse&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Castlevania:_Symphony_of_the_Night" target="_blank"&gt;Symphony of the Night&lt;/a&gt;. These were games that classic hack and slash platforms; they were engaging, colorful, and just down right fun to play.&lt;/p&gt;

&lt;p&gt;Before I review the demo, I want to comment on the title, of which this game has three: 1) Castlevania 2) Lords of Shadow 3) Mirror of Fate. This game is &lt;a href="http://en.wikipedia.org/wiki/Castlevania:_Lords_of_Shadow" target="_blank"&gt;a spin off of a reboot&lt;/a&gt; of the Castlevania franchise. This name made me wary because it seemed, at least to me, to imply a lack of identity or originality in this game itself.&lt;/p&gt;

&lt;p&gt;...but enough hearsay, let's get to the demo!&lt;/p&gt;

&lt;p style="text-align:center"&gt;&lt;img style="width:400px" src="http://sites.google.com/site/tdupont750/castlvania_3ds_demo_review.png"&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Starting The Demo&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;I launched the demo and my first thought of the title screen just looked generic, so I immediately launched the game. First the loading screen popped up and showed me the controls for the game, which seems a like a large number of buttons/abilities to dump on the users one second into the game. Also, it did nothing to help &lt;a href="http://www.youtube.com/watch?feature=player_detailpage&amp;v=j03DVgCTLQs#t=0s" target="_blank"&gt;set the atmosphere or tone of the game&lt;/a&gt;. On the other hand, I like that there was no distracting, interrupting, or hand holding tutorial.&lt;/p&gt;

&lt;p&gt;Once the game loads the then camera zooms around our protagonist in front of a giant castle and then you are left to run across a bridge. There was no dialog or exposition, which could be fine, but then I'm not sure who I am or even if this is Dracula's castle. &lt;a href="http://www.youtube.com/watch?feature=player_detailpage&amp;v=9gEGIT9anJ0#t=75s" target="_blank"&gt;Some headings or subtitles&lt;/a&gt; could have been useful to help set the scene.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Slow Clunky Combat&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Once I ran I immediately had to fight some skeletons, one of which had a shield. I took a few swings with my whip, which felt slow and clunky, and it seemed to do very little to no damage to the enemies. I then moved to jump away from their attacks only to find that my character could not move until his attack animation was done, making him get clobbered by the shielded skeleton.&lt;/p&gt;

&lt;p&gt;After &lt;a href="http://www.youtube.com/watch?feature=player_detailpage&amp;v=gUFOq0bxU8Y#t=174s" target="_blank"&gt;mindlessly whacking away at the skeletons&lt;/a&gt; for a while, and taking a decent amount of damage while I was at it, I finally manged to kill one; and then a big game pausing modal popped up telling me that I had killed an enemy and earned experience points. This completely sucked me out of the immersion of the game, I stopped fighting and had to read a completely useless piece of ugly text telling me something that I already knew...not a good start!&lt;/p&gt;

&lt;p&gt;&lt;b&gt;An Under Powered Protagonist&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;I finally managed to kill other two skeletons and proceed forward. I then killed two more little skeletons, each taking 4 or 5 hits to take down. This was also bothersome because it made my main character feel extremely weak. I am a vampire hunter single-handedly charging into what I can only assume is Dracula's castle, and it takes me 5 attacks to kill a single entry level skeleton? That is not at all impressive.&lt;/p&gt;

&lt;p&gt;So now, after struggling to kill 5 skeletons, &lt;a href="http://www.youtube.com/watch?feature=player_detailpage&amp;v=gUFOq0bxU8Y#t=192s" target="_blank"&gt;the first mini boss appears&lt;/a&gt;. It is a big fat unmemorable armored guy with a wreaking ball flail, at whom I proceed to swing my whip. Each time that I hit him he flashes red but I there are no damage animations or pauses, nor is there a health meter anyone on the HUD; so even after a dozen attacks I still have no idea how much damage I am doing to him, if any at all. However a tool tip did appear on the screen telling me to press R to hold the enemy, but every time I pressed R absolutely nothing happened.&lt;/p&gt;

&lt;p&gt;...and so I died on the first mini boss.&lt;br&gt;
...multiple times.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;A Second Opinion&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;At this point I was very disappointed and frustrated by the demo because, despite any particular complaint I had with the game, I was simply not having fun. My girlfriend was waking up around this time and asked me what I was doing, and so without making any comments or explanations I had passed her my 3DS XL and had her try to demo.&lt;/p&gt;

&lt;p&gt;She is usually better than me at most games, and she died on the first set of skeletons! She complained numerous times that she could not jump away from them when they attacked, and she also noted that the tool tip telling her to press R did absolutely nothing. Of course I then explained that I had experienced the exact same problems while I was playing the game, and we both agreed that this was a pretty shitty game,or at least a pretty shitty demo.&lt;/p&gt;

&lt;p&gt;(Hours later I had a friend of mine try this demo and got very similar reactions from him. His solution to the shielded skeleton was to &lt;a href="http://www.youtube.com/watch?feature=player_detailpage&amp;v=c4SJ0xR2_bQ#t=151s" target="_blank"&gt;jump over it and run away&lt;/a&gt;, because he did not think that it could be killed.)&lt;/p&gt;

&lt;p&gt;&lt;i&gt;I should have stopped there, but I really wanted to give Castlevania another chance to win me over.&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The Boring Boomerang&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;I finally beat the first mini boss and proceeded into the next room in the castle. Visual this room was bland and boring, and made me &lt;a href="http://www.youtube.com/watch?feature=player_detailpage&amp;v=gUFOq0bxU8Y#t=287s" target="_blank"&gt;run across it for seemly no reason&lt;/a&gt;. However at the end of the room, I got my first secondary weapon: the boomerang. This got me excited, that was by far the best secondary weapon in Castlevania 3, and I was immediately stoked about trying it out. Right on queue, some bats broke through a window in the background and volunteered themselves for boomerang target practice.&lt;/p&gt;

&lt;p&gt;When I threw the boomerang at the bats, &lt;a href="http://www.youtube.com/watch?feature=player_detailpage&amp;v=gUFOq0bxU8Y#t=328s" target="_blank"&gt;nothing happened&lt;/a&gt;. I mean the boomerang left my hand a few into the bat, but the bat did not react! The boomerang just stuck out of him with no auditory or visual queues as to the bat being injured, let alone killed. I had to throw three boomerangs into one bat to kill it, and then three more into another, until finally I was out of boomerangs and had to kill the final bat with my stupid whip.&lt;/p&gt;

&lt;p&gt;When you first get &lt;a href="http://www.youtube.com/watch?v=BzaMNiJH9eg" target="_blank"&gt;the boomerang in Castlevania 3&lt;/a&gt;, you use it to fight zombies and a single boomerang rips through and destroys dozens of zombies at a time! It was powerful, it was cool, it was infinitely better than this latest iteration's piece of crap.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Final Verdict&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Gameplay - 3/10&lt;/u&gt;&lt;br&gt;
The controls are sluggish, the weapons are weak, and ammo is limited. This game does not feel like a fun fast paced Castlevania, it plays like a slow boring iOS clone.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Graphics - 6/10&lt;/u&gt;&lt;br&gt;
The game looks pretty good, but it uses a very dark and drab color pallet and none of the art itself stands out in any way. Also, there are no impressive spectacles in the intro, just rooms with flat backgrounds.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Music - 0/10&lt;/u&gt;&lt;br&gt;
This soundtrack is so bland and forgettable that I had to go back and replay the demo to just see if there was any music at all. This is elevator music, not what a Castlevania game &lt;a href="http://www.youtube.com/watch?v=78706bv98S8" target="_blank"&gt;should sound like&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Story - N/A&lt;/u&gt;&lt;br&gt;
I like it when games start out quick and do not get bogged down in complex exposition, but Castlevania: Lords of Shadow - Mirror of Fate -- Demo Edition --- We Love Titles ---- On the 3DS eShop has the opposite problem; I am not even sure what castle I was in.&lt;/p&gt;

&lt;p&gt;I really hope that this demo is not indicative of the final game, unfortunately it is a pretty safe bet &lt;a href="http://www.ign.com/articles/2013/03/05/castlevania-lords-of-shadow-mirror-of-fate-review" target="_blank"&gt;that it is&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Game on,&lt;br&gt;
Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/8670465773792337151/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2013/03/castlevania-3ds-demo-review.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/8670465773792337151?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/8670465773792337151?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2013/03/castlevania-3ds-demo-review.html" title="Castlevania 3DS - Demo Review" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;A0MNR3Y5fyp7ImA9WhBREkk.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-1249510179698375735</id><published>2013-02-28T09:00:00.000-08:00</published><updated>2013-03-02T10:38:16.827-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-03-02T10:38:16.827-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="Windows Service" /><title>Running a Windows Service as a Console App</title><content type="html">&lt;p&gt;This is a prerequisite post before I can talk about the &lt;a href="https://github.com/tdupont750/WindowsServiceTasks" target="_blank"&gt;WindowsServiceTasks library&lt;/a&gt; that I recently released.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;How do you test windows services?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;I hope your first response was unit tests, but even if it was we both know that you still have to integration test the whole application. You could install your service into windows and then attach your debugger to it's process, but that is a lot of work. Why not just run your service as a console application? Then you can test it by just pressing play in Visual Studio!&lt;/p&gt;

&lt;p&gt;&lt;b&gt;How do you run a windows service as a console application?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Easy! Just go into your windows service project's settings and set the Output Type to Console Application. This will allow the executable to launch as a console app, but it is still completely executable as a service!&lt;/p&gt;

&lt;img src="https://sites.google.com/site/tdupont750/WindowsServiceConsoleApplication.png" style="width: 550px;"&gt;

&lt;p&gt;Inside of your code, you can use the Environment.UserInteractive property to determine which mode you are in. With that you can do cool things to help you debug, such as register an alternate logger with your IOC container that will write your long lines to console instead of (or as well as) to file.&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Program&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Main(&lt;span class="kwrd"&gt;params&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[] args)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; service = &lt;span class="kwrd"&gt;new&lt;/span&gt; Service1();&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!Environment.UserInteractive)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; servicesToRun = &lt;span class="kwrd"&gt;new&lt;/span&gt; ServiceBase[] { service };&lt;/pre&gt;
&lt;pre&gt;            ServiceBase.Run(servicesToRun);&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt; &lt;/pre&gt;
&lt;pre&gt;        Console.WriteLine(&lt;span class="str"&gt;"Running as a Console Application"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;        Console.WriteLine(&lt;span class="str"&gt;" 1. Run Service"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;        Console.WriteLine(&lt;span class="str"&gt;" 2. Other Option"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;        Console.WriteLine(&lt;span class="str"&gt;" 3. Exit"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;        Console.Write(&lt;span class="str"&gt;"Enter Option: "&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; input = Console.ReadLine();&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;switch&lt;/span&gt; (input)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;"1"&lt;/span&gt;:&lt;/pre&gt;
&lt;pre&gt;                service.Start(args);&lt;/pre&gt;
&lt;pre class="alt"&gt;                Console.WriteLine(&lt;span class="str"&gt;"Running Service - Press Enter To Exit"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;                Console.ReadLine();&lt;/pre&gt;
&lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;"2"&lt;/span&gt;:&lt;/pre&gt;
&lt;pre&gt;                &lt;span class="rem"&gt;// TODO!&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt; &lt;/pre&gt;
&lt;pre&gt;        Console.WriteLine(&lt;span class="str"&gt;"Closing"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;pre class="alt"&gt; &lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Service1 : ServiceBase&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; Service1() { InitializeComponent(); }&lt;/pre&gt;
&lt;pre class="alt"&gt; &lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Start(&lt;span class="kwrd"&gt;string&lt;/span&gt;[] args) { OnStart(args); }&lt;/pre&gt;
&lt;pre class="alt"&gt; &lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnStart(&lt;span class="kwrd"&gt;string&lt;/span&gt;[] args) { }&lt;/pre&gt;
&lt;pre class="alt"&gt; &lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnStop() { }&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;b&gt;What other uses does this offer?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;You can then also use your windows services as management utilities. I have worked with applications before where when I needed to make a configuration change to a system I was told to go run windows services with random undiscoverable command line arguments or magic number configuration settings. By launching your service as a console app you can inject simple menu systems to allow users easy access to admin functionality.&lt;/p&gt;

&lt;a style="float:right" rev="vote-for" href="http://dotnetshoutout.com/Running-a-Windows-Service-as-a-Console-App"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Fwww.tomdupont.net%2F2013%2F02%2Frunning-windows-service-as-console-app.html" style="border:0px"/&gt;&lt;/a&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/1249510179698375735/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2013/02/running-windows-service-as-console-app.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/1249510179698375735?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/1249510179698375735?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2013/02/running-windows-service-as-console-app.html" title="Running a Windows Service as a Console App" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;DE8BRn8zcCp7ImA9WhBSEU4.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-1267569088125974608</id><published>2013-02-17T09:37:00.000-08:00</published><updated>2013-02-17T13:34:17.188-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-02-17T13:34:17.188-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Unity" /><category scheme="http://www.blogger.com/atom/ns#" term="MVC" /><category scheme="http://www.blogger.com/atom/ns#" term="Dependency Injection" /><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="Cache" /><category scheme="http://www.blogger.com/atom/ns#" term="NuGet" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><category scheme="http://www.blogger.com/atom/ns#" term="MVC4" /><category scheme="http://www.blogger.com/atom/ns#" term="Caching" /><title>Cache Repository for MVC</title><content type="html">&lt;p&gt;First and foremost, the CacheRepository is &lt;i&gt;NOT web specific!&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;The CacheRepository library contains the abstract CacheRepositoryBase class, which can be implemented by any caching system that you choose. The CacheRepository.Web NuGet package includes a WebCacheRepository implementation that leverages System.Web.Caching.Cache&lt;/p&gt;

&lt;p style="text-align:center;"&gt;&lt;a href="http://nuget.org/packages/CacheRepository.Web" target="_blank"&gt;&lt;img src="https://sites.google.com/site/tdupont750/CacheRepository.Web.png" alt="CacheRepository.Web" style="width: 398px;height:65px;"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Get all of the source code, unit tests, and a complete MVC4 sample application (preconfigured to include dependency injection with Unity) from GitHub. Or to just jump in and start using it, grab the CacheRepository.Web package from NuGet.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;b&gt;&lt;a href="https://github.com/tdupont750/CacheRepository" target="_blank"&gt;GitHub - Source Code, Tests, &amp; Sample&lt;/a&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href="http://nuget.org/packages/CacheRepository.Web" target="_blank"&gt;NuGet Gallery - CacheRepository.Web&lt;/a&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;h3&gt;ICacheRepository&lt;/h3&gt;&lt;/p&gt;

&lt;p&gt;The ICacheRepository interface has all the standard Get, Set, Remove and Clear methods. Additionally, these methods have been expanded to include enum parameters to group manage cache expiration.&lt;/p&gt;

&lt;p&gt;Best of all, it includes GetOrSet methods. These methods will try to get the value of the specified key, and when it can not find that value it will then be loaded via the passed in Func. A key feature here is the fact that the setter of the GetOrSet will lock on load to prevent redundant data loads. (More details about this below.)&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; ICacheRepository&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;object&lt;/span&gt; Get(&lt;span class="kwrd"&gt;string&lt;/span&gt; key);&lt;/pre&gt;
&lt;pre&gt;    T Get&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt; key);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    T GetOrSet&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt; key, Func&amp;lt;T&amp;gt; loader);&lt;/pre&gt;
&lt;pre class="alt"&gt;    T GetOrSet&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt; key, Func&amp;lt;T&amp;gt; loader, DateTime expiration);&lt;/pre&gt;
&lt;pre&gt;    T GetOrSet&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt; key, Func&amp;lt;T&amp;gt; loader, TimeSpan sliding);&lt;/pre&gt;
&lt;pre class="alt"&gt;    T GetOrSet&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt; key, Func&amp;lt;T&amp;gt; loader, CacheExpiration expiration);&lt;/pre&gt;
&lt;pre&gt;    T GetOrSet&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt; key, Func&amp;lt;T&amp;gt; loader, CacheSliding sliding);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; Set&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt; key, T value);&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; Set&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt; key, T value, DateTime expiration);&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; Set&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt; key, T value, TimeSpan sliding);&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; Set&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt; key, T value, CacheExpiration expiration);&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; Set&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt; key, T value, CacheSliding sliding);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; Remove(&lt;span class="kwrd"&gt;string&lt;/span&gt; key);&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; ClearAll();&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;h3&gt;ThreadSafe GetOrSet&lt;/h3&gt;&lt;/p&gt;

&lt;p&gt;As any good cache should, the CacheRepository is thread safe and can be treated as a singleton.&lt;/p&gt;

&lt;p&gt;Even better, the GetOrSet methods lock on set. This means that 10 threads could be trying to load the same cache value simultaneously, but only one will actually trigger a load and set. This helps redundant resource loads and database calls and keep your application running optimally.&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; T GetOrSet&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt; key, Func&amp;lt;T&amp;gt; loader,&lt;/pre&gt;
&lt;pre&gt;    DateTime? expiration, TimeSpan? sliding)&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="rem"&gt;// Get It&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;    T value;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; success = TryGet(key, &lt;span class="kwrd"&gt;out&lt;/span&gt; value);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="rem"&gt;// Got It or No Loader&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (loader == &lt;span class="kwrd"&gt;null&lt;/span&gt; || success)&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; value;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="rem"&gt;// Load It&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; LockedInvoke(key, () =&amp;gt;&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="rem"&gt;// Get It (Again)&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        success = TryGet(key, &lt;span class="kwrd"&gt;out&lt;/span&gt; value);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!success)&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="rem"&gt;// Load It (For Real)&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;            value = loader();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="rem"&gt;// Set It&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (value != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;                Set(key, value, expiration, sliding);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; value;&lt;/pre&gt;
&lt;pre class="alt"&gt;    });&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;h3&gt;Configurable Expiration Enums&lt;/h3&gt;&lt;/p&gt;

&lt;p&gt;Instead of being forced to set each of your cache expirations separately, you now have the option to use an enum value to group your cache expirations. Enums are available for both absolute expiration and sliding expiration.&lt;/p&gt;

&lt;p&gt;You may override the duration of each cache key in your app config; this is really useful for when you want to uniformly modify your cache expirations in your QA or testing environments. Additionally, you may override the CacheRepositoryBase.GetConfigurationValue method to pull this configuration for anywhere you want, not just the ConfigurationManager.

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;enum&lt;/span&gt; CacheExpiration&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    VeryShort = 10,     &lt;span class="rem"&gt;// Ten Seconds&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    Short = 60,         &lt;span class="rem"&gt;// One Minute&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;    Medium = 300,       &lt;span class="rem"&gt;// Five Minutes&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    Long = 3600,        &lt;span class="rem"&gt;// One Hour&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;    VeryLong = 86400    &lt;span class="rem"&gt;// One Day&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;br&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;appSettings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;key&lt;/span&gt;&lt;span class="kwrd"&gt;="CacheExpiration.VeryShort"&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="15"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;key&lt;/span&gt;&lt;span class="kwrd"&gt;="CacheExpiration.Short"&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="90"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;h3&gt;ByType Extensions&lt;/h3&gt;&lt;/p&gt;

&lt;p&gt;Transparent cache key management is offered through a series of ICacheRepository extension methods. This makes caching even easier, as you don't need to worry about cache key collisions.&lt;/p&gt;

&lt;p&gt;Using these extension methods, you many cache a Cat object with an Id of 1 and a Dog object with an Id of 1 in the same manner. The extension methods will create a key prefix based on the type and then use the specified identified as the suffix.&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;[Fact]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SameKeyDifferentType()&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; setCat = &lt;span class="kwrd"&gt;new&lt;/span&gt; Cat { Name = &lt;span class="str"&gt;"Linq"&lt;/span&gt; };&lt;/pre&gt;
&lt;pre class="alt"&gt;    CacheRepository.SetByType(1, setCat);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; setDog = &lt;span class="kwrd"&gt;new&lt;/span&gt; Dog { Name = &lt;span class="str"&gt;"Taboo"&lt;/span&gt; };&lt;/pre&gt;
&lt;pre&gt;    CacheRepository.SetByType(1, setDog);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; getCat = CacheRepository.GetByType&amp;lt;Cat&amp;gt;(1);&lt;/pre&gt;
&lt;pre class="alt"&gt;    Assert.Equal(setCat.Name, getCat.Name);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; getDog = CacheRepository.GetByType&amp;lt;Dog&amp;gt;(1);&lt;/pre&gt;
&lt;pre&gt;    Assert.Equal(setDog.Name, getDog.Name);&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;h3&gt;Web Implementation &amp; Dependency Injection via Unity&lt;/h3&gt;&lt;/p&gt;

&lt;p&gt;The CacheRepository.Web NuGet package includes a WebCacheRepository implementation that leverages System.Web.Caching.Cache. This is a very simple, but very effective, production ready implementation of the CacheRepositoryBase.&lt;/p&gt;

&lt;p&gt;It should also be noted that this implementation is not only useful in ASP.NET, the System.Web.Caching.Cache is located in the System.Web library, but it still available outside of a web context. This means that this implementation can be used in other applications, including but not limited to Windows Services.&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; WebCacheRepository : CacheRepositoryBase&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; Cache _cache;&lt;/pre&gt;
&lt;pre&gt;        &lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; WebCacheRepository()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        _cache = HttpContext.Current == &lt;span class="kwrd"&gt;null&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;            ? HttpRuntime.Cache&lt;/pre&gt;
&lt;pre class="alt"&gt;            : HttpContext.Current.Cache;&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Wiring the cache repository to be injected into your controllers via Unity is also very easy. Just register the WebCacheRepository for the ICacheRepository interface, and be sure to provide a ContainerControlledLifetimeManager for optimal performance.&lt;/p&gt;

&lt;p&gt;To use the implementation below, you will need to include the &lt;a href="http://nuget.org/packages/Unity.Mvc3/" target="_blank"&gt;Unity.MVC3 NuGet Package&lt;/a&gt; to gain access to the UnityDependencyResolver.&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Initialise()&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; container = BuildUnityContainer();&lt;/pre&gt;
&lt;pre&gt;    &lt;/pre&gt;
&lt;pre class="alt"&gt;    DependencyResolver.SetResolver(&lt;span class="kwrd"&gt;new&lt;/span&gt; UnityDependencyResolver(container));&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; IUnityContainer BuildUnityContainer()&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; container = &lt;span class="kwrd"&gt;new&lt;/span&gt; UnityContainer();&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    container.RegisterType&amp;lt;ICacheRepository, WebCacheRepository&amp;gt;(&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;new&lt;/span&gt; ContainerControlledLifetimeManager());           &lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; container;&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;If you missed the links above, here they are again:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;b&gt;&lt;a href="https://github.com/tdupont750/CacheRepository" target="_blank"&gt;GitHub - Source Code, Tests, &amp; Sample&lt;/a&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href="http://nuget.org/packages/CacheRepository.Web" target="_blank"&gt;NuGet Gallery - CacheRepository.Web&lt;/a&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;a style="float:right" rev="vote-for" href="http://dotnetshoutout.com/Cache-Repository-for-MVC"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Fwww.tomdupont.net%2F2013%2F02%2Fcache-repository-for-mvc.html" style="border:0px"/&gt;&lt;/a&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/1267569088125974608/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2013/02/cache-repository-for-mvc.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/1267569088125974608?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/1267569088125974608?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2013/02/cache-repository-for-mvc.html" title="Cache Repository for MVC" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>3</thr:total></entry><entry gd:etag="W/&quot;DEMEQng6cCp7ImA9WhBSEU4.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-2514174170848558220</id><published>2013-01-13T22:29:00.000-08:00</published><updated>2013-02-17T13:26:43.618-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-02-17T13:26:43.618-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><category scheme="http://www.blogger.com/atom/ns#" term="WebDriver" /><category scheme="http://www.blogger.com/atom/ns#" term="Selenium" /><title>WebElement Form Extensions for WebDriver</title><content type="html">&lt;p&gt;I really like &lt;a href="http://code.google.com/p/selenium/" target="_blank"&gt;Selenium 2.0&lt;/a&gt;!

&lt;p&gt;I've been working a lot on a side project involving WebDriver, and thus I have been creating a few extension methods for working with form data that I thought others might find helpful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bool IsSelected(this IWebElement element)&lt;/li&gt;
&lt;li&gt;bool IsChecked(this IWebElement element)&lt;/li&gt;
&lt;li&gt;void SetChecked(this IWebElement element)&lt;/li&gt;
&lt;li&gt;void SetUnchecked(this IWebElement element)&lt;/li&gt;
&lt;li&gt;IWebElement GetOptionByValue(this IWebElement element, string value)&lt;/li&gt;
&lt;li&gt;IWebElement GetOptionByText(this IWebElement element, string text)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b&gt;Extension Methods&lt;/b&gt;&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; WebElementExtensions&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; StringComparer DefaultComparer =&lt;/pre&gt;
&lt;pre&gt;        StringComparer.InvariantCultureIgnoreCase;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[] Selected = &lt;span class="kwrd"&gt;new&lt;/span&gt;[] { &lt;span class="str"&gt;"true"&lt;/span&gt;, &lt;span class="str"&gt;"selected"&lt;/span&gt; };&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsSelected(&lt;span class="kwrd"&gt;this&lt;/span&gt; IWebElement element)&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; attribute = element.GetAttribute(&lt;span class="str"&gt;"selected"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; Selected.Contains(attribute, DefaultComparer);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[] Checked = &lt;span class="kwrd"&gt;new&lt;/span&gt;[] { &lt;span class="str"&gt;"true"&lt;/span&gt;, &lt;span class="str"&gt;"checked"&lt;/span&gt; };&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsChecked(&lt;span class="kwrd"&gt;this&lt;/span&gt; IWebElement element)&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; attribute = element.GetAttribute(&lt;span class="str"&gt;"checked"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; Checked.Contains(attribute, DefaultComparer);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SetChecked(&lt;span class="kwrd"&gt;this&lt;/span&gt; IWebElement element)&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!element.IsChecked())&lt;/pre&gt;
&lt;pre class="alt"&gt;            element.Click();&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SetUnchecked(&lt;span class="kwrd"&gt;this&lt;/span&gt; IWebElement element)&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (element.IsChecked())&lt;/pre&gt;
&lt;pre class="alt"&gt;            element.Click();&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; StringComparison DefaultComparison = &lt;/pre&gt;
&lt;pre class="alt"&gt;        StringComparison.InvariantCultureIgnoreCase;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; IWebElement GetOptionByValue(&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt; IWebElement element, &lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;string&lt;/span&gt; value)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; element.GetOption(&lt;/pre&gt;
&lt;pre&gt;            o =&amp;gt; value.Equals(o.GetAttribute(&lt;span class="str"&gt;"value"&lt;/span&gt;), DefaultComparison));&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; IWebElement GetOptionByText(&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt; IWebElement element, &lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;string&lt;/span&gt; text)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; element.GetOption(o =&amp;gt; text.Equals(o.Text, DefaultComparison));&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; IWebElement GetOption(&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt; IWebElement element, &lt;/pre&gt;
&lt;pre&gt;        Func&amp;lt;IWebElement, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt; predicate)&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; element&lt;/pre&gt;
&lt;pre class="alt"&gt;            .FindElements(By.CssSelector(&lt;span class="str"&gt;"option"&lt;/span&gt;))&lt;/pre&gt;
&lt;pre&gt;            .FirstOrDefault(predicate);&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;b&gt;Unit Tests&lt;/b&gt;&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; WebElementExtensionTests : IDisposable&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; IWebDriver Driver { &lt;span class="kwrd"&gt;get&lt;/span&gt;; &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;set&lt;/span&gt;; }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; WebElementExtensionTests()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        Driver = &lt;span class="kwrd"&gt;new&lt;/span&gt; ChromeDriver(&lt;span class="str"&gt;"C:/Code/Drivers"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;        Driver.Url = &lt;span class="str"&gt;"file:///C:/Code/WebDriverTests/TestPage.htm"&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Dispose()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        Driver.Dispose();&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    [Fact]&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RadioTests()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; e1 = Driver.FindElement(By.Id(&lt;span class="str"&gt;"r1"&lt;/span&gt;));&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; e2 = Driver.FindElement(By.Id(&lt;span class="str"&gt;"r2"&lt;/span&gt;));&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        IsNotSelected(e1);&lt;/pre&gt;
&lt;pre class="alt"&gt;        IsSelected(e2);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        e1.Click();&lt;/pre&gt;
&lt;pre&gt;        IsSelected(e1);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        e2.Click();&lt;/pre&gt;
&lt;pre class="alt"&gt;        IsNotSelected(e1);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; IsSelected(IWebElement element)&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        Assert.True(element.IsSelected());&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; IsNotSelected(IWebElement element)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        Assert.False(element.IsSelected());&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    [Fact]&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CheckboxTests()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; e1 = Driver.FindElement(By.Id(&lt;span class="str"&gt;"c1"&lt;/span&gt;));&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; e2 = Driver.FindElement(By.Id(&lt;span class="str"&gt;"c2"&lt;/span&gt;));&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        IsNotChecked(e1);&lt;/pre&gt;
&lt;pre class="alt"&gt;        IsChecked(e2);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        e1.Click();&lt;/pre&gt;
&lt;pre&gt;        IsChecked(e1);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        e1.Click();&lt;/pre&gt;
&lt;pre class="alt"&gt;        IsNotChecked(e1);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; IsChecked(IWebElement element)&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        Assert.True(element.IsChecked());&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; IsNotChecked(IWebElement element)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        Assert.False(element.IsChecked());&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    [Fact]&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OptionTests()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; e1 = Driver.FindElement(By.Id(&lt;span class="str"&gt;"s1"&lt;/span&gt;));&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; option1 = e1.GetOptionByValue(&lt;span class="str"&gt;"a"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; option2 = e1.GetOptionByValue(&lt;span class="str"&gt;"b"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        IsNotSelected(option1);&lt;/pre&gt;
&lt;pre class="alt"&gt;        IsSelected(option2);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        option1.Click();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        IsSelected(option1);&lt;/pre&gt;
&lt;pre&gt;        IsNotSelected(option2);&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    [Fact]&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ToggleCheckedTests()&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; e1 = Driver.FindElement(By.Id(&lt;span class="str"&gt;"c1"&lt;/span&gt;));&lt;/pre&gt;
&lt;pre class="alt"&gt;        IsNotChecked(e1);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        e1.SetChecked();&lt;/pre&gt;
&lt;pre&gt;        IsChecked(e1);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        e1.SetChecked();&lt;/pre&gt;
&lt;pre class="alt"&gt;        IsChecked(e1);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        e1.SetUnchecked();&lt;/pre&gt;
&lt;pre&gt;        IsNotChecked(e1);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        e1.SetUnchecked();&lt;/pre&gt;
&lt;pre class="alt"&gt;        IsNotChecked(e1);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;b&gt;TestPage.htm&lt;/b&gt;&lt;/p&gt;

&lt;pre style="background-color: white"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;html&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;body&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;p&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;select &lt;/span&gt;&lt;span style="color: #FF0000;"&gt;id&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="s1"&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;option &lt;/span&gt;&lt;span style="color: #FF0000;"&gt;value&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="a"&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;Ant&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;option&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;option &lt;/span&gt;&lt;span style="color: #FF0000;"&gt;value&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="b"&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; selected&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="selected"&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;Bird&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;option&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;select&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;p&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;p&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;input &lt;/span&gt;&lt;span style="color: #FF0000;"&gt;id&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="r1"&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; type&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="radio"&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; name&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="r"&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; value&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="c"&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;/&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;Cat&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;br&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;input &lt;/span&gt;&lt;span style="color: #FF0000;"&gt;id&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="r2"&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; type&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="radio"&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; name&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="r"&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; value&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="d"&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; checked&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="checked"&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;/&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;Dog
&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;p&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;p&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;input &lt;/span&gt;&lt;span style="color: #FF0000;"&gt;id&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="c1"&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; type&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="checkbox"&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; name&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="vehicle"&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; value&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="e"&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;/&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;Elephant&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;br&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;input &lt;/span&gt;&lt;span style="color: #FF0000;"&gt;id&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="c2"&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; type&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="checkbox"&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; name&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="vehicle"&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; value&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="f"&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; checked&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;="checked"&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;/&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;Fox 
&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;p&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;body&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;html&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;

&lt;a style="float:right" rev="vote-for" href="http://dotnetshoutout.com/Form-Extensions-for-Selenium-20-WebDriver"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Fwww.tomdupont.net%2F2013%2F01%2Fwebelement-form-extensions-for-webdriver.html" style="border:0px"/&gt;&lt;/a&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/2514174170848558220/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2013/01/webelement-form-extensions-for-webdriver.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/2514174170848558220?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/2514174170848558220?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2013/01/webelement-form-extensions-for-webdriver.html" title="WebElement Form Extensions for WebDriver" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;AkUGQXg8fCp7ImA9WhNUEkU.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-3944517657406940275</id><published>2013-01-03T23:13:00.000-08:00</published><updated>2013-01-04T00:30:20.674-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-01-04T00:30:20.674-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Emulators" /><category scheme="http://www.blogger.com/atom/ns#" term="DOS" /><category scheme="http://www.blogger.com/atom/ns#" term="Master of Orion" /><category scheme="http://www.blogger.com/atom/ns#" term="DosBox Turbo" /><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><category scheme="http://www.blogger.com/atom/ns#" term="GOG" /><title>How To: Play GOG Games on Android with DosBox Turbo</title><content type="html">&lt;p&gt;&lt;b&gt;Good Old Games&lt;/b&gt;&lt;/p&gt;

&lt;img style="float:right; width:190px; border:0px" src="https://sites.google.com/site/tdupont750/DosBox_Turbo_for_Android.png"&gt;

&lt;p&gt;If you like classic games, then &lt;a href="http://www.gog.com/" target="blank"&gt;GOG is the online game retailer&lt;/a&gt; for you. Not only do they have a great selection of retro and modern games, but best of all they are provided &lt;a href="http://en.wikipedia.org/wiki/Digital_rights_management" target="_blank"&gt;DRM&lt;/a&gt; free.&lt;/p&gt;

&lt;p&gt;Many of the old DOS games that GOG sells come preconfigured to run &lt;a href="http://www.dosbox.com/" target="blank"&gt;DOSBox&lt;/a&gt; behind the scenes. For those of you not familiar with DOSBox, it is the leading open source DOS emulator.&lt;/p&gt;

&lt;p&gt;This is great because GOG can offer the original game experience without having to modify any of the game files or their content. Also, this allows users to run those same games on any platform that has a port of DOSBox available!&lt;/p&gt;

&lt;p&gt;&lt;b&gt;DosBox Turbo for Android&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;There are three DOS emulators available on Android, the best of which (by far) is &lt;a href="https://sites.google.com/site/dosboxturbo/" target="_blank"&gt;DosBox Turbo&lt;/a&gt;. It costs approximately $3 dollars, but I assure you that it is worth every penny. It is feature rich, stable, and fast.&lt;/p&gt;

&lt;p style="text-align:center"&gt;&lt;a href="https://play.google.com/store/apps/details?id=com.fishstix.dosbox&amp;hl=en" target="_blank"&gt;DosBox Turbo on the Google Play Store&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally there is a free app called DosBox Manager that helps manage your DosBox configuration profiles for game or program that you wish to run. This is extremely useful and I strongly suggest that you get it, especially because (as mentioned before) it is free!&lt;/p&gt;

&lt;p style="text-align:center"&gt;&lt;a href="https://play.google.com/store/apps/details?id=com.fishstix.dosboxlauncher" target="_blank"&gt;DosBox Manager on the Google Play Store&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Installation &amp; Configuration&lt;/b&gt;&lt;/p&gt;

&lt;ol start="1"&gt;&lt;li&gt;&lt;i&gt;Install Android Applications&lt;/i&gt;&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;Simply install the two applications, DosBox Turbo amd DosBox Manager, from the Google Play store.&lt;/p&gt;

&lt;ol start="2"&gt;&lt;li&gt;&lt;i&gt;Get GOG Games&lt;/i&gt;&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;Purchase, download, and install your desired &lt;a href="http://www.gog.com/catalogue" target="_blank"&gt;GOG games&lt;/a&gt; onto your computer. Not all GOG games use DOSBox, thus not all GOG games will run on Android; here is a &lt;a href="http://www.dosbox.com/wiki/GOG_games_that_use_DOSBox" target="_blank"&gt;list of games GOG games that use DOSBox&lt;/a&gt;.&lt;/p&gt;

&lt;ol start="3"&gt;&lt;li&gt;&lt;i&gt;Copy GOG Games to Android&lt;/i&gt;&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;Connect your android device to your computer, create a DOS folder at the root of your storage, and then copy your GOG games to there. Note: You do not have to copy the DOSBox folder.&lt;/p&gt;

&lt;p&gt;Here is an example of where I installed &lt;a href="http://www.gog.com/gamecard/master_of_orion_1_2" target="_blank"&gt;Master of Orion&lt;/a&gt; on my computer, and which folders I copied to my ASUS Transformer tablet.&lt;/p&gt;

&lt;p style="text-align:center"&gt;&lt;a href="https://sites.google.com/site/tdupont750/Android_DosBox_Copy_Orion.png" target="_blank"&gt;&lt;img style="width: 425px" src="https://sites.google.com/site/tdupont750/Android_DosBox_Copy_Orion_t.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol start="4"&gt;&lt;li&gt;&lt;i&gt;Configure DosBox Manager&lt;/i&gt;&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;If you are using DosBox Manager, then you will never have to launch the DosBox Turbo application directly. Once your games are copied over, launch DosBox Manager so that you can create profiles for your games.&lt;/p&gt;

&lt;ol start="1" type="a"&gt;&lt;li&gt;&lt;i&gt;Copy DosBox Profile&lt;/i&gt;&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;Copy the "Default" DosBox configuration by clicking and holding down on the icon. When prompted, select "Copy Profile" and enter the new name of your game; in my example this would be "Master of Orion".&lt;/p&gt;

&lt;ol start="2" type="a"&gt;&lt;li&gt;&lt;i&gt;Configure DosBox Profile&lt;/i&gt;&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;This is by far the most complicated step. Click and hold down on the new configuration file, and when prompted select "Edit Configuration". Each game configuration could be different, but there are at least 2 or 3 steps that will always need to be updated.&lt;/p&gt;

&lt;p&gt;First, scroll down in the configuration and enable "Screen Scaling". This will allow your screen resolution to scale up to the full screen size of your Android device.&lt;/p&gt;

&lt;p&gt;Second, for a game like Master of Orion, I would suggest setting your "Mouse Tracking" option to "Absolute (experimental)". This will allow you to click on the screen like a touch screen instead of moving the mouse around like a touch pad. Note: This may not be ideal for all gaming experiences.&lt;/p&gt;

&lt;p&gt;Third, and this is the most important step, we must edit the Autoexec to launch your game! Select the "DosBox Settings" sub-menu, and then select "Autoexec". Here we can enter a series of commands that will be automatically executed whenever this DosBox profile launches. Here are the commands to launch Master of Orion from the directory that I copied it's files to earlier:&lt;/p&gt;

&lt;pre&gt;mount c: /storage/sdcard0/
c:
cd: dos/orion
orion.exe&lt;/pre&gt;

&lt;p&gt;That's it, you are done! Click "OK" and back out of the menu until you return to the DosBox Manager home screen.&lt;/p&gt;

&lt;p style="text-align:center"&gt;
&lt;a href="https://sites.google.com/site/tdupont750/Configure_DosBox_Manager_Profile.png" target="_blank"&gt;&lt;img style="width: 200px" src="https://sites.google.com/site/tdupont750/Configure_DosBox_Manager_Profile_t.png"&gt;&lt;/a&gt;
&amp;nbsp;
&lt;a href="https://sites.google.com/site/tdupont750/Edit_Autoexec_Orion.png" target="_blank"&gt;&lt;img style="width: 200px" src="https://sites.google.com/site/tdupont750/Edit_Autoexec_Orion_t.png"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;ol start="3" type="a"&gt;&lt;li&gt;&lt;i&gt;Set DosBox Profile Icon&lt;/i&gt;&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;This step is completely optional, but I like to set Profile Icons for my games. Click and hold down again on your game profile, select "Change Icon", and then navigate to and select whichever image you would like to be your profile icon.&lt;/p&gt;

&lt;ol start="5"&gt;&lt;li&gt;&lt;i&gt;Launch Your Game&lt;/i&gt;&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;You are now ready to play GOG games on your Android device. Simply click on the game Profile that you would like to play, and have fun!&lt;/p&gt;

&lt;p style="text-align:center"&gt;
&lt;a href="https://sites.google.com/site/tdupont750/DosBox_Turbo_Master_of_Orion.png" target="_blank"&gt;&lt;img style="width: 200px" src="https://sites.google.com/site/tdupont750/DosBox_Turbo_Master_of_Orion_t.png"&gt;&lt;/a&gt;
&amp;nbsp;
&lt;a href="https://sites.google.com/site/tdupont750/DosBox_Turbo_Master_Of_Orion_2.png" target="_blank"&gt;&lt;img style="width: 200px" src="https://sites.google.com/site/tdupont750/DosBox_Turbo_Master_Of_Orion_2_t.png"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/3944517657406940275/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2013/01/how-to-play-gog-games-on-android-with.html#comment-form" title="15 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/3944517657406940275?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/3944517657406940275?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2013/01/how-to-play-gog-games-on-android-with.html" title="How To: Play GOG Games on Android with DosBox Turbo" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>15</thr:total></entry><entry gd:etag="W/&quot;CUUMSHg9eSp7ImA9WhNVGUo.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-366470335082703070</id><published>2012-12-31T08:23:00.000-08:00</published><updated>2012-12-31T09:01:29.661-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-12-31T09:01:29.661-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="CookieContainer" /><category scheme="http://www.blogger.com/atom/ns#" term="HttpWebRequest" /><title>CookieContainer for HttpWebRequest</title><content type="html">&lt;img src="https://sites.google.com/site/tdupont750/cookiejar.jpg" style="float:right; margin-left:10px; width:120px"&gt;

&lt;p&gt;Happy New Year!&lt;/p&gt;

&lt;p&gt;Are you making a series of HttpWebRequests where you need to persist cookies? For example, perhaps you are experiencing an infinite series of authentication hops. Don't worry, this is very easy to resolve by using the System.Net.CookieContainer class.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;xUnit Example&lt;/b&gt;&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;[Theory]&lt;/pre&gt;
&lt;pre&gt;[InlineData(&lt;span class="str"&gt;"http://www.yahoo.com"&lt;/span&gt;, 0)]&lt;/pre&gt;
&lt;pre class="alt"&gt;[InlineData(&lt;span class="str"&gt;"http://www.google.com"&lt;/span&gt;, 2)]&lt;/pre&gt;
&lt;pre&gt;[InlineData(&lt;span class="str"&gt;"http://www.bing.com"&lt;/span&gt;, 8)]&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CookieJarCount(&lt;span class="kwrd"&gt;string&lt;/span&gt; requestUriString, &lt;span class="kwrd"&gt;int&lt;/span&gt; expectedCookieCount)&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; request = (HttpWebRequest) HttpWebRequest.Create(requestUriString);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="rem"&gt;// Create a CookieContainer and assign it to the request.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; cookieJar = &lt;span class="kwrd"&gt;new&lt;/span&gt; CookieContainer(); &lt;/pre&gt;
&lt;pre class="alt"&gt;    request.CookieContainer = cookieJar;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="rem"&gt;// Make the request like normal.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; response = (HttpWebResponse) request.GetResponse();&lt;/pre&gt;
&lt;pre class="alt"&gt;    Assert.Equal(HttpStatusCode.OK, response.StatusCode);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="rem"&gt;// Let's see how many cookies are in the cookie jar!&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    Assert.Equal(expectedCookieCount, cookieJar.Count);&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;a style="float:right" rev="vote-for" href="http://dotnetshoutout.com/CookieContainer-for-HttpWebRequest"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://www.tomdupont.net/2012/12/cookiecontainer-for-httpwebrequest.html" style="border:0px"/&gt;&lt;/a&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/366470335082703070/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2012/12/cookiecontainer-for-httpwebrequest.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/366470335082703070?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/366470335082703070?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2012/12/cookiecontainer-for-httpwebrequest.html" title="CookieContainer for HttpWebRequest" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;Dk4CRnk-eyp7ImA9WhNVF08.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-2060458574309085177</id><published>2012-12-28T12:02:00.000-08:00</published><updated>2012-12-28T12:02:47.753-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-12-28T12:02:47.753-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Emulators" /><category scheme="http://www.blogger.com/atom/ns#" term="DOS" /><category scheme="http://www.blogger.com/atom/ns#" term="SNES" /><category scheme="http://www.blogger.com/atom/ns#" term="Android" /><category scheme="http://www.blogger.com/atom/ns#" term="NES" /><title>Best Emulators for Android</title><content type="html">&lt;img style="float:right; width:125px; margin-left:10px; border:0px" src="https://sites.google.com/site/tdupont750/AndroidSanta.png"&gt;

&lt;p&gt;Happy Holidays!&lt;/p&gt;

&lt;p&gt;If you were lucky and got an Android tablet or phone this holiday season, congratulations! If you got a bunch of gift cards and you don't know what to do with them, I strongly suggest that you take a look at the &lt;a href="https://play.google.com/store/devices/details?id=nexus_7_32gb" target="_blank"&gt;Nexus 7!&lt;/a&gt; (Although I personally have an &lt;a href="http://eee.asus.com/en/transformer-prime/" target="_blank"&gt;ASUS Transformer Prime.&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Best of all, if you like old school video games, you can emulate just about anything made in the 90s on modern Android devices! (Don't know what emulators are? Here is a helpful article about &lt;a href="http://fantasyanime.com/emuhelp/index.htm" target="_blank"&gt;video game emulation for newbies&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Please remember that &lt;a href="http://en.wikipedia.org/wiki/Console_emulator#Legal_issues" target="_blank"&gt;emulation is legal&lt;/a&gt;, so long as you own the console and game that you are trying to emulate. As always, please play nice and play fair!&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The Best Emulators&lt;/b&gt;&lt;/p&gt;

&lt;table border="1" cellspacing="0" cellpadding="4" style="width:100%"&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Emulator&lt;/th&gt;
&lt;th&gt;Extras&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SNES&lt;/td&gt;
&lt;td&gt;&lt;a href="http://www.explusalpha.com/home/snes9x-ex" target="_blank"&gt;Snes9x EX&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NES&lt;/td&gt;
&lt;td&gt;&lt;a href="http://sourceforge.net/projects/nesoid/" target="_blank"&gt;Nesoid&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Game Boy Advance&lt;/td&gt;
&lt;td&gt;&lt;a href="http://sourceforge.net/projects/gameboid/" target="_blank"&gt;GameBoid&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Game Boy Color&lt;/td&gt;
&lt;td&gt;&lt;a href="http://sourceforge.net/projects/gbcoid/" target="_blank"&gt;GBCoid&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sega Genesis&lt;/td&gt;
&lt;td&gt;&lt;a href="https://play.google.com/store/apps/details?id=ca.halsafar.genesisdroid" target="_blank"&gt;GENPlusDroid&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Free with Ads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PlayStation&lt;/td&gt;
&lt;td&gt;&lt;a href="https://play.google.com/store/apps/details?id=com.emulator.fpse" target="_blank"&gt;FPse for Android&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="http://www.emuparadise.me/biosfiles/bios.html" target="_blank"&gt;Requires a BIOS file&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;$3.63&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DOS&lt;/td&gt;
&lt;td&gt;&lt;a href="https://play.google.com/store/apps/details?id=com.fishstix.dosbox" target="_blank"&gt;DosBox Turbo&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://play.google.com/store/apps/details?id=com.fishstix.dosboxlauncher" target="_blank"&gt;DosBox Manager&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;$3.49&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;&lt;b&gt;How To Install&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;You must manually install applications that are not purchased from the Google Play Store. Fortunately this is very easy to do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Copy the .APK file to your Android device.&lt;/li&gt;
&lt;li&gt;Allow installations from "Unknown sources".
&lt;br&gt;(Settings &gt; Security &gt; Device Administration &gt; Unknown sources)&lt;/li&gt;
&lt;li&gt;Navigate to the APK file using a file manager.
&lt;br&gt;(I prefer &lt;a href="https://play.google.com/store/apps/details?id=com.metago.astro" target="_blank"&gt;ASTRO File Manager&lt;/a&gt;.)&lt;/li&gt;
&lt;li&gt;Launch the APK file, and accept the installation of application.&lt;/li&gt;
&lt;li&gt;For safety, I recommend you then undo your "Unknown sources" setting.&lt;/li&gt; 
&lt;/ol&gt;

&lt;p&gt;All you have to do know is copy your ROMs to your device, and then select them from the App.&lt;/p&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/2060458574309085177/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2012/12/best-emulators-for-android.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/2060458574309085177?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/2060458574309085177?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2012/12/best-emulators-for-android.html" title="Best Emulators for Android" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DEMGRnY4fyp7ImA9WhNXFUQ.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-1617648370494731437</id><published>2012-11-28T20:26:00.000-08:00</published><updated>2012-12-03T20:47:07.837-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-12-03T20:47:07.837-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="XNA" /><category scheme="http://www.blogger.com/atom/ns#" term="Windows 8" /><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio" /><title>XNA and Visual Studio 2012 on Windows 8</title><content type="html">&lt;p&gt;Microsoft does not always make it easy to use their latest toys.&lt;/p&gt;

&lt;p style="float:right"&gt;&lt;img style="width:200px; margin-left:20px;"  src="https://sites.google.com/site/tdupont750/RipXna.jpg"&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The Good&lt;/b&gt;&lt;br&gt;
I recently rebuilt my computer and, wanting to stay on the forefront of technology, I of course installed Windows 8 and Visual Studio 2012. Both products come with a series of pros and cons, but the quick boot up times of Windows 8 and the parallel builds of Visual Studio 2012 make them both winners in my book.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The Bad&lt;/b&gt;&lt;br&gt;
That being said, the first project that I wanted to work on after rebuilding my machine was a small XNA game that I have been writing for a while now. Unfortunately that XNA has been unofficially retired, and Microsoft is not making it easy for people to continue using their product.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;And The Ugly&lt;/b&gt;&lt;br&gt;
To use XNA on Windows 8 you must first download and install Games for Windows LIVE Redistributable. Then you must install XNA Studio into Visual Studio 2010 and manually copy the installed assemblies to Visual Studio 2012.&lt;/p&gt;

&lt;p&gt;Here are the details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a target="_blank" href="http://stackoverflow.com/questions/12849107/how-to-install-the-xna-game-studio-4-0-in-windows-8"&gt;How to install the XNA Game Studio 4.0 in Windows 8?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://stackoverflow.com/questions/10881005/how-to-install-xna-game-studio-on-visual-studio-2012"&gt;How to install XNA game studio on Visual Studio 2012?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope that helps,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/1617648370494731437/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2012/11/xna-and-visual-studio-2012-on-windows-8.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/1617648370494731437?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/1617648370494731437?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2012/11/xna-and-visual-studio-2012-on-windows-8.html" title="XNA and Visual Studio 2012 on Windows 8" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CUcMRnY4fCp7ImA9WhNVGUo.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-4435873432044920662</id><published>2012-11-17T12:57:00.001-08:00</published><updated>2012-12-31T08:58:07.834-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-12-31T08:58:07.834-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="jQuery" /><title>jQuery Refresh Page Extension</title><content type="html">&lt;p&gt;There are three scenarios when a web page refreshes:&lt;p&gt;

&lt;ol&gt;
&lt;li&gt;Honors your cache (does not make resource requests).&lt;/li&gt;
&lt;li&gt;Verifies your cache (causes resources to generate 304s).&lt;/li&gt;
&lt;li&gt;Ignores your cache (causes resources to generate 200s).
&lt;/ol&gt;

&lt;p&gt;For a simple page refresh you want your webpage to generate as few server requests as possible. There any many ways to refresh a page in JavaScript, however they can all have different and sometimes undesirable results. Let's look some code snippets of the aforementioned scenarios in reverse order.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;3. Ignore Cache&lt;/b&gt;&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;window.location.reload(&lt;span class="kwrd"&gt;true&lt;/span&gt;);&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This scenario is not usually necessary unless you know that the resources of your page have been updated. Also, using a good minification framework is probably a better way of ensuring that your clients always consume the latest resources with every request.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;2. Verify Cache&lt;/b&gt;&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;window.location.reload();&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This is obvious similar to the first call, only we are calling &lt;a href="http://www.w3schools.com/jsref/met_loc_reload.asp" target="_blank"&gt;an override of the reload method&lt;/a&gt; that tells the browser to respect cache. However, this will still cause a series of 304 requests!&lt;/p&gt;

&lt;p&gt;&lt;b&gt;1. Honor Cache&lt;/b&gt;&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;window.location.href = window.location.href;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This is obviously a very simple way to refresh the page, and it will honor cache without forcing 304 requests. However, this will not work if your includes a hash tag.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;jQuery Plugin&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;This little jQuery plugin will refresh the page and try to cause as few resource requests as possible.&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;(function($) {&lt;/pre&gt;
&lt;pre&gt;    $.refreshPage = refreshPage;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;/pre&gt;
&lt;pre&gt;    function refreshPage(reload) {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (reload === &lt;span class="kwrd"&gt;true&lt;/span&gt;) {&lt;/pre&gt;
&lt;pre&gt;            window.location.reload(&lt;span class="kwrd"&gt;true&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; i = window.location.href.indexOf(&lt;span class="str"&gt;'#'&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (i === -1) {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="rem"&gt;// There is no hash tag, refresh the page.&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;            window.location.href = window.location.href;&lt;/pre&gt;
&lt;pre&gt;        } &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (i === window.location.href.length - 1) {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="rem"&gt;// The hash tag is at the end, just strip it.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;            window.location.href = window.location.href.substring(i);&lt;/pre&gt;
&lt;pre class="alt"&gt;        } &lt;span class="kwrd"&gt;else&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="rem"&gt;// There is a legit hash tag, reload the page.&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;            window.location.reload(&lt;span class="kwrd"&gt;false&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;})(jQuery);&lt;/pre&gt;
&lt;/div&gt;

&lt;a style="float:right" rev="vote-for" href="http://dotnetshoutout.com/jQuery-Refresh-Page-Extension"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://www.tomdupont.net/2012/11/jquery-refresh-page-extension.html" style="border:0px"/&gt;&lt;/a&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/4435873432044920662/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2012/11/jquery-refresh-page-extension.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/4435873432044920662?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/4435873432044920662?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2012/11/jquery-refresh-page-extension.html" title="jQuery Refresh Page Extension" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;A0UGRH8-fip7ImA9WhNQFUs.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-3052384037740044558</id><published>2012-10-26T08:21:00.000-07:00</published><updated>2012-11-21T23:27:05.156-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-11-21T23:27:05.156-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Unit Testing" /><category scheme="http://www.blogger.com/atom/ns#" term="xUnit" /><category scheme="http://www.blogger.com/atom/ns#" term="Resharper" /><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio" /><category scheme="http://www.blogger.com/atom/ns#" term="MSTest" /><title>xUnit Visual Studio Integration</title><content type="html">&lt;img src="https://sites.google.com/site/tdupont750/xunitbook.gif" style="float:right;margin-left:10px;width:145px;"&gt;

&lt;p&gt;Good news, everyone! It is actually very easy to get xUnit completely integrated with Visual Studio. You only need to install two plugins...&lt;/p&gt;
 
&lt;p&gt;&lt;b&gt;VS2010 - xUnit Test Runner Extension&lt;/b&gt;&lt;/p&gt;
 
&lt;p&gt;This will support running tests with a Visual Studio test project.&lt;br&gt;
This includes all of the VS features, such as code coverage!&lt;/p&gt;
 
&lt;p&gt;&lt;a href="https://github.com/quetzalcoatl/xvsr10/downloads" target="_blank"&gt;https://github.com/quetzalcoatl/xvsr10/downloads&lt;/a&gt;&lt;/p&gt;
 
&lt;p&gt;&lt;b&gt;ReSharper - xUnit Contrib Plugin&lt;/b&gt;&lt;/p&gt;
 
&lt;p&gt;This will allow ReSharper to detect and run xUnit tests.&lt;/p&gt;
 
&lt;p&gt;&lt;a href="http://xunitcontrib.codeplex.com/releases/view/92101" target="_blank"&gt;http://xunitcontrib.codeplex.com/releases/view/92101&lt;/a&gt;&lt;br&gt;
&lt;a href="http://devnet.jetbrains.net/docs/DOC-280" target="_blank"&gt;(If you are still running Resharper 6, then you will need the latest: v6.1.1)&lt;/a&gt;&lt;/p&gt;
 
&lt;p&gt;&lt;b&gt;Team Build (TFS) Integration&lt;/b&gt;&lt;/p&gt;
 
&lt;p&gt;Integrating with xUnit your Team Foundation Server is a very tricky proposition, but it can be done. That, however, is a (rather long) blog post for another day!&lt;/p&gt;

&lt;a style="float:right" rev="vote-for" href="http://dotnetshoutout.com/xUnit-Visual-Studio-Integration"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://www.tomdupont.net/2012/10/xunit-visual-studio-integration.html" style="border:0px"/&gt;&lt;/a&gt;

&lt;p&gt;Enjoy,&lt;br&gt;
Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/3052384037740044558/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2012/10/xunit-visual-studio-integration.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/3052384037740044558?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/3052384037740044558?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2012/10/xunit-visual-studio-integration.html" title="xUnit Visual Studio Integration" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DkEGQ306fyp7ImA9WhNTGUs.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-8644323011872204104</id><published>2012-10-22T20:38:00.000-07:00</published><updated>2012-10-22T20:57:02.317-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-10-22T20:57:02.317-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="IIS" /><category scheme="http://www.blogger.com/atom/ns#" term="Configuration" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><title>How to Unlock a Configuration Section from IIS Manager</title><content type="html">&lt;p&gt;
&lt;b&gt;HTTP Error 500.19 - Internal Server Error&lt;/b&gt;&lt;br&gt;
The requested page cannot be accessed because the related configuration data for the page is invalid.
&lt;/p&gt;

&lt;p&gt;
This configuration section cannot be used at this path. This happens when the section is locked at a parent level. Locking is either by default (overrideModeDefault="Deny"), or set explicitly by a location tag with overrideMode="Deny" or the legacy allowOverride="false".
&lt;/p&gt;

&lt;p&gt;
If you have ever experienced this problem then you probably have also experienced the fun of digging through your system configuration files to find where to unlock the related authentication sections. This is, to say the least, &lt;i&gt;not fun.&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Did you know that you can unlock configuration sections from IIS Manager?&lt;/b&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Launch IIS Manager.&lt;/li&gt;
&lt;li&gt;Select your Connection's home page.&lt;/li&gt;
&lt;li&gt;Open the Configuration Editor under Management.&lt;/li&gt;
&lt;li&gt;Navigate to the section that you need to unlock.&lt;/li&gt;
&lt;li&gt;Look to the right Action pane and &lt;i&gt;click unlock!&lt;/i&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p style="text-align:center;"&gt;
&lt;a href="http://sites.google.com/site/tdupont750/UnlockSection.png" target="_blank"&gt;
&lt;img src="http://sites.google.com/site/tdupont750/UnlockSection.png" style="width: 500px;"&gt;
&lt;/a&gt;
&lt;/p&gt;

&lt;a rev="vote-for" href="http://dotnetshoutout.com/How-to-Unlock-a-Configuration-Section-from-IIS-Manager" style="float:right;"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://www.tomdupont.net/2012/10/how-to-unlock-configuration-section.html" style="border:0px"/&gt;&lt;/a&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/8644323011872204104/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2012/10/how-to-unlock-configuration-section.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/8644323011872204104?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/8644323011872204104?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2012/10/how-to-unlock-configuration-section.html" title="How to Unlock a Configuration Section from IIS Manager" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C08FSX06fCp7ImA9WhJbFk4.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-2744044878962642081</id><published>2012-09-25T20:46:00.000-07:00</published><updated>2012-09-25T20:56:58.314-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-09-25T20:56:58.314-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="LinqToSql" /><category scheme="http://www.blogger.com/atom/ns#" term="Unity" /><category scheme="http://www.blogger.com/atom/ns#" term="Dependency Injection" /><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="ORM" /><title>Func Injection in Unity</title><content type="html">&lt;img style="float:right;margin-left:15px" src="http://sites.google.com/site/tdupont750/microsoft_patterns_practices.gif"&gt;

&lt;p&gt;Let your container be your factory. :)&lt;/p&gt;

&lt;p&gt;If you are using LinqToSql and dependency injection, then you have probably created a factory with which you create DataContexts. But what if you could just let your IOC Container do that work for you? You can!&lt;/p&gt;

&lt;p&gt;If you are using Unity then you can inject a Func&amp;lt;T&amp;gt; of any registered type. Unity will automatically bind the injected Func to the container's resolve method, thus preserving the resource Lifetime Manager.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Example Code&lt;/b&gt;&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; FuncInjectionTests&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    [Fact]&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; TransientLifetimeFuncIsThreadsafe()&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; container = &lt;span class="kwrd"&gt;new&lt;/span&gt; UnityContainer();&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        container&lt;/pre&gt;
&lt;pre class="alt"&gt;            .RegisterType&amp;lt;IUserService, UserService&amp;gt;(&lt;/pre&gt;
&lt;pre&gt;                &lt;span class="kwrd"&gt;new&lt;/span&gt; ContainerControlledLifetimeManager())&lt;/pre&gt;
&lt;pre class="alt"&gt;            .RegisterType&amp;lt;IDataContext, DataContext&amp;gt;(&lt;/pre&gt;
&lt;pre&gt;                &lt;span class="kwrd"&gt;new&lt;/span&gt; TransientLifetimeManager());&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; parallelOptions = &lt;span class="kwrd"&gt;new&lt;/span&gt; ParallelOptions {MaxDegreeOfParallelism = 100};&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        Parallel.For(0, 1000, parallelOptions, i =&amp;gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; userService = container.Resolve&amp;lt;IUserService&amp;gt;();&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            Parallel.For(0, 1000, parallelOptions, j =&amp;gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;            {&lt;/pre&gt;
&lt;pre&gt;                userService.Update();&lt;/pre&gt;
&lt;pre class="alt"&gt;            });&lt;/pre&gt;
&lt;pre&gt;        });&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        Assert.Equal(1, UserService.Count);&lt;/pre&gt;
&lt;pre class="alt"&gt;        Assert.Equal(1000000, DataContext.Count);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IUserService&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; Update();&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IDataContext : IDisposable&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; UpdateUser();&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; UserService : IUserService&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Count;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; Func&amp;lt;IDataContext&amp;gt; _dataContextFactory;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; UserService(Func&amp;lt;IDataContext&amp;gt; dataContextFactory)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        _dataContextFactory = dataContextFactory;&lt;/pre&gt;
&lt;pre&gt;        Interlocked.Increment(&lt;span class="kwrd"&gt;ref&lt;/span&gt; Count);&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;using&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; dataContext = _dataContextFactory())&lt;/pre&gt;
&lt;pre&gt;            dataContext.UpdateUser();&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; DataContext : IDataContext&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Count;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; DataContext()&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        Interlocked.Increment(&lt;span class="kwrd"&gt;ref&lt;/span&gt; Count);&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; UpdateUser()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        Trace.WriteLine(Thread.CurrentThread.ManagedThreadId + &lt;span class="str"&gt;" - "&lt;/span&gt; + Count);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Dispose()&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;a rev="vote-for" href="http://dotnetshoutout.com/Func-Injection-in-Unity"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://www.tomdupont.net/2012/09/func-injection-in-unity.html" style="border:0px;float:right"/&gt;&lt;/a&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/2744044878962642081/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2012/09/func-injection-in-unity.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/2744044878962642081?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/2744044878962642081?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2012/09/func-injection-in-unity.html" title="Func Injection in Unity" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;A0cFRHk8eCp7ImA9WhJUF08.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-2370261704478762934</id><published>2012-09-15T10:10:00.000-07:00</published><updated>2012-09-15T10:10:15.770-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-09-15T10:10:15.770-07:00</app:edited><title>The problem with the Nintendo eShop</title><content type="html">&lt;p&gt;Dear Nintendo,&lt;/p&gt;

&lt;p&gt;I am a huge fan. I have owned every single Nintendo console that has ever been released (except for the Virtual Boy, naturally). You have made so many great games, and I love them all. I enjoy Mario, Zelda, Metroid, Donkey Kong, pretty much all of your franchises.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;So, why won't you let me buy these games from you again?&lt;/i&gt;&lt;/p&gt;

&lt;p style="text-align:center"&gt;
&lt;img src="http://sites.google.com/site/tdupont750/nintendo_eshop_fry.png"&gt;
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The Nintendo 3DS eShop and the Ambassador Program&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;The eShop is Nintendo's online store and digital distribution system for the Nintendo 3DS. With it they sell small games, old emulated virtual console games, and they just recently selling complete feature titles via the eShop. It's a great idea that has been very successful, and it shows that Nintendo is trying to keep up with the times. Other companies, such as Valve and Apple, have made the vast majority of their profits in recent years by take percentages from their digital distribution services, Steam and iTunes respectively. &lt;/p&gt;

&lt;p&gt;After the very sluggish start for 3DS sales, Nintendo inevitably had to commit to a price cut for their new hardware. To try and appease consumers who had already paid full price for their 3DS, Nintendo gifted early adopters with the "Ambassador Program". This granted all 3DS owners, whom had purchased their console prior to August 11th 2011, 20 free downloadable titles via the Nintendo eShop. These included 10 NES titles, and 10 GBA titles.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Nintendo has shown us that they can easily emulate software from previous consoles on the Nintendo 3DS.&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;The Current Predicament&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Now that it is far too late to gain access to the Ambassador program, you can no longer download many of the virtual titles that were offered. Not even by PAYING for them! Not only are they completely unavailable now, but Nintendo has stated that they "currently have no plans to release those titles again."&lt;/p&gt;

&lt;p&gt;When I look at the eShop's very small and weak game lineup, I find myself feeling very frustrated. Nintendo has so many classic games that I would love to pay for again and play again, and yet they refuse to release them to customers.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Nintendo is refusing to sell us software that they have already released; and they wonder why they are losing money for the first time in their company's history?&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Nintendo eShop by the Numbers&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Nintendo has been criticized for their handling both their Wii and DS eShops poorly, and I feel that this is rightly so. They do not have consistent new releases, they do a poor job of announcing and scheduling their releases, and worst of all they offer a very limited number of available titles.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Number of NES Games: &lt;a href="http://en.wikipedia.org/wiki/List_of_Nintendo_Entertainment_System_games" target="_blank"&gt;707&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Number of GameBoy Games: &lt;a href="http://en.wikipedia.org/wiki/List_of_games_for_the_original_Game_Boy" target="_blank"&gt;528&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Number of GBC Games: &lt;a href="http://en.wikipedia.org/wiki/List_of_Game_Boy_Color_games" target="_blank"&gt;549&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Number of SNES Games: &lt;a href="http://en.wikipedia.org/wiki/List_of_Nintendo_Entertainment_System_games" target="_blank"&gt;786&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Number of GBA Games: &lt;a href="http://en.wikipedia.org/wiki/List_of_Game_Boy_Advance_games" target="_blank"&gt;1017&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;&lt;i&gt;Number of eShop Virtual Console Games: &lt;a href="http://en.wikipedia.org/wiki/List_of_Virtual_Console_games_for_Nintendo_3DS_(North_America)" target="_blank"&gt;68&lt;/a&gt;&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Being that Nintendo owns the rights to their own games, and that they have already build the infrastructure to support selling and distributing these games on a global scale, I find these numbers to be embarrassing! Nintendo has already done all of the heavy lifting, why not put that system to better use?&lt;/p&gt;

&lt;p&gt;&lt;i&gt;A good analogy would be that Nintendo has build a transcontinental rail road system across the United States, but is only running a dozen trains on it.&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Arguments Against Selling More Games&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;As I understand it, there are only three arguments against loading up a service like the eShop with an arsenal of downloadable titles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Oversaturation&lt;br&gt;
- By releasing too many games on the virtual console you could obscure smaller titles and reduce their sales.&lt;br&gt;
+ I fail to see this as a problem, for as long as people are buy these old games (that would otherwise not be selling at all) you are still making money where you would have been before.&lt;br&gt;
+ Additionally, there are over 1500 games available on Steam, and I have not seen Valve complain about that.
&lt;/li&gt;
&lt;li&gt;Cross Promotional Releases&lt;br&gt;
- When a new game in a series is about to come out, there is often a sales spike for the previous games. This is partly because of the promotional advertise of the new game, but also because games often want to go back brush on the old games to prepare for next title, as well as some people just literally can not wait to play the game again.&lt;br&gt;
+ Make some sales is always advantageous over making no sales, and sales, discounts, or bundles can work to help bolster sales prior to a game launch.&lt;br&gt;
+ Again we can look to Steam for an example of how to make this work. Value uses every trick in the book to help promote new game sales, and it works out very well for them.
&lt;/li&gt;
&lt;li&gt;Maintenance&lt;br&gt;
- The more games you release, the more games you have to provide support for.&lt;br&gt;
+ Consoles are a controlled environment, there are not going to be issues with driver versions or third party software. All Nintendo has to do is support their emulators, which should (for the most part) be a one size fits all product. I can not see the cost in maintenance for this being overwhelming. &lt;br&gt;
+ If open source software projects can do it in their spare time after work, then you Nintendo can too.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;b&gt;Summary: Nintendo should put more games on the Virtual Console.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;So please, shut up and take my money,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/2370261704478762934/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2012/09/the-problem-with-nintendo-eshop.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/2370261704478762934?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/2370261704478762934?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2012/09/the-problem-with-nintendo-eshop.html" title="The problem with the Nintendo eShop" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>1</thr:total></entry><entry gd:etag="W/&quot;DkEBSXY9eyp7ImA9WhJVF04.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-3533694089108687765</id><published>2012-08-30T21:14:00.000-07:00</published><updated>2012-09-03T21:57:38.863-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-09-03T21:57:38.863-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Unit Testing" /><category scheme="http://www.blogger.com/atom/ns#" term="xUnit" /><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="WebDriver" /><title>WebDrivers in Parallel</title><content type="html">&lt;p&gt;Here is a post that is long over due, and is finally getting published by request!&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Concurrent WebDrivers&lt;/b&gt;&lt;/p&gt;

&lt;img src="http://sites.google.com/site/tdupont750/browsers.png" style="float:right; margin-left:20px"&gt;

&lt;p&gt;A WebDriver is not thread safe, but it is not required to be a singleton either. If you instantiate multiple drivers, they can all be run at the same time. If you cast a series of drivers into a collection of the IWebDriver interface, and then throw that into a Parallel ForEach, you have yourself one fun toy to play with!&lt;/p&gt;

&lt;p&gt;&lt;b&gt;So what are some uses of this?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Admittedly it is not a particularly common or practical use case to have multiple automated browser sessions running at the same time, but it can still come in handy. One fun application is to test website concurrency. You can do a minor load test of a webpage, or your can have two sessions trying to race each other for a limited resource.&lt;/p&gt;

&lt;p&gt;...also, running WebDrivers in parallel can make for a &lt;i&gt;killer demo!&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Sample Code (xUnit Test)&lt;/b&gt;&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ParallelDemo : IDisposable&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; IList&amp;lt;IWebDriver&amp;gt; Drivers { &lt;span class="kwrd"&gt;get&lt;/span&gt;; &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;set&lt;/span&gt;; }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; ParallelDemo()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        Drivers = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;IWebDriver&amp;gt;&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;new&lt;/span&gt; InternetExplorerDriver(),&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;new&lt;/span&gt; FirefoxDriver(),&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;new&lt;/span&gt; ChromeDriver()&lt;/pre&gt;
&lt;pre&gt;        };&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Dispose()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; driver &lt;span class="kwrd"&gt;in&lt;/span&gt; Drivers)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            driver.Close();&lt;/pre&gt;
&lt;pre&gt;            driver.Dispose();&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    [Fact]&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ParallelSearch()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        Parallel.ForEach(Drivers, SearchForTom);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SearchForTom(IWebDriver driver)&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        driver.Url = &lt;span class="str"&gt;"https://www.google.com/#q=tom+dupont"&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; firstResult = driver.FindElement(By.CssSelector(&lt;span class="str"&gt;"h3 &amp;gt; a.l"&lt;/span&gt;));&lt;/pre&gt;
&lt;pre&gt;        Assert.Contains(&lt;span class="str"&gt;"Tom DuPont .NET"&lt;/span&gt;, firstResult.Text);&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;a style="float:right" rev="vote-for" href="http://dotnetshoutout.com/Running-WebDrivers-in-Parallel"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://www.tomdupont.net/2012/08/webdrivers-in-parallel.html" style="border:0px"/&gt;&lt;/a&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/3533694089108687765/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2012/08/webdrivers-in-parallel.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/3533694089108687765?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/3533694089108687765?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2012/08/webdrivers-in-parallel.html" title="WebDrivers in Parallel" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;D0YASH0zfCp7ImA9WhJVEU8.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-1549575167227468482</id><published>2012-08-18T12:44:00.000-07:00</published><updated>2012-08-27T20:39:09.384-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-08-27T20:39:09.384-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="LinqToSql" /><category scheme="http://www.blogger.com/atom/ns#" term="Future Queries" /><category scheme="http://www.blogger.com/atom/ns#" term="Lazy" /><category scheme="http://www.blogger.com/atom/ns#" term="NuGet" /><category scheme="http://www.blogger.com/atom/ns#" term="ORM" /><title>LinqToSql Futures</title><content type="html">&lt;p&gt;Batch queries are crucial feature of any good ORM...including LinqToSql!&lt;/p&gt;

Future queries are an unobtrusive and easy to use way of batching database queries into a lazy loaded data structures. Future queries were originally a &lt;a href="http://ayende.com/blog/3979/nhibernate-futures" target="_blank"&gt;feature of NHibernate&lt;/a&gt;, and have since been ported to other ORMs. However I am currently working on a project where I do not have access to those tools.&lt;/p&gt;

&lt;img style="float:right; margin-left:10px"  src="http://sites.google.com/site/tdupont750/LinqToSqlFutures.png"&gt;

&lt;p&gt;Thus I created LinqToSql.Futures, a simple extension that adds batched futures queries to LinqToSql.&lt;/p&gt;

&lt;p style="font-size:1.1em"&gt;&lt;b&gt;Using Future Queries&lt;/b&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get the LinqToSqlFutures NuGet package.&lt;/li&gt;
&lt;li&gt;Extend your DataContext to implement IFutureDataContext. (This is optional, see below!)&lt;/li&gt;
&lt;li&gt;Use future queries!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To batch queries together, simply call the ToFuture extension method on your IQueryables, this will return a Lazy collection of entities. The first time that one of the Lazy collections is accessed, all of the pending queries will be batched and executed together.&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;[Fact]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ToFuture()&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="rem"&gt;// SimpleDataContext Implements IFutureDataContext &lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;using&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; dataContext = &lt;span class="kwrd"&gt;new&lt;/span&gt; SimpleDataContext())&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        Lazy&amp;lt;IList&amp;lt;Person&amp;gt;&amp;gt; people = dataContext.Persons&lt;/pre&gt;
&lt;pre&gt;            .Where(p =&amp;gt; p.FirstName == &lt;span class="str"&gt;"Tom"&lt;/span&gt; || p.FirstName == &lt;span class="str"&gt;"Cat"&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;            .ToFuture();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        Lazy&amp;lt;IList&amp;lt;Pet&amp;gt;&amp;gt; pets = dataContext.Pets&lt;/pre&gt;
&lt;pre&gt;            .Where(p =&amp;gt; p.Name == &lt;span class="str"&gt;"Taboo"&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;            .ToFuture();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="rem"&gt;// Single database call!&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        Assert.Equal(2, people.Value.Count);&lt;/pre&gt;
&lt;pre class="alt"&gt;        Assert.Equal(1, pets.Value.Count);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;To see the future queries working, you can use SqlProfiler to capture the batch query:

&lt;p&gt;&lt;img src="http://sites.google.com/site/tdupont750/LinqToSqlFuturesProfiler.png"&gt;&lt;/p&gt;

&lt;p style="font-size:1.1em"&gt;&lt;b&gt;Extending Your DataContext&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;To use the code above, you need only extend your generated DataContext to implement the IFutureDataContext interface (which consists of a mere one property). Additionally, the sample code below overrides the Dispose method to optimize query disposal.&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SimpleDataContext : IFutureDataContext&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Dispose(&lt;span class="kwrd"&gt;bool&lt;/span&gt; disposing)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (_futureCollection != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            _futureCollection.Dispose();&lt;/pre&gt;
&lt;pre&gt;            _futureCollection = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;base&lt;/span&gt;.Dispose(disposing);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; IFutureCollection _futureCollection;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; IFutureCollection FutureCollection&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;get&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_futureCollection == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;                _futureCollection = &lt;span class="kwrd"&gt;this&lt;/span&gt;.CreateFutureCollection();&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; _futureCollection;&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Do you not have access to extend your DataContext? No problem...&lt;/p&gt;

&lt;p style="font-size:1.1em"&gt;&lt;b&gt;Alternative Consumption&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Your DataContext does not need to implement IFutureDataContext to use future queries. You can also create a FutureCollection and pass that into the ToFuture method. This will provide the future queries with a batch context.&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;[Fact]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; FutureCollection()&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;using&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; dataContext = &lt;span class="kwrd"&gt;new&lt;/span&gt; SimpleDataContext())&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;using&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; futureCollcetion = dataContext.CreateFutureCollection())&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        Lazy&amp;lt;IList&amp;lt;Person&amp;gt;&amp;gt; people = dataContext.Persons&lt;/pre&gt;
&lt;pre&gt;            .Where(p =&amp;gt; p.FirstName == &lt;span class="str"&gt;"Tom"&lt;/span&gt; || p.FirstName == &lt;span class="str"&gt;"Cat"&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;            .ToFuture(futureCollcetion);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        Lazy&amp;lt;IList&amp;lt;Pet&amp;gt;&amp;gt; pets = dataContext.Pets&lt;/pre&gt;
&lt;pre&gt;            .Where(p =&amp;gt; p.Name == &lt;span class="str"&gt;"Taboo"&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;            .ToFuture(futureCollcetion);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="rem"&gt;// Single database call!&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        Assert.Equal(2, people.Value.Count);&lt;/pre&gt;
&lt;pre class="alt"&gt;        Assert.Equal(1, pets.Value.Count);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p style="font-size:1.1em"&gt;&lt;b&gt;Links&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;If you enjoy the future queries or need to extend them, then please feel free to download the source from GitHub.&lt;p&gt;

&lt;p&gt;
&lt;a target="_blank" href="https://github.com/tdupont750/LinqToSql.Futures/"&gt;LinqToSql.Futures on GitHub&lt;/a&gt;&lt;br&gt;
&lt;a target="_blank" href="http://nuget.org/packages/LinqToSqlFutures"&gt;LinqToSql.Futures on NuGet&lt;/a&gt;
&lt;/p&gt;

&lt;a style="float:right" rev="vote-for" href="http://dotnetshoutout.com/Batched-Future-Queries-for-LinqToSql-available-via-NuGet"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Fwww.tomdupont.net%2F2012%2F08%2Flinqtosql-futures.html" style="border:0px"/&gt;&lt;/a&gt;

&lt;p&gt;
Enjoy,&lt;br&gt;
Tom
&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/1549575167227468482/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2012/08/linqtosql-futures.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/1549575167227468482?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/1549575167227468482?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2012/08/linqtosql-futures.html" title="LinqToSql Futures" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CkIDRH8_fSp7ImA9WhJXEUU.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-8248566861000354946</id><published>2012-07-29T23:53:00.000-07:00</published><updated>2012-08-05T08:29:35.145-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-08-05T08:29:35.145-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Unity" /><category scheme="http://www.blogger.com/atom/ns#" term="Dependency Injection" /><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="Lazy" /><title>Lazy Unity Injection</title><content type="html">&lt;p&gt;Adapting a legacy project to use proper Dependency Injection can be difficult.&lt;/p&gt;

&lt;img style="float:right" src="https://sites.google.com/site/tdupont750/LazyTree.png"&gt;

&lt;p&gt;Often times your services can not be singletons, and then those dependencies cause chains of other services to require transient lifetimes. Sometimes these service dependency trees can grow deep, and their initialization can become quite expensive. If you are working with a website, those big trees can add up and cost a lot of time and memory with every request.&lt;/p&gt;

&lt;p&gt;One way to trim a deep or expensive dependency tree is to inject Lazy&lt;T&gt; types of your services.&lt;/p&gt;

&lt;p&gt;Lazy injection will prevent an optional resource from being instantiated until it is actually needed. While this is not a scenario that you want to architect your application into voluntarily, it can be a crucial performance optimization. Have you ever taken a memory dump of your website and found thousands of services floating in memory? I have, and let me assure you, it's not pretty!&lt;/p&gt;



&lt;p&gt;&lt;b&gt;LazyExtension for Unity&lt;/b&gt;&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; LazyExtension : UnityContainerExtension&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Initialize()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        Context.Policies.Set&amp;lt;IBuildPlanPolicy&amp;gt;(&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;new&lt;/span&gt; LazyBuildPlanPolicy(), &lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(Lazy&amp;lt;&amp;gt;));&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; LazyBuildPlanPolicy : IBuildPlanPolicy&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; BuildUp(IBuilderContext context)&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (context.Existing != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; container = context.NewBuildUp&amp;lt;IUnityContainer&amp;gt;();&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; typeToBuild = context.BuildKey.Type.GetGenericArguments()[0];&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; nameToBuild = context.BuildKey.Name;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; lazyType = &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(Lazy&amp;lt;&amp;gt;).MakeGenericType(typeToBuild);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; func = GetType()&lt;/pre&gt;
&lt;pre class="alt"&gt;                .GetMethod(&lt;span class="str"&gt;"CreateResolver"&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;                .MakeGenericMethod(typeToBuild)&lt;/pre&gt;
&lt;pre class="alt"&gt;                .Invoke(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt;[] { container, nameToBuild });&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            context.Existing = Activator.CreateInstance(lazyType, func);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            DynamicMethodConstructorStrategy.SetPerBuildSingleton(context);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; Func&amp;lt;T&amp;gt; CreateResolver&amp;lt;T&amp;gt;(&lt;/pre&gt;
&lt;pre class="alt"&gt;            IUnityContainer currentContainer, &lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; nameToBuild)&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; () =&amp;gt; currentContainer.Resolve&amp;lt;T&amp;gt;(nameToBuild);&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;



&lt;p&gt;&lt;b&gt;Unit Tests&lt;/b&gt;&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; ITestClass&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;int&lt;/span&gt; HighFive();&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; TestClass : ITestClass&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; InstanceCount = 0;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; TestClass()&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        Interlocked.Increment(&lt;span class="kwrd"&gt;ref&lt;/span&gt; InstanceCount);&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; HighFive()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; 5;&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;[TestFixture]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; TestFixture&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    [Test]&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;using&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; container = &lt;span class="kwrd"&gt;new&lt;/span&gt; UnityContainer())&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;            container.RegisterType&amp;lt;ITestClass, TestClass&amp;gt;();&lt;/pre&gt;
&lt;pre&gt;            container.AddNewExtension&amp;lt;LazyExtension&amp;gt;();&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; testClass1 = container.Resolve&amp;lt;Lazy&amp;lt;ITestClass&amp;gt;&amp;gt;();&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            Assert.AreEqual(&lt;span class="kwrd"&gt;false&lt;/span&gt;, testClass1.IsValueCreated);&lt;/pre&gt;
&lt;pre class="alt"&gt;            Assert.AreEqual(0, TestClass.InstanceCount);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            Assert.AreEqual(5, testClass1.Value.HighFive());&lt;/pre&gt;
&lt;pre&gt;            Assert.AreEqual(&lt;span class="kwrd"&gt;true&lt;/span&gt;, testClass1.IsValueCreated);&lt;/pre&gt;
&lt;pre class="alt"&gt;            Assert.AreEqual(1, TestClass.InstanceCount);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; testClass2 = container.Resolve&amp;lt;Lazy&amp;lt;ITestClass&amp;gt;&amp;gt;();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;            Assert.AreEqual(&lt;span class="kwrd"&gt;false&lt;/span&gt;, testClass2.IsValueCreated);&lt;/pre&gt;
&lt;pre&gt;            Assert.AreEqual(1, TestClass.InstanceCount);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            Assert.AreEqual(5, testClass2.Value.HighFive());&lt;/pre&gt;
&lt;pre class="alt"&gt;            Assert.AreEqual(&lt;span class="kwrd"&gt;true&lt;/span&gt;, testClass2.IsValueCreated);&lt;/pre&gt;
&lt;pre&gt;            Assert.AreEqual(2, TestClass.InstanceCount);&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;


&lt;a style="float:right" href="http://www.dotnetkicks.com/kick/?url=http://www.tomdupont.net/2012/07/lazy-unity-injection.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http://www.tomdupont.net/2012/07/lazy-unity-injection.html" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/8248566861000354946/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2012/07/lazy-unity-injection.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/8248566861000354946?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/8248566861000354946?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2012/07/lazy-unity-injection.html" title="Lazy Unity Injection" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;Ck4EQHs7eCp7ImA9WhJSE0U.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-7758369054717257165</id><published>2012-07-03T22:44:00.001-07:00</published><updated>2012-07-03T22:48:21.500-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-07-03T22:48:21.500-07:00</app:edited><title>Game Design: How to Begin an RPG</title><content type="html">&lt;style&gt;
table.how-to-begin td:first-child {
   width: 110px;
   text-align: center;
   vertical-align: top;
}
&lt;/style&gt;

&lt;p&gt;Great games peak player interest in 10 minutes or less.&lt;/p&gt;

&lt;p&gt;The opening moments are crucial to any story. Not only must an introduction immediately engage the audience, but it must also provide incentive to stick around for the entirety of the narrative. If a game does not spark interest quickly, the player will put it down and forget about it.&lt;/p&gt;

&lt;div style="text-align:center"&gt;
&lt;img src="https://sites.google.com/site/tdupont750/ct-plot-diagram.png"&gt;
&lt;/div&gt;

&lt;p&gt;With regard to story, games must adhere to the same dramatic structure as any other medium, but with the additional challenge of including gameplay. A good game must be able to quickly move the player to an interesting inciting incident without sacrificing the fun of gameplay to get there.&lt;/p&gt;

&lt;p&gt;To help us learn from our past, I have created a simple test to see if a game starts out well. Then, using this test, let us a review some past games to see how well they did!&lt;/p&gt;

&lt;p&gt;&lt;b&gt;10 minutes into the game, ask yourself the following questions:&lt;/b&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Who am I?&lt;/li&gt;
&lt;li&gt;What am I doing?&lt;/li&gt;
&lt;li&gt;Why do I care?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Final Fantasy 6&lt;/b&gt;&lt;/p&gt;

&lt;table class="how-to-begin"&gt;
&lt;tr&gt;
&lt;td&gt;Who am I?&lt;/td&gt;
&lt;td&gt;I am a witch, one of the only magic users in the world.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What am I doing?&lt;/td&gt;
&lt;td&gt;I am driving a giant mech suit as I invade a town to capture some magic artifact.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Why do I care?&lt;/td&gt;
&lt;td&gt;As the opening narrative briefly explained, this artifact could return magic to the world and solidify the empires global consolidation of power. Also, I am a witch driving a mech, that is really cool!&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;Final Fantasy 6 opens perfectly. It has about 60 seconds of pitching the worlds history to you in the form of narration, during which it never drops any proper nouns such as names, dates, or locations, but in the background we are seeing characters that we will come to learn about later. It is a great setup in that it is quick and vague, yet it will pay off later. After that we have the beautiful and artistic scene of the mechs approaching Narshe, it sets the tone and atmosphere of the game well, but is literally completely skippable. After that we are dropped into combat as an overpowered group of warriors driving giant mech suites and destroying a town...ya, that is just FUN.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Verdict: Perfect Opening&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Tales of the Abyss&lt;/b&gt;&lt;/p&gt;

&lt;table class="how-to-begin"&gt;
&lt;tr&gt;
&lt;td&gt;Who am I?&lt;/td&gt;
&lt;td&gt;Some rich kid who gets headaches.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What am I doing?&lt;/td&gt;
&lt;td&gt;Wandering around my mansion, being scolded for talking to commoners, complaining that I am bored.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Why do I care?&lt;/td&gt;
&lt;td&gt;I don't.&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;Tales of the Abyss uses the cliche JRPG trope of an angsty teenager coming of age, only this time it is even worse because our protagonist is both rich and sheltered. When the inciting incident finally does occur a half hour into the game, it has no explanation or setup and it puts the lead characters motivations completely in question. All that the main character does for the first 30 minutes of the game is complain about how he wants to get out of the house, and then all he wants to do is go straight back home? Also, was there supposed to be a setup for an actual story hidden somewhere in there?&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Verdict: Boring Introduction&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Super Mario RPG: Legend of the Seven Stars&lt;/b&gt;&lt;/p&gt;

&lt;table class="how-to-begin"&gt;
&lt;tr&gt;
&lt;td&gt;Who am I?&lt;/td&gt;
&lt;td&gt;I am Mario!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What am I doing?&lt;/td&gt;
&lt;td&gt;I am invading Bowser's castle! I am punching Goombas! I am jumping on Dry Bones! I am saving the princess!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Why do I care?&lt;/td&gt;
&lt;td&gt;I have played Mario in a dozen games before, but never in an RPG where I could actually beat up my enemies in isometric 3D!&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;This is the perfect example of how to leverage your existing IP when making an RPG. Players already have an emotional attachment to the characters and world that you are placing them in, so take full advantage of that. If a player has spent hundreds of hours trying to save a princess in the past, open the game up so that they are immediately feeling that reward. Then, after they are hooked, you can change to story to involve clouds that wear pants and talking dolls.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Verdict: Brilliant Opening&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Golden Sun: Dark Dawn&lt;/b&gt;&lt;/p&gt;

&lt;table class="how-to-begin"&gt;
&lt;tr&gt;
&lt;td&gt;Who am I?&lt;/td&gt;
&lt;td&gt;I don't know yet. I could be the same characters from the first game, or I could be their kids, I have not played as anyone yet!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What am I doing?&lt;/td&gt;
&lt;td&gt;I am listening to Garret and Issac groan on and on about how their world has changed. I played the first games and I don't even remember any of the places, events, or characters that they are name dropping.  I do not know what I am doing now, much less what I will be doing in another 10 minutes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Why do I care?&lt;/td&gt;
&lt;td&gt;Nothing has even happened yet; so far we have only talked about what is going on in the current scene, which seems to have nothing to do with the plot.&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;Dark Dawn falls into the age old sequel pitfall of trying to explain too much about the games that came before it. This exposition drags on for far too long and only serves to alienate the player from the game itself. When you can "play" a game for 20 minutes, and never actually get to play the game, something is very wrong.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Verdict: Horrendous Exposition&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Cthulhu Saves the World&lt;/b&gt;&lt;/p&gt;

&lt;table class="how-to-begin"&gt;
&lt;tr&gt;
&lt;td&gt;Who am I?&lt;/td&gt;
&lt;td&gt;I am Cthulhu.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What am I doing?&lt;/td&gt;
&lt;td&gt;I am going to bring insanity and destruction to the worl...oh, wait...I have to save the world? WTF?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Why do I care?&lt;/td&gt;
&lt;td&gt;Whether we know it or not Lovecraftian lore has permeated our culture; now we are being asked to comically flip our preconceived notions on their head, and man is it funny.&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;Cthulhu Saves the World takes the opposite approach to most modern RPGs: it is less dark and less serious than the source material which it is based on. Humor is a very powerful and seemly underrated tool in the game market, especially among RPGs. Players do not always want to see the world end. They do not need to watch characters brood. Sometimes gamers just want to have FUN. It amazes me that a little indie company like Zeboyd Games can figure that out, while a giant like Square Enix seems to have completely forgotten it.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Verdict: Hilarious Setup&lt;/i&gt;&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Which other games can these opening questions be applied to?&lt;/p&gt;

&lt;p&gt;Seiken Densetsu 3?&lt;br&gt;
Final Fantasy Tactics?&lt;br&gt;
World of Warcraft?&lt;/p&gt;

&lt;p&gt;Game on,&lt;br&gt;
Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/7758369054717257165/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2012/07/game-design-how-to-begin-rpg.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/7758369054717257165?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/7758369054717257165?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2012/07/game-design-how-to-begin-rpg.html" title="Game Design: How to Begin an RPG" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C0UAR3w8eCp7ImA9WhJTFUo.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-7380361263828266235</id><published>2012-06-16T11:33:00.000-07:00</published><updated>2012-06-24T13:54:06.270-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-06-24T13:54:06.270-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="BlockingQueue" /><category scheme="http://www.blogger.com/atom/ns#" term="BlockingCollection" /><title>.NET BlockingQueue</title><content type="html">&lt;p&gt;Task.Factory.StartNew is great, but often abused.&lt;/p&gt;

&lt;p&gt;Do you need to make a call that could take a long time to complete, but you don't care about the results? If so, then you need to make an async call. Should you make these calls by constantly creating and starting new Tasks? No, as this could use up a lot of resouces, exhaust your thread pool, or possibly even tear down your app domain.&lt;/p&gt;

&lt;p&gt;I was recently introduced to System.Collections.Concurrent.BlockingCollection, and I absolutely love that class. However, 99% of my use cases with BlockingCollections are actually more specific to queuing. My solution: create a generic BlockingQueue!&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Simple File Example&lt;/b&gt;&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SimpleFile&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Path { &lt;span class="kwrd"&gt;get&lt;/span&gt;; &lt;span class="kwrd"&gt;set&lt;/span&gt;; }&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Contents { &lt;span class="kwrd"&gt;get&lt;/span&gt;; &lt;span class="kwrd"&gt;set&lt;/span&gt;; }&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SimpleFileQueue : BlockingQueue&amp;lt;SimpleFile&amp;gt;&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; SimpleFileQueue(&lt;span class="kwrd"&gt;int&lt;/span&gt; threadCount) : &lt;span class="kwrd"&gt;base&lt;/span&gt;(threadCount) { }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ProcessModel(SimpleFile model)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        System.IO.File.WriteAllText(model.Path, model.Contents);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; HandleException(Exception ex)&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="rem"&gt;// TODO: Log me!&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SimpleFileExample&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; SimpleFileQueue Queue = &lt;span class="kwrd"&gt;new&lt;/span&gt; SimpleFileQueue(3);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; EnqueueSimpleFile(&lt;span class="kwrd"&gt;string&lt;/span&gt; path, &lt;span class="kwrd"&gt;string&lt;/span&gt; content)&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        Queue.Enqueue(&lt;span class="kwrd"&gt;new&lt;/span&gt; SimpleFile&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            Path = path,&lt;/pre&gt;
&lt;pre class="alt"&gt;            Contents = content&lt;/pre&gt;
&lt;pre&gt;        });&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;b&gt;BlockingQueue&amp;lt;T&amp;gt; Implementation&lt;/b&gt;&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; BlockingQueue&amp;lt;T&amp;gt; : IDisposable&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="preproc"&gt;#region&lt;/span&gt; Private Members&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; _disposed;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; CancellationTokenSource _tokenSource;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; BlockingCollection&amp;lt;T&amp;gt; _collection;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; Task[] _tasks;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="preproc"&gt;#region&lt;/span&gt; Public Properties&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Count&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;get&lt;/span&gt; { &lt;span class="kwrd"&gt;return&lt;/span&gt; _collection.Count; }&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsCanceled&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;get&lt;/span&gt; { &lt;span class="kwrd"&gt;return&lt;/span&gt; _tokenSource.IsCancellationRequested; }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsCompleted&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;get&lt;/span&gt; { &lt;span class="kwrd"&gt;return&lt;/span&gt; _tasks.All(t =&amp;gt; t.IsCompleted); }&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="preproc"&gt;#region&lt;/span&gt; Constructor &amp;amp; Destructor&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; BlockingQueue(&lt;span class="kwrd"&gt;int&lt;/span&gt; threadCount)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        _tokenSource = &lt;span class="kwrd"&gt;new&lt;/span&gt; CancellationTokenSource();&lt;/pre&gt;
&lt;pre&gt;            &lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; queue = &lt;span class="kwrd"&gt;new&lt;/span&gt; ConcurrentQueue&amp;lt;T&amp;gt;();&lt;/pre&gt;
&lt;pre&gt;        _collection = &lt;span class="kwrd"&gt;new&lt;/span&gt; BlockingCollection&amp;lt;T&amp;gt;(queue);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        _tasks = &lt;span class="kwrd"&gt;new&lt;/span&gt; Task[threadCount];&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;for&lt;/span&gt;(&lt;span class="kwrd"&gt;var&lt;/span&gt; i=0; i&amp;lt;threadCount; i++)&lt;/pre&gt;
&lt;pre&gt;            _tasks[i] = Task.Factory.StartNew(ProcessQueue);&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    ~BlockingQueue()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        Dispose(&lt;span class="kwrd"&gt;true&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="preproc"&gt;#region&lt;/span&gt; Abstracts&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; HandleException(Exception ex);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ProcessModel(T model);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="preproc"&gt;#region&lt;/span&gt; Methods&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Enqueue(T model)&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (IsCompleted)&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Exception(&lt;span class="str"&gt;"BlockingQueue has been Completed"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (IsCanceled)&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Exception(&lt;span class="str"&gt;"BlockingQueue has been Canceled"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        _collection.Add(model);&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Cancel()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!IsCanceled)&lt;/pre&gt;
&lt;pre&gt;            _tokenSource.Cancel(&lt;span class="kwrd"&gt;false&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CancelAndWait()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        Cancel();&lt;/pre&gt;
&lt;pre class="alt"&gt;        Task.WaitAll(_tasks);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ProcessQueue()&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        while (&lt;span class="kwrd"&gt;true&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;            {&lt;/pre&gt;
&lt;pre&gt;                &lt;span class="kwrd"&gt;var&lt;/span&gt; model = _collection.Take(_tokenSource.Token);&lt;/pre&gt;
&lt;pre class="alt"&gt;                ProcessModel(model);&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (OperationCanceledException)&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                &lt;span class="kwrd"&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class="alt"&gt;                HandleException(ex);&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class="alt"&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="preproc"&gt;#region&lt;/span&gt; IDisposable&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Dispose()&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        Dispose(&lt;span class="kwrd"&gt;false&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Dispose(&lt;span class="kwrd"&gt;bool&lt;/span&gt; finalizing)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (_disposed)&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        Cancel();&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!finalizing)&lt;/pre&gt;
&lt;pre class="alt"&gt;            GC.SuppressFinalize(&lt;span class="kwrd"&gt;this&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;        _disposed = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;a style="float:right" rev="vote-for" href="http://dotnetshoutout.com/NET-BlockingQueue"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://www.tomdupont.net/2012/06/net-blockingqueue.html" style="border:0px"/&gt;&lt;/a&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/7380361263828266235/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2012/06/net-blockingqueue.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/7380361263828266235?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/7380361263828266235?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2012/06/net-blockingqueue.html" title=".NET BlockingQueue" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;CkQCQn47cSp7ImA9WhVaEkU.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-8524713760719113274</id><published>2012-06-09T01:23:00.000-07:00</published><updated>2012-06-09T15:19:23.009-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-06-09T15:19:23.009-07:00</app:edited><title>Prometheus Review</title><content type="html">&lt;p&gt;I am a huge Alien fan, but I did not enjoy Prometheus.&lt;/p&gt;

&lt;p&gt;First, let's start on a good note: Prometheus is visually stunning, the cinematography is gorgeousness, the art and atmosphere are stellar, and the acting is top notch. Technically speaking, it is a very well made film.&lt;/p&gt;

&lt;p&gt;Unfortunately the story and screenplay are just f***ing terrible.&lt;/p&gt;

&lt;p&gt;The characters are shallow, the dialog is absolutely terrible, the pacing is inconsistent, and the plot is sloppy at best. There are countless elements in the film that get setup but yield absolutely no pay off. Worse still is how many bad plot points there are; things that are completely and utterly illogical or contradictory, and staring the audience right in the face.&lt;/p&gt;

&lt;p&gt;Movies do not need to resolve every plot point that they contain, they do not need to explain every event, nor do they need to answer every question that they raise. However this does not excuse plot holes, inconsistency, and bad writing.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Here are 150 unanswered questions that I had after watching Prometheus:&lt;/b&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If the space jockeys seeded life on Earth, how did people make cave paintings of them?&lt;/li&gt;
&lt;li&gt;What about the seventh piece of cave art was more compelling than the first six?&lt;/li&gt;
&lt;li&gt;Why is there a giant holographic display grid in a cargo bay?&lt;/li&gt;
&lt;li&gt;How does no one know why they are on this mission?&lt;/li&gt;
&lt;li&gt;What makes the main character an expert in the fields of archaeology, ancient civilizations, aliens, and astronomy?&lt;/li&gt;
&lt;li&gt;How did the main character convince one of the richest most powerful men in the world of anything by using a series of cave drawings?&lt;/li&gt;
&lt;li&gt;Why did the ship not scan the planet before going to land?&lt;/li&gt;
&lt;li&gt;How lucky would you have to get to just spot an alien building bu looking out the window?&lt;/li&gt;
&lt;li&gt;Why does everyone go out for their first expedition with only 6 hours of daylight left?&lt;/li&gt;
&lt;li&gt;How could anyone think that the pyramid was created naturally?&lt;/li&gt;
&lt;li&gt;How does the unsealed pyramid have a breathable atmosphere contained in it?&lt;/li&gt;
&lt;li&gt;Why is no one worried about taking off their helmets in the alien atmosphere?&lt;/li&gt;
&lt;li&gt;Why does no one ask the android to translate any markings?&lt;/li&gt;
&lt;li&gt;Where did the fresh goo on the wall come from?&lt;/li&gt;
&lt;li&gt;Why does no one ask the android how or why he activated the holographs?&lt;/li&gt;
&lt;li&gt;Why did the holographs play back that specific death scene?&lt;/li&gt;
&lt;li&gt;What were the space jockeys running from?&lt;/li&gt;
&lt;li&gt;Why did the advance automatic door not have a stop sensor like my primitive garage door?&lt;/li&gt;
&lt;li&gt;Why does the rock guy not take rock samples?&lt;/li&gt;
&lt;li&gt;Why do none of the scientists do anything remotely scientific?&lt;/li&gt;
&lt;li&gt;Why is there a giant head in the middle of the room?&lt;/li&gt;
&lt;li&gt;Why are the containers spaced around the room?&lt;/li&gt;
&lt;li&gt;Why after two thousand years are the containers just starting to ooze now?&lt;/li&gt;
&lt;li&gt;How do the two scientists with GPS and map get lost in the caves?&lt;/li&gt;
&lt;li&gt;Where did the freak storm come from?&lt;/li&gt;
&lt;li&gt;How do the same two guys not hear the radio transmission about the storm?&lt;/li&gt;
&lt;li&gt;Why do none of the crew direct them out of the caves?&lt;/li&gt;
&lt;li&gt;How does it take them 30 minute to realize they are lost, when everyone else made it back in less time?&lt;/li&gt;
&lt;li&gt;How does no one know that the other two didn't make it back, especially given that they took all the vehicles?&lt;/li&gt;
&lt;li&gt;Wasn't it supposed to be night time by now?&lt;/li&gt;
&lt;li&gt;What does the word quarantine mean in this universe?&lt;/li&gt;
&lt;li&gt;How do they know that the alien even has a nervous system that works like ours?&lt;/li&gt;
&lt;li&gt;Why would they want to fake the alien nervous system into thinking it is alive?&lt;/li&gt;
&lt;li&gt;Why do they stick that thing in the dead alien's ear to stimulate electricity?&lt;/li&gt;
&lt;li&gt;Why does waking up the brain also weak up the bacteria?&lt;/li&gt;
&lt;li&gt;Why does that make the head blow up?&lt;/li&gt;
&lt;li&gt;Why does no one do any more research on the blown up head?&lt;/li&gt;
&lt;li&gt;How is the DNA a 100% match if they are not human?&lt;/li&gt;
&lt;li&gt;If the DNA is a 100% match, did the space jockeys only seed human life on earth?&lt;/li&gt;
&lt;li&gt;If the storm was artificial or triggered by the humans, where did it go?&lt;/li&gt;
&lt;li&gt;Why is there a pile of dead space jockeys?&lt;/li&gt;
&lt;li&gt;What killed the pile of dead space jockeys?&lt;/li&gt;
&lt;li&gt;Where did the think that killed the dead space jockeys go?&lt;/li&gt;
&lt;li&gt;If the space jockey busted from the inside, what laid an egg in him?&lt;/li&gt;
&lt;li&gt;Where did the egg layer go?&lt;/li&gt;
&lt;li&gt;Where did the alien that hatched out of him go?&lt;/li&gt;
&lt;li&gt;Why does the captain ask where the two scientists are when they have a giant 3D map that shows exactly where they are?&lt;/li&gt;
&lt;li&gt;Why does no one send another probe to investigate the life form readings?&lt;/li&gt;
&lt;li&gt;Why does no one go to investigate the life form readings?&lt;/li&gt;
&lt;li&gt;Why does no one care about the life form readings?&lt;/li&gt;
&lt;li&gt;Why do the scared scientists go back to the room that scared them to go to sleep?&lt;/li&gt;
&lt;li&gt;Where did the biologist get that little blanket?&lt;/li&gt;
&lt;li&gt;Why do they think the alien worm is cute?&lt;/li&gt;
&lt;li&gt;Why does the alien worm have acid for blood?&lt;/li&gt;
&lt;li&gt;Why does the alien worm have unreasonably high blood pressure?&lt;/li&gt;
&lt;li&gt;How does the alien worm regrow its limbs?&lt;/li&gt;
&lt;li&gt;Where does the alien worm go after it kills the scientists?&lt;/li&gt;
&lt;li&gt;Why does no one see the video feed from the dead or dying scientists?&lt;/li&gt;
&lt;li&gt;How does no one notice the two scientists are dead?&lt;/li&gt;
&lt;li&gt;Why does the container have only one drop of black fluid if the other containers are oozing a gallon of goo apiece?&lt;/li&gt;
&lt;li&gt;Why would you freeze a bottle of wine?&lt;/li&gt;
&lt;li&gt;Why does talking about creating life piss off the main character so much?&lt;/li&gt;
&lt;li&gt;Why does the girl have sex with the captain?&lt;/li&gt;
&lt;li&gt;Why does the guy not tell anyone about having a worm in his eye?&lt;/li&gt;
&lt;li&gt;Why did the survey drone stop at the dead end door if it didn't tell anyone that it was at a door?&lt;/li&gt;
&lt;li&gt;Why did that drone detect life in an empty corridor?&lt;/li&gt;
&lt;li&gt;Why are the containers in the cargo bay not oozing like the other containers?&lt;/li&gt;
&lt;li&gt;Why are the containers in the cargo bay stacked differently than the other containers?&lt;/li&gt;
&lt;li&gt;Why does everyone stop caring about the other dead guys and the worms coming out of heads when another guy gets sick?&lt;/li&gt;
&lt;li&gt;Why does that guy not just take his helmet off if he want to die?&lt;/li&gt;
&lt;li&gt;If she is such a bad ass, why does that girl cry after using the flame thrower?&lt;/li&gt;
&lt;li&gt;Why does no one do an autopsy on the mutant body?&lt;/li&gt;
&lt;li&gt;How does the other mutant find the ship?&lt;/li&gt;
&lt;li&gt;Why did the other guy become a mutant?&lt;/li&gt;
&lt;li&gt;Why was he super strong, super fast, and super aggressive?&lt;/li&gt;
&lt;li&gt;Why does no one do an autopsy on the other mutant body?&lt;/li&gt;
&lt;li&gt;Why is David conducting a medical diagnosis of the main character instead of a doctor?&lt;/li&gt;
&lt;li&gt;Why does David need to decontaminate the cross, especially given that she is infected with an alien?&lt;/li&gt;
&lt;li&gt;Why doesn't the android just put the main character into cryosleep?&lt;/li&gt;
&lt;li&gt;How does the main character knock out the other two doctors?&lt;/li&gt;
&lt;li&gt;Why is the surgery capsule not programmed to work on women if it belongs to the other girl?&lt;/li&gt;
&lt;li&gt;If the surgery capsule is not programmed to work on women, how does it start working?&lt;/li&gt;
&lt;li&gt;How does the main character stay awake with all those pain killers?&lt;/li&gt;
&lt;li&gt;Why can the surgery machine not drug the patient?&lt;/li&gt;
&lt;li&gt;How do staples heal the tissue and stop the bleeding?&lt;/li&gt;
&lt;li&gt;How can the main character walk around after that surgery?&lt;/li&gt;
&lt;li&gt;How come no one cares that the main character just aborted an alien?&lt;/li&gt;
&lt;li&gt;Where did all of Weylands private medical staff come from?&lt;/li&gt;
&lt;li&gt;Weren't some of those doctors knocked unconscious by the main character just a few minutes ago?&lt;/li&gt;
&lt;li&gt;Why is Weyland played by a young guy in makeup if he is always old?&lt;/li&gt;
&lt;li&gt;What does it matter that the girl is Weyland's daughter?&lt;/li&gt;
&lt;li&gt;How does the captain know that this is a weapon facility?&lt;/li&gt;
&lt;li&gt;Why would a weapon facility have statues of giant heads?&lt;/li&gt;
&lt;li&gt;Why would the space jockeys leave a map that leads to a weapon facility?&lt;/li&gt;
&lt;li&gt;How can the main character go adventuring after that surgery?&lt;/li&gt;
&lt;li&gt;Why does that main character not care that the android killed her husband?&lt;/li&gt;
&lt;li&gt;Why does the android want to kill his maker, especially after helping keep him alive all movie?&lt;/li&gt;
&lt;li&gt;What is Weyland's plan when he meets the space jockey?&lt;/li&gt;
&lt;li&gt;Why do the space jockeys use flutes to unlock their computers?&lt;/li&gt;
&lt;li&gt;When did the android learn to speak space jockey?&lt;/li&gt;
&lt;li&gt;What did the android say to the space jockey?&lt;/li&gt;
&lt;li&gt;Why did that piss of the space jockey?&lt;/li&gt;
&lt;li&gt;Why did the space jockey wait for a few minutes before killing everyone?&lt;/li&gt;
&lt;li&gt;Why do bullets not hurt the space jockey?&lt;/li&gt;
&lt;li&gt;Why did no one bring a flame thrower?&lt;/li&gt;
&lt;li&gt;Why if the space jockey's mission was to kill all humans, was he asleep for thousands of years?&lt;/li&gt;
&lt;li&gt;Why, if hyper sleep is used for travel, was the space jockey asleep on a planet?&lt;/li&gt;
&lt;li&gt;Why is only one space jockey left alive?&lt;/li&gt;
&lt;li&gt;Why did the space jockey not care about any of the other space jockeys?&lt;/li&gt;
&lt;li&gt;Why does the space jockey immediately leave to destroy earth if he was arbitrarily woken up?&lt;/li&gt;
&lt;li&gt;How do they know the space jockey wanted to wipe out earth?&lt;/li&gt;
&lt;li&gt;How do they know the space jockey "changed his mind" about earth?&lt;/li&gt;
&lt;li&gt;Why would the space jockey want to wipe out earth?&lt;/li&gt;
&lt;li&gt;Why wouldn't the space jockey want to wipe out any other planets?&lt;/li&gt;
&lt;li&gt;Why does the space jockey not kill the main character?&lt;/li&gt;
&lt;li&gt;How can the main character run after that surgery?&lt;/li&gt;
&lt;li&gt;How did they not detect the giant launch doors two feet under the soil?&lt;/li&gt;
&lt;li&gt;Why does the girl decide that is the right time to go home and not earlier?&lt;/li&gt;
&lt;li&gt;Why does the flight crew decide to be suicidal heroes?&lt;/li&gt;
&lt;li&gt;Why does the girl run for the escape pod instead of try to stop the captain?&lt;/li&gt;
&lt;li&gt;Why do they throw their hands up before running in to the ship?&lt;/li&gt;
&lt;li&gt;How does the alien ship get damaged from the collision but not the fall?&lt;/li&gt;
&lt;li&gt;Why do the two girls run in the wrong direction every time?&lt;/li&gt;
&lt;li&gt;Why did the main character's suit run out of air so quickly?&lt;/li&gt;
&lt;li&gt;How did the baby squid not die earlier?&lt;/li&gt;
&lt;li&gt;How did the baby squid get so big?&lt;/li&gt;
&lt;li&gt;How did the space jockey survive the crash?&lt;/li&gt;
&lt;li&gt;How did the space jockey get out of his ship after the crash?&lt;/li&gt;
&lt;li&gt;How did the space jockey find the little escape module?&lt;/li&gt;
&lt;li&gt;How did the space jockey survive outside without his iconic helmet?&lt;/li&gt;
&lt;li&gt;Why does the space jockey now finally want to kill the main character?&lt;/li&gt;
&lt;li&gt;Why does the android wait all this time to finally call and mention that the space jockey is on his way?&lt;/li&gt;
&lt;li&gt;How did the android know that is where the space jockey was going?&lt;/li&gt;
&lt;li&gt;How does the main character's suit get refilled on air so quickly?&lt;/li&gt;
&lt;li&gt;How did the androids body not move during the crash?&lt;/li&gt;
&lt;li&gt;How does the android know about all the other ships?&lt;/li&gt;
&lt;li&gt;Why does the main character now trust the android again?&lt;/li&gt;
&lt;li&gt;If she is repelling down, how did the main character get into the crashed ship originally?&lt;/li&gt;
&lt;li&gt;Why does the main character take the androids useless body?&lt;/li&gt;
&lt;li&gt;Why didn't the space jockey go to use one of the other ships after he crashed?&lt;/li&gt; 
&lt;li&gt;Why are there no other space jockeys in any of the other ships?&lt;/li&gt;
&lt;li&gt;Why are there no aliens or worms or goo in any of the other ships?&lt;/li&gt;
&lt;li&gt;How does the android know how to fly the other ships?&lt;/li&gt;
&lt;li&gt;What did the main character use to leave her final message?&lt;/li&gt;
&lt;li&gt;Why did the no one ever send any information or progress reports back to earth?&lt;/li&gt;
&lt;li&gt;What is the main character going to eat or drink on her voyage?&lt;/li&gt;
&lt;li&gt;If this was supposed to setup the original movie, how does the alien get to LV-426?&lt;/li&gt;
&lt;li&gt;Why is the alien hatched as a medium size alien instead of a small alien?&lt;/li&gt;
&lt;li&gt;If the alien is supposed to be an alien, then why does it not look like an alien?&lt;/li&gt;
&lt;li&gt;What questions left by the original 1979 film does Prometheus actually answer?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ridley Scott used to be my absolute favorite director of all time. Unfortunately his recent streak of mediocre films had lessened my opinion of him, and now this is the final nail in the coffin. Mr. Scott may be a very skilled and highly technical director, but I can just no longer consider him to truly great film maker.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;2 / 5&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Sorry,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/8524713760719113274/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2012/06/prometheus-review.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/8524713760719113274?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/8524713760719113274?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2012/06/prometheus-review.html" title="Prometheus Review" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DkMBQ3k9fip7ImA9WhVUF0g.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-3969638415680191166</id><published>2012-05-20T21:05:00.002-07:00</published><updated>2012-05-22T23:27:32.766-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-05-22T23:27:32.766-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="Compression" /><category scheme="http://www.blogger.com/atom/ns#" term="Combres" /><category scheme="http://www.blogger.com/atom/ns#" term="MvcBundleConfig" /><category scheme="http://www.blogger.com/atom/ns#" term="MVC" /><category scheme="http://www.blogger.com/atom/ns#" term="NuGet" /><category scheme="http://www.blogger.com/atom/ns#" term="Bundle" /><category scheme="http://www.blogger.com/atom/ns#" term="MVC4" /><category scheme="http://www.blogger.com/atom/ns#" term="CSS" /><category scheme="http://www.blogger.com/atom/ns#" term="Minification" /><title>MvcBundleConfig NuGet Package</title><content type="html">&lt;p&gt;MvcBundleConfig is now available on NuGet!&lt;/p&gt;

&lt;p style="text-align:center"&gt;&lt;a target="_blank" href="http://nuget.org/packages/MvcBundleConfig"&gt;&lt;img src="http://sites.google.com/site/tdupont750/NugetBundle.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MvcBundleConfig is a very simple project that adds configuration and debugging features to MVC 4's bundling framework. Once you create a new MVC4 web application and install the MvcBundleConfig NuGet Package, then you need only update our layout to use the new bundle extension methods, and you are ready to go!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Original Blog Post: &lt;a target="_blank" href="http://www.tomdupont.net/2012/03/configuring-bundles-in-mvc-4.html"&gt;Configuring Bundles in MVC 4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Github Repository: &lt;a target="_blank" href="http://github.com/tdupont750/MvcBundleConfig"&gt;tdupont750/MvcBundleConfig&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;NuGet Package: &lt;a target="_blank" href="http://nuget.org/packages/MvcBundleConfig"&gt;MvcBundleConfig&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please note that the System.Web.Optimization NuGet package is still in beta, and thus that dependency is not included in the current version of the NuGet package. However, if you have created a new MVC4 project then that assembly should already be included.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Sample Installation Steps&lt;/b&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a target="_blank" href="http://sites.google.com/site/tdupont750/NugetBundle_1.png"&gt;Create a new ASP.NET MVC 4 Project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://sites.google.com/site/tdupont750/NugetBundle_2.png"&gt;Select Manage NuGet Packages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://sites.google.com/site/tdupont750/NugetBundle_3.png"&gt;Search for and install MvcBundleConfig&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a target="_blank" href="http://sites.google.com/site/tdupont750/NugetBundle_4.png"&gt;Update the Layout&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div style="float:right"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http://www.tomdupont.net/2012/05/mvcbundleconfig-nuget-package.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.tomdupont.net%2f2012%2f05%2fmvcbundleconfig-nuget-package.html" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/3969638415680191166/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2012/05/mvcbundleconfig-nuget-package.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/3969638415680191166?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/3969638415680191166?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2012/05/mvcbundleconfig-nuget-package.html" title="MvcBundleConfig NuGet Package" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;AkcCSHgzfip7ImA9WhVVFk8.&quot;"><id>tag:blogger.com,1999:blog-4063545436138319205.post-3147047300150250765</id><published>2012-05-04T23:24:00.000-07:00</published><updated>2012-05-09T22:34:29.686-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-05-09T22:34:29.686-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Timeout" /><category scheme="http://www.blogger.com/atom/ns#" term="ConnectionLimit" /><category scheme="http://www.blogger.com/atom/ns#" term="WebClient" /><title>Configuring WebClient Timeout and ConnectionLimit</title><content type="html">&lt;p&gt;Simplicity is nice, but not when it comes at the expense off accomplishing your goal.&lt;/p&gt;

&lt;p&gt;Recently I have been using System.Net.WebClient to access some REST APIs. It is great how simple the WebClient class is to use, but unfortunately it does not natively support configuring it's timeout or connection limit. In fact, before I knew that the default connection limit was preventing me from making more than two concurrent requests at a time, it was actually causing me some serious issues while doing performance testing.&lt;/p&gt;

&lt;p&gt;Good news, both of these issues are very easy to fix by simply extending the WebClient class.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Sample Class&lt;/b&gt;&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ConfigurableWebClient : WebClient&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt;? Timeout { &lt;span class="kwrd"&gt;get&lt;/span&gt;; &lt;span class="kwrd"&gt;set&lt;/span&gt;; }&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt;? ConnectionLimit { &lt;span class="kwrd"&gt;get&lt;/span&gt;; &lt;span class="kwrd"&gt;set&lt;/span&gt;; }&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; WebRequest GetWebRequest(Uri address)&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; baseRequest = &lt;span class="kwrd"&gt;base&lt;/span&gt;.GetWebRequest(address);&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; webRequest = baseRequest &lt;span class="kwrd"&gt;as&lt;/span&gt; HttpWebRequest;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (webRequest == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; baseRequest;&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (Timeout.HasValue)&lt;/pre&gt;
&lt;pre&gt;            webRequest.Timeout = Timeout.Value;&lt;/pre&gt;
&lt;pre class="alt"&gt; &lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (ConnectionLimit.HasValue)&lt;/pre&gt;
&lt;pre class="alt"&gt;            webRequest.ServicePoint.ConnectionLimit = ConnectionLimit.Value;&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; webRequest;&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;a style="float:right" href="http://www.dotnetkicks.com/kick/?url=http://www.tomdupont.net/2012/05/configuring-webclient-timeout-and.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.tomdupont.net%2f2012%2f05%2fconfiguring-webclient-timeout-and.html" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.tomdupont.net/feeds/3147047300150250765/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.tomdupont.net/2012/05/configuring-webclient-timeout-and.html#comment-form" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/3147047300150250765?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4063545436138319205/posts/default/3147047300150250765?v=2" /><link rel="alternate" type="text/html" href="http://www.tomdupont.net/2012/05/configuring-webclient-timeout-and.html" title="Configuring WebClient Timeout and ConnectionLimit" /><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/-UtZb_tTy910/TlWr_1mdodI/AAAAAAAAAQI/W3kObHj-5t4/s220/tom_dupont.png" /></author><thr:total>4</thr:total></entry></feed>
