<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://scottonwriting.net/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Scott On Writing.NET : Miscellaneous</title><link>http://scottonwriting.net/sowblog/archive/tags/Miscellaneous/default.aspx</link><description>Tags: Miscellaneous</description><dc:language>en</dc:language><generator>CommunityServer 2007 (Build: 20423.869)</generator><item><title>A Synchronized Visual Studio Crash</title><link>http://scottonwriting.net/sowblog/archive/2011/06/20/a-synchronized-visual-studio-crash.aspx</link><pubDate>Mon, 20 Jun 2011 19:52:17 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:189648</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=189648</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2011/06/20/a-synchronized-visual-studio-crash.aspx#comments</comments><description>&lt;p&gt;About month ago at a user group meeting the guy sitting across from me shared the tale of a talk he had attended. The speaker’s laptop had downloaded a slew of Windows Updates in the background, after which the “Restart your computer to finish installing important updates” dialog box appeared. The speaker unwittingly clicked the “Restart now” button, which closed the presentation and displayed those ominous words: “Please do not power off or unplug your machine… Installing update 1 of 43.” But how many speakers have the distinction of not only crashing their own system, but in addition the laptops of dozens of others in the audience? I am now among those hallowed ranks.&lt;/p&gt;  &lt;p&gt;On Saturday I presented another &lt;a href="http://scottonwriting.net/sowblog/archive/2011/05/12/full-day-asp-net-mvc-3-training-event-in-los-angeles-on-may-21st-2011.aspx"&gt;full-day ASP.NET MVC 3 training event&lt;/a&gt; in Los Angeles. Attendees were encouraged to bring their laptops and to follow along as I presented the material. At one point, I was creating a demo and writing some HTML in the &lt;strong&gt;_Layout.cshtml&lt;/strong&gt; file. After typing in some HTML I switched from the &lt;strong&gt;_Layout.cshtml&lt;/strong&gt; file to a controller at which point Visual Studio froze on me. Hard. And with vengeance. I quickly apologized and launched Windows Task Manager to kill VS and restart it.&lt;/p&gt;  &lt;p&gt;As Visual Studio was restarting I heard a rising murmur from the crowd – many other people just had Visual Studio crash on them, too! Several people were following along with me key stroke for key stroke and had experienced the same crash. Lovely. I asked the audience to humor me and I tried to reproduce the crash again, but had no luck. But clearly whatever sequence of events caused Visual Studio to crash was deterministic seeing that several other people had the same experience when following the same steps.&lt;/p&gt;  &lt;p&gt;So the next time you are at a conference or user group and are swapping stories of speaker flubs or miscues, feel free to tell them about this one guy who not only crashed his own demo, but was so bad that also he crashed dozens of other laptops in the audience.&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=189648" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/Miscellaneous/default.aspx">Miscellaneous</category></item><item><title>I’ve Written My Last Article for 4GuysFromRolla</title><link>http://scottonwriting.net/sowblog/archive/2011/03/29/i-ve-written-my-last-article-for-4guysfromrolla.aspx</link><pubDate>Tue, 29 Mar 2011 19:32:48 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:183641</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>118</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=183641</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2011/03/29/i-ve-written-my-last-article-for-4guysfromrolla.aspx#comments</comments><description>&lt;p&gt;&lt;font color="#ff0000"&gt;&lt;strong&gt;Warning!&lt;/strong&gt; This blog post is long and rife with navel-gazing.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;In 1998 I started an ASP resource site, 4GuysFromRolla.com. Toward the tail end of the dotcom boom I sold 4Guys to &lt;a href="http://internet.com/"&gt;Internet.com&lt;/a&gt;, but continued working as the editor and primary contributor for the site, writing a new article each week. This arrangement continued until just recently. My last article for 4Guys has been written – &lt;em&gt;&lt;a href="http://www.4guysfromrolla.com/articles/031611-1.aspx"&gt;Use MvcContrib Grid to Display a Grid of Data in ASP.NET MVC&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;  &lt;h2&gt;The Beginnings&lt;/h2&gt;  &lt;p&gt;My first exposure to web programming came in 1998 working at Empower Trainers and Consultants, a mid-sized consulting and training firm with locations in Kansas City, St. Louis, and Nashville. At the time I was an inexperienced, nervous, 19 year old sophomore at the &lt;a href="http://mst.edu/"&gt;University of Missouri-Rolla&lt;/a&gt; (UMR) who had landed an 8-month internship with Empower at their Kansas City location. My first assignment was to add some new features to the internal timekeeping tool, a custom-build data-driven web application powered by SQL Server and ASP. At the time I had done some rudimentary HTML development, but had zero experience with JavaScript, ASP, and SQL.&lt;/p&gt;  &lt;p&gt;Needless to say, I found ASP enthralling. The ability to quickly create an application that could be shared with the world amazed me then as it continues to amaze me to this day. At the time there weren’t many online resources for learning more about ASP. As my internship drew to an end I decided that once I got back to school I would start my own site rich with ASP information.&lt;/p&gt;  &lt;p&gt;Upon returning to university I cajoled three good friends into starting a website, 4GuysFromRolla.com. The idea was that the site would boast four sections:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;ASP Information &lt;/li&gt;    &lt;li&gt;Programming Information &lt;/li&gt;    &lt;li&gt;Linux Information &lt;/li&gt;    &lt;li&gt;Humor &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;If you couldn’t guess, we were four witty computer nerds (with an emphasis on the nerd part).&lt;/p&gt;  &lt;p&gt;In September 1998 4GuysFromRolla.com went live. Over time, the other three guys lost interest and moved onto other projects. By the time I graduated in May 2000, 4GuysFromRolla.com was run by one guy from Rolla and focused strictly on ASP.&lt;/p&gt;  &lt;h2&gt;&lt;/h2&gt;  &lt;h2&gt;Sale to Internet.com&lt;/h2&gt;  &lt;p&gt;The dotcom boom reached its fever pitch in 2000. Companies were paying $5,000 a month for a little 125x125 banner to appear on the 4Guys homepage and $500 for a two sentence text ad to appear in the weekly newsletter, not to mention the thousands of dollars per month companies were dropping to have their animated 468x60 banners in the rotation to appear at the top of each article. The spending frenzy also extended to the acquisitions side, as numerous ASP resource sites were gobbled up by larger players.&lt;/p&gt;  &lt;p&gt;In late 2000 I decided to “cash out.” 4Guys was sold to Internet.com.&lt;/p&gt;  &lt;p&gt;I wrestled with the decision on whether to sell the site or not for a long time. On one hand, 4Guys was my baby and I had poured uncounted hours into it over the previous three years. Having seen how sites like &lt;a href="http://15seconds.com/"&gt;15Seconds.com&lt;/a&gt; fared after their acquisition, I knew that selling 4Guys would be akin to signing its death warrant. When a larger company buys a smaller site it’s not uncommon for the original founders to exit stage right, either immediately or in the very near term. When that happens, and when the acquirer starts to turn the screws in an attempt to better monetize their purchase, the inevitable happens – the site withers on the vine, traffic languishes, and the death knell is sounded. On the other hand, by late 2000 I think it was pretty apparent to everyone that the dotcom boom was coming to an end.&lt;/p&gt;  &lt;p&gt;In the end, I decided to sell. The sales price reflected more than five years of dotcom boom revenue, which I deduced would be more like ten or more years of revenue once the boom ended. At age 22, five to ten years is an unimaginable window of time. I wondered, Would I be interested in writing about ASP ten years hence? Would I even be using ASP or web-based technologies? Since the answers to those questions were “maybe,” I decided to take the bird in the hand over the two in the bush.&lt;/p&gt;  &lt;p&gt;Of course, here we are, 11 years later, and I am still actively involved in ASP.NET and the ASP.NET community and, until recently, was still writing for 4Guys. If I had it to do over again (and knowing what I know now), I would not have sold the site. Hindsight is 20/20. But that’s not to say that I regret the decision to sell the site – I don’t. In fact, I still hold that it was the right decision at the time given the unknowns.&lt;/p&gt;  &lt;h2&gt;The Buying Eyeballs Business Model&lt;/h2&gt;  &lt;p&gt;The dotcom boom heralded an interesting time in the history of the web. At its peak, billions of dollars were spent buying traffic, or “eyeballs,” as it was commonly referred to back then. In 2000, companies like Internet.com and DevX (among many others) were buying technology resource sites not for their content or talent, but for their existing traffic. This was a workable business model at the time due to the high rates advertisers were paying. Unfortunately, it was not sustainable once the bottom dropped out of advertising.&lt;/p&gt;  &lt;p&gt;In 2009, Internet.com and its hundreds of technology-focused websites &lt;a href="http://www.internetnews.com/webcontent/article.php/3833856/WebMediaBrands-Sells-Internetcom-to-QuinStreet.htm"&gt;were sold to QuinStreet for $18 million&lt;/a&gt;. I continued working on 4Guys for QuinStreet (until recently). Unfortunately, QuinStreet’s purchase was a continuation of the buying eyeballs business model as evidenced by the lack of investment in the purchased web properties. 4Guys retained its dated look and feel as even more ads were squeezed onto the page.&lt;/p&gt;  &lt;p&gt;Sites like 4Guys were sold by Internet.com to QuinStreet for pennies on the dollar. Even at such a steep discount, the question remains: did QuinStreet overpay? Time will tell.&lt;/p&gt;  &lt;h2&gt;Withering On the Vine&lt;/h2&gt;  &lt;p&gt;After the sale of 4Guys to Internet.com in 2000 I continued on as the site’s editor and primary contributor, authoring an article each week. Despite my continued work on the site, 4Guys started to lose prevalence in the ASP.NET community. There were many times I talked to a developer at a User Group or at a conference who would say something nice like, “I taught myself classic ASP from your articles on 4GuysFromRolla.com - I used to go there all the time.” The message was always the same – a meaningful compliment that had embedded in it a reflection on the current state of the site - &lt;em&gt;I &lt;strong&gt;used&lt;/strong&gt; to visit 4Guys&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;There are probably a lot of different reasons why the importance and relevance of 4GuysFromRolla diminished over the years. Some of the reasons I’ve arrived at include:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;My predominant use of VB code samples (rather than C#).&lt;/strong&gt; In recent years, I started writing more C#-focused articles, as well as articles with code samples in both VB and C#, but the majority of articles on 4Guys are VB-only. And my switch to a more C#-friendly style came long after C# had become the de facto .NET language. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Increased attempts at monetization.&lt;/strong&gt; More ads, bigger ads, flashier ads, and more annoying ads all made the site more difficult and less enjoyable to use. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;A dated look and feel.&lt;/strong&gt; If you couldn’t guess, the 4GuysFromRolla.com website hasn’t had a site redesign since 2002. It just looks old and dated. I’d like to think that the quality and quantity of content can make up for such aesthetic issues, but I understand why visitors would find the site appearance off-putting and why that might make them less likely to return, especially if there was similar content to be found elsewhere, which brings me to the next three factors… &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;The Google.&lt;/strong&gt; Google turned the Internet upside down. Prior to Google, when faced with a particular problem people would go to a particular site and start hunting (or searching) for a solution. Once Google made search quick, fast, easy, and accurate – something I think happened in the early 2000s – user behavior shifted radically. Now Google was where people went to find answers to their questions. Just ask &lt;a href="http://www.codinghorror.com/blog"&gt;Jeff Atwood&lt;/a&gt;, who &lt;a href="http://www.codinghorror.com/blog/2009/02/the-elephant-in-the-room-google-monoculture.html"&gt;notes that&lt;/a&gt;: “Currently, 83% of our total traffic [to Stackoverflow] is from search engines, or rather, one &lt;em&gt;particular&lt;/em&gt; search engine.” And that search engine, if you couldn’t guess, is Google. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;A stronger online presence from Microsoft.&lt;/strong&gt; In the late 90s and early 2000s, Microsoft offered a substandard web presence for their web technologies. There was technical documentation buried somewhere on Microsoft’s website, some articles on their MSDN site here and there, as well as articles from &lt;em&gt;MSDN Magazine&lt;/em&gt; that were available online. But everything was scattered and hard to find. Microsoft finally got it right in the mid-2000s when they made MSDN easier and quicker to search and separated out their core technologies into standalone sites – &lt;a href="http://www.asp.net"&gt;www.asp.net&lt;/a&gt;, &lt;a href="http://www.iis.net"&gt;www.iis.net&lt;/a&gt;, etc. This move sucked an appreciable amount of traffic from community-founded sites like 4GuysFromRolla. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;The proliferation of blogs.&lt;/strong&gt; Blogs are another technology that made resource sites like 4GuysFromRolla.com less relevant. Intelligent developers with something interesting or useful to share didn’t need to get their thoughts published on your site – instead, they could start their own blog. The explosion of blogs outpaced the demand for information, cutting into everyone’s traffic and relevance. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Of all of the reasons listed above only one of them falls on my shoulders, namely my slow move away from VB to C#. But perhaps there are other factors that are my fault that my ego is blinding me from. I do believe that the quality of writing that has appeared on 4Guys has improved over the years. When I read some of the articles I wrote while I was still in school (1998-2000) I cringe. Also, I posit that the articles’ topics are (relatively) timely and of interest to ASP.NET developers. (To be fair, I was a bit late to jQuery and ASP.NET MVC, but once I jumped on that bandwagon I wrote quite a bit on said topics.)&lt;/p&gt;  &lt;p&gt;The increased attempts and monetization and dated look and feel falls on Internet.com and QuinStreet’s shoulders. The last three factors were out of everyone’s control and affected all websites, not just those in my little corner of the web. And those macro changes, while perhaps detrimental to the growth of a site like 4Guys, are net gains for the Internet (and humanity) as a whole.&lt;/p&gt;  &lt;p&gt;Neither QuinStreet nor Internet.com has ever provided me with traffic numbers so I don’t have any hard data to back up my thoughts on this, but my presumption is that 4Guys is still used by hundreds of thousands of developers around the world each month, but that it’s become less and less relevant as time has gone on. Today, I imagine that most people reach 4Guys from a Google search or from a link posted on an old messageboard or newsgroup thread. Few visit the site to see what new content is available or because a coworker told them that it’s a great website for ASP.NET developers of any stripe.&lt;/p&gt;  &lt;p&gt;Yes, there are still many who find a solution to their problem on 4Guys, but few say, “How do I do &lt;em&gt;X&lt;/em&gt;? I bet 4Guys has the answer!”&lt;/p&gt;  &lt;h2&gt;Some Fun Facts&lt;/h2&gt;  &lt;p&gt;Is it just me, or is this blog post getting a little depressing? How about some fun 4Guys trivia.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;First online article I ever wrote was published on 4Guys on September 16th, 1998 – &lt;em&gt;&lt;a href="http://www.4guysfromrolla.com/webtech/091698-1.shtml"&gt;Using ActiveX Controls on Your Web Page&lt;/a&gt;&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;First article on 4Guys about ASP.NET was published on July 15th, 2000 – &lt;em&gt;&lt;a href="http://www.4guysfromrolla.com/webtech/071500-1.shtml"&gt;ASP.NET: An Introduction and My Views on the Matter&lt;/a&gt;&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Rolla,_Missouri"&gt;Rolla&lt;/a&gt; is a small town in Missouri that is home to the University of Missouri – Rolla, now named &lt;a href="http://en.wikipedia.org/wiki/Missouri_University_of_Science_and_Technology"&gt;Missouri University of Science and Technology&lt;/a&gt;. Rolla is pronounced &lt;em&gt;Rawl-ah&lt;/em&gt;. It’s 4GuysFrom&lt;em&gt;Rawl-ah&lt;/em&gt;, not 4GuysFrom&lt;em&gt;Roll-ah&lt;/em&gt;. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;For those who have never been to Rolla, it is about an hour and a half west of St. Louis, located square in the middle of nowhere. The university in Rolla focuses on engineering and the sciences and the student body is predominantly male. Many people wonder how I had the time to write nearly 750 articles while a student at UMR. The answer is that I went to school in the middle of nowhere with no girls - free time was not something that was hard to find!&lt;/p&gt;  &lt;p&gt;When we started 4Guys, one of the other 4Guys created the site design. It had a black background with gray text and these bubbles that spanned the top and right of each page with links to each of the four sections. Together, we redesigned the site in 1999 to give it a more professional look. It was at this time that 4Guys adopted teal as its primary color. After acquiring the site, Internet.com did a resign in 2002. The redesign made the site a bit more graphics heavy and added some curved doodads here and there. I always found the 4Guys logo that Internet.com’s design team created to be hilarious.&lt;/p&gt;  &lt;p&gt;&lt;img style="display: block; float: none; margin-left: auto; margin-right: auto" src="http://www.4guysfromrolla.com/img/4guyslogo.gif" /&gt;&lt;/p&gt;  &lt;p&gt;The guy on the left looks depressed and ostracized from the group. The guy on the right wants nothing more than a big group hug. And those two guys in the middle? They look like a couple of real a-holes. Too cocky and arrogant to console their melancholy friend on the left, and too cool for school to hug the guy on the right. Jerks.&lt;/p&gt;  &lt;h2&gt;So Farewell…&lt;/h2&gt;  &lt;p&gt;My time with 4Guys has now come to an end. It was a fun and unforgettable run. I fondly remember huddled around a computer monitor with the other three guys from Rolla as we tried to decide on a domain name. I remember the excitement of landing my first advertiser and of depositing that first check. And I won’t forget the many emails from fellow developers who wrote in to thank me for an article that helped them solve a vexing problem. But most of all, my memories will center around writing the 4Guys article each week – drumming up a topic, banging out some code, and then putting that code into prose.&lt;/p&gt;  &lt;p&gt;&lt;font color="#ff0000"&gt;&lt;font color="#555555"&gt;Having written a 4Guys article each of the preceding 650 or so weeks, it will be odd not to do so this week. Or next week. Or ever again.&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;Farewell, old girl, it was a good run.&lt;/p&gt;  &lt;h2 align="center"&gt;&lt;font color="#ff0000"&gt;&lt;font color="#555555"&gt;&lt;font style="background-color: #ffff00; font-weight: normal" size="4"&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#ff0000"&gt;&lt;font color="#555555"&gt;&lt;font style="font-weight: normal" size="4"&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font style="font-weight: normal" color="#ff0000" size="5"&gt;Just to be clear, I am not retiring! I am a writer, that’s what I do. You’ll continue to see articles from me on this blog and on sites like &lt;/font&gt;&lt;font style="font-weight: normal" color="#ff0000" size="5"&gt;DotNetSlackers.com&lt;/font&gt;&lt;font style="font-weight: normal" color="#ff0000" size="5"&gt; and &lt;/font&gt;&lt;font style="font-weight: normal" color="#ff0000" size="5"&gt;ASPAlliance.com&lt;/font&gt;&lt;font style="font-weight: normal" color="#ff0000" size="5"&gt;. And I am always looking for additional engagements – if you have a need for a technical writer or prolific ASP.NET author, please don’t hesitate to &lt;a href="http://scottonwriting.net/ScottMitchell.asp"&gt;check out my resume&lt;/a&gt; and &lt;a href="http://scottonwriting.net/sowblog/contact.aspx"&gt;drop me a line&lt;/a&gt;.&lt;/font&gt;&lt;/h2&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=183641" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/About+Writing/default.aspx">About Writing</category><category domain="http://scottonwriting.net/sowblog/archive/tags/Miscellaneous/default.aspx">Miscellaneous</category></item><item><title>Adding a RESTful Service to My Boggle Solver</title><link>http://scottonwriting.net/sowblog/archive/2010/09/11/adding-a-restful-service-to-my-boggle-solver.aspx</link><pubDate>Fri, 10 Sep 2010 22:47:20 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:169410</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=169410</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2010/09/11/adding-a-restful-service-to-my-boggle-solver.aspx#comments</comments><description>&lt;p align="center"&gt;&lt;font color="#ff0000" size="5"&gt;This blog post has been deprecated. Please see &lt;a href="http://www.4guysfromrolla.com/articles/112410-1.aspx"&gt;Updating My Online Boggle Solver Using jQuery Templates and WCF&lt;/a&gt; for an updated discussion on the solver service, the data it returns, and how to call it from a web page.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;My immediate and extended family enjoys playing games, and one of our favorites is Boggle. &lt;a href="http://en.wikipedia.org/wiki/Boggle"&gt;Boggle&lt;/a&gt; is a word game trademarked by Parker Brothers and Hasbro that involves several players trying to find as many words as they can in a 4x4 grid of letters. At the end of the game, players compare the words they found. During this comparison I've always wondered what words we may have missed. Was there some elusive 10-letter word that no one unearthed? Did we only discover 25 solutions when there were 200 or more?&lt;/p&gt;  &lt;p&gt;To answer these questions I created a Boggle solver web application (back in 2008) that prompts a user for the letters in the Boggle board and then recursively explores the board to locate (and display) all available solutions. This &lt;a href="http://fuzzylogicinc.net/Boggle/"&gt;Boggle solver&lt;/a&gt; is available online - &lt;a href="http://fuzzylogicinc.net/Boggle/"&gt;fuzzylogicinc.net/Boggle&lt;/a&gt;. My family uses it every time we get together and play Boggle. For more information on how it works and to get your hands on the code, check out my article, &lt;a href="http://www.4guysfromrolla.com/articles/040208-1.aspx"&gt;Creating an Online Boggle Solver&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Recently, I’ve been working on some projects that have involved creating &lt;a href="http://en.wikipedia.org/wiki/Representational_State_Transfer#RESTful_web_services"&gt;RESTful web services&lt;/a&gt; using &lt;a href="http://msdn.microsoft.com/en-us/netframework/aa663324.aspx"&gt;WCF&lt;/a&gt;. Being Friday, I decided to have a little fun and add a RESTful interface to the Boggle solver. This was actually quite easy to do and took all of 5 minutes.&lt;/p&gt;  &lt;h2&gt;Creating the Boggle Solver Service&lt;/h2&gt;  &lt;p&gt;I started by adding a new item to my website of type WCF Service, naming it &lt;strong&gt;Solver.svc&lt;/strong&gt;. This created three files:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Solver.scr &lt;/li&gt;    &lt;li&gt;ISolver.cs &lt;/li&gt;    &lt;li&gt;Solver.cs &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;In the contract (&lt;strong&gt;ISolver.cs&lt;/strong&gt;) I added a single method, &lt;strong&gt;Solve&lt;/strong&gt;, that accepts two inputs: a string representing the board and a string indicating the minimum number of letters for a word to be considered a solution. (Boggle rules allow for words of three letters or more, but house rules only count words that are four letters or longer.) I then used the &lt;strong&gt;WebGet&lt;/strong&gt; attribute to indicate that the board and length input parameters would be specified via the querystring fields &lt;strong&gt;BoardID&lt;/strong&gt; and &lt;strong&gt;Length&lt;/strong&gt;, and that the resulting output should be formatted as &lt;a href="http://json.org/"&gt;JSON&lt;/a&gt;.&lt;/p&gt;  &lt;pre class="brush: csharp;"&gt;[ServiceContract]
public interface ISolver
{
    [OperationContract]
    [WebGet(UriTemplate = &amp;quot;?BoardID={board}&amp;amp;Length={length}&amp;quot;, ResponseFormat=WebMessageFormat.Json)]
    BoggleWordDTO[] Solve(string board, string length);
}&lt;/pre&gt;

&lt;p&gt;Note that the &lt;strong&gt;Solve&lt;/strong&gt; method returns an array of &lt;strong&gt;BoggleWordDTO&lt;/strong&gt; objects. This is a new class I created to represent the data to transmit from the service. This class has two properties:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Word&lt;/strong&gt; – a string value that represents a word found in the Boggle board, and &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;Score&lt;/strong&gt; – the score for that solution. According to the official rules, three and four letter words are worth 1 point, five letter words are worth 2, six letter words worth 3, seven letter words worth 5, and eight letter words and longer worth 11. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;Solve&lt;/strong&gt; method implementation (&lt;strong&gt;Solver.cs&lt;/strong&gt;) is pretty straightforward. It starts with a bit of error checking to ensure that the passed in board and letter information is kosher. Next, it creates a &lt;strong&gt;BoggleBoard&lt;/strong&gt; object, specifying the minimum number of letters for a solution and the board contents. Then the BoggleBoard object’s &lt;strong&gt;Solve&lt;/strong&gt; method is invoked, which performs the recursion and computes the set of solutions (as an object of type &lt;strong&gt;BoggleWordList&lt;/strong&gt;). The solutions are then converted into an array of &lt;strong&gt;BoggleWordDTO&lt;/strong&gt; objects, which is then returned to the client.&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;public BoggleWordDTO[] Solve(string board, string length)
{
    ...

    // Create the BoggleBoard
    BoggleBoard bb = new BoggleBoard(
                        letters,
                        board[0].ToString(), ..., board[15].ToString()
                    );

    // Solve the Boggle board
    var solutions = bb.Solve();

    // Populate and return an array of BoggleWordDTO objects
    return solutions
                .Select(s =&amp;gt; new BoggleWordDTO()
                {
                    Word = s.Word,
                        Score = s.Score
                })
                .ToArray();
}&lt;/pre&gt;

&lt;p&gt;Because the service is configured to return the data using JSON, the results are serialized into a JSON array.&lt;/p&gt;

&lt;p&gt;In addition to creating the Solver-related files and writing the code I noted, I also had to add &lt;strong&gt;&amp;lt;system.serviceModel&amp;gt;&lt;/strong&gt; configuration to &lt;strong&gt;Web.config&lt;/strong&gt; to permit HTTP access to the service &lt;strike&gt;and to enable ASP.NET compatibility. The reason I had to enable ASP.NET compatibility is because the dictionary used by the solver is a text file stored on disk, and the solver gets the path to that text file using &lt;strong&gt;Server.MapPath&lt;/strong&gt; (namely, &lt;strong&gt;HttpContext.Current.Server.MapPath(“…”)&lt;/strong&gt;). Without ASP.NET compatibility, &lt;strong&gt;HttpContext.Current&lt;/strong&gt; is null when the service attempts to solve and then the call to &lt;strong&gt;Server.MapPath&lt;/strong&gt; blows up.&lt;/strike&gt; Also, I had to specify the &lt;strong&gt;Factory&lt;/strong&gt; attribute in the &lt;strong&gt;&amp;lt;%@ ServiceHost %&amp;gt; &lt;/strong&gt;directive of the &lt;strong&gt;Solver.svc&lt;/strong&gt; file. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[UPDATE: 2010-09-10]&lt;/strong&gt; &lt;a href="http://allben.net/"&gt;Ben Amada&lt;/a&gt; posted a helpful comment pointing me to the existence of the &lt;strong&gt;HostingEnvironment.MapPath&lt;/strong&gt; method, which does the same work as &lt;strong&gt;Server.MapPath&lt;/strong&gt; but doesn’t require an &lt;strong&gt;HttpContext&lt;/strong&gt; object. I updated this code accordingly. I also updated the code that cached the dictionary in memory, replacing the use of &lt;strong&gt;HttpContext.Current.Cache&lt;/strong&gt; with &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.httpruntime.cache.aspx"&gt;HttpRuntime.Cache&lt;/a&gt;, which I &lt;a href="http://weblogs.asp.net/pjohnson/archive/2006/02/06/437559.aspx"&gt;probably should have been using all along&lt;/a&gt;&lt;strong&gt;&lt;/strong&gt;. The code has been updated. Thanks, Ben!&lt;/p&gt;

&lt;h2&gt;Using the Boggle Solver Service&lt;/h2&gt;

&lt;p&gt;To use the service, just point your browser (or your code/script) to:&amp;#160; &lt;strong&gt;&lt;a href="http://fuzzylogicinc.net/Boggle/Solver.svc?BoardID=board&amp;amp;Length=length"&gt;http://fuzzylogicinc.net/Boggle/Solver.svc?BoardID=&lt;em&gt;board&lt;/em&gt;&amp;amp;Length=&lt;em&gt;length&lt;/em&gt;&lt;/a&gt;&lt;/strong&gt;. The &lt;em&gt;board&lt;/em&gt; value should be entered as a string of the characters in the Boggle board, starting from the upper left corner and reading to the right and down. For example, if you had the board:&lt;/p&gt;

&lt;pre&gt;r e i b
t m f w
i r a e
r h s t &lt;/pre&gt;

&lt;p&gt;You would use a &lt;em&gt;board&lt;/em&gt; value of &lt;strong&gt;reibtmfwiraerhst&lt;/strong&gt;. &lt;em&gt;letter&lt;/em&gt; should be a number between 3 and 6, inclusive.&lt;/p&gt;

&lt;p&gt;So, to find all solutions to the above board that are four or more letters, you’d visit: &lt;a title="http://fuzzylogicinc.net/Boggle/Solver.svc?BoardID=reibtmfwiraerhst&amp;amp;Length=4" href="http://fuzzylogicinc.net/Boggle/Solver.svc?BoardID=reibtmfwiraerhst&amp;amp;Length=4"&gt;http://fuzzylogicinc.net/Boggle/Solver.svc?BoardID=reibtmfwiraerhst&amp;amp;Length=4&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Doing so would return the following (abbreviated) JSON:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[{&amp;quot;Score&amp;quot;:1,&amp;quot;Word&amp;quot;:&amp;quot;amir&amp;quot;},{&amp;quot;Score&amp;quot;:2,&amp;quot;Word&amp;quot;:&amp;quot;amirs&amp;quot;},{&amp;quot;Score&amp;quot;:1,&amp;quot;Word&amp;quot;:&amp;quot;awes&amp;quot;},{&amp;quot;Score&amp;quot;:1,&amp;quot;Word&amp;quot;:&amp;quot;bier&amp;quot;},{&amp;quot;Score&amp;quot;:1,&amp;quot;Word&amp;quot;:&amp;quot;ears&amp;quot;},{&amp;quot;Score&amp;quot;:1,&amp;quot;Word&amp;quot;:&amp;quot;east&amp;quot;},...]&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The above JSON represents an array of objects, where each object has two properties, &lt;strong&gt;Score&lt;/strong&gt; and &lt;strong&gt;Word&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So how can this service be used? Well, with a bit of JavaScript you can call the service from a browser and display the results dynamically. I’ve included a rudimentary example in the download (which you can find at the end of this blog post) that prompts the user to enter the 16 characters for the board and the minimum number of letters. It then uses &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt;’s &lt;a href="http://api.jquery.com/jQuery.getJSON/"&gt;&lt;strong&gt;getJSON&lt;/strong&gt; function&lt;/a&gt; to make a call to the service and get the data back. The JSON array is then enumerated and a series of list items are constructed, showing each solution in a bulleted list.&lt;/p&gt;

&lt;p&gt;Here is the web page when you visit it and enter a boggle board and the minimum number of letters (but before you click the “Find All Words!” button.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://nbaweblog.com/images/sowblog/BoggleBoard2_0C860A56.gif"&gt;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="BoggleBoard2" border="0" alt="BoggleBoard2" src="http://nbaweblog.com/images/sowblog/BoggleBoard2_thumb_209F26DF.gif" width="547" height="312" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Clicking the “Find All Words!” button executes the following jQuery script:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;$.getJSON(
    &amp;quot;Solver.svc&amp;quot;,
    {
        &amp;quot;BoardID&amp;quot;: $(&amp;quot;#board&amp;quot;).val(),
        &amp;quot;Length&amp;quot;: $(&amp;quot;#length&amp;quot;).val()
    },
    function (words) {
        var output = &amp;quot;No solutions exists!&amp;quot;;

        if (words.length &amp;gt; 0) {
            output = &amp;quot;&amp;lt;h2&amp;gt;&amp;quot; + words.length + &amp;quot; Solutions!&amp;lt;/h2&amp;gt;&amp;lt;ul&amp;gt;&amp;quot;;

            var score = 0;

            $.each(words, function (index, word) {
                score += word.Score;
                output += &amp;quot;&amp;lt;li&amp;gt;&amp;quot; + word.Word + &amp;quot; (&amp;quot; + word.Score + &amp;quot; points)&amp;lt;/li&amp;gt;&amp;quot;;
            });

            output += &amp;quot;&amp;lt;/ul&amp;gt;&amp;lt;p&amp;gt;Total score = &amp;quot; + score + &amp;quot; points!&amp;lt;/p&amp;gt;&amp;quot;;
        }

        $(&amp;quot;#solutions&amp;quot;).html(output);
    }
);&lt;/pre&gt;

&lt;p&gt;Note that the above script calls the &lt;strong&gt;Solver.svc&lt;/strong&gt; service passing in the BoardID and Length querystring parameters. The textbox where the user enters the board has an &lt;strong&gt;id&lt;/strong&gt; of &lt;strong&gt;board&lt;/strong&gt; while the minimum letter drop-down list has an &lt;strong&gt;id&lt;/strong&gt; of &lt;strong&gt;length&lt;/strong&gt;. The function defined in the call is what is executed when the result comes back successfully. Here, the jQuery &lt;a href="http://api.jquery.com/each/"&gt;&lt;strong&gt;each &lt;/strong&gt;function&lt;/a&gt; is used to enumerate the array and build up a string of HTML in a variable named &lt;strong&gt;output&lt;/strong&gt; that produces a bulleted list of solutions. The total number of solutions and total number of points is also included in &lt;strong&gt;output&lt;/strong&gt;. Finally, the contents of &lt;strong&gt;output&lt;/strong&gt; are dumped to a &lt;strong&gt;&amp;lt;div&amp;gt;&lt;/strong&gt; on the page with an &lt;strong&gt;id&lt;/strong&gt; of &lt;strong&gt;solutions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here’s the page after clicking the “Find All Words!” button. Nothing fancy, of course, and not nearly as useful or eye-pleasing as &lt;a href="http://fuzzylogicinc.net/Boggle/EnterBoard.aspx?BoardID=reibtmfwiraerhst&amp;amp;Length=4"&gt;the website’s results page&lt;/a&gt;, but it does illustrate one way you can use the Boggle &lt;strong&gt;Solver.svc&lt;/strong&gt; service.&lt;/p&gt;

&lt;p align="center"&gt;&lt;a href="http://nbaweblog.com/images/sowblog/BoggleBoard3_71D96E3C.gif"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="BoggleBoard3" border="0" alt="BoggleBoard3" src="http://nbaweblog.com/images/sowblog/BoggleBoard3_thumb_1EEE5B0B.gif" width="353" height="484" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;Download the Code!&lt;/h2&gt;

&lt;p&gt;You can download the complete Boggle solver engine, web application, and WCF RESTful service from &lt;a title="http://aspnet.4guysfromrolla.com/code/BoggleSolver.zip" href="http://aspnet.4guysfromrolla.com/code/BoggleSolver.zip"&gt;http://aspnet.4guysfromrolla.com/code/BoggleSolver.zip&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy Programming, and Happy Boggling!&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=169410" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+Talk/default.aspx">ASP.NET Talk</category><category domain="http://scottonwriting.net/sowblog/archive/tags/Miscellaneous/default.aspx">Miscellaneous</category><category domain="http://scottonwriting.net/sowblog/archive/tags/Web+Services/default.aspx">Web Services</category><category domain="http://scottonwriting.net/sowblog/archive/tags/jQuery/default.aspx">jQuery</category></item><item><title>I’m Teaching Two Upcoming Training Classes in San Diego</title><link>http://scottonwriting.net/sowblog/archive/2010/08/19/i-m-teaching-two-upcoming-training-classes-in-san-diego.aspx</link><pubDate>Thu, 19 Aug 2010 17:45:32 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:168128</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=168128</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2010/08/19/i-m-teaching-two-upcoming-training-classes-in-san-diego.aspx#comments</comments><description>&lt;p&gt;Once a year (or so) I teach a handful of one-day, four hour classes in San Diego on various ASP.NET topics. I’ve got &lt;a href="http://www.fuzzylogicinc.net/InDepth/Outline.aspx"&gt;two such classes&lt;/a&gt; lined up for Saturday, September 11:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;&lt;a href="http://fuzzylogicinc.net/InDepth/Outline.aspx?coid=25ccc9a6-bdef-4265-888e-7111cc5660ca"&gt;Get Started with ASP.NET MVC&lt;/a&gt;&lt;/strong&gt; – &lt;em&gt;8 AM to Noon       &lt;br /&gt;&lt;/em&gt;Traditionally, ASP.NET websites have been designed using the Web Forms model; &lt;a href="http://www.asp.net/mvc"&gt;ASP.NET MVC&lt;/a&gt; is an alternative model that uses the Model-View-Controller pattern. In a nutshell, ASP.NET MVC gives developers much finer control over the markup rendered by their web pages, a greater and clearer separation of concerns, better testability, and cleaner, more SEO-friendly URLs. This four hour class introduces ASP.NET MVC, explores how to build ASP.NET MVC applications, covers key differences between Web Forms and ASP.NET MVC, and highlights the benefits of ASP.NET MVC. During the class, we will build a real-world ASP.NET MVC application from start to finish.      &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;&lt;a href="http://fuzzylogicinc.net/InDepth/Outline.aspx?coid=bfb9f765-b5ca-4886-a8e6-b4d80668e18f"&gt;Build Responsive Web Applications with Ajax, jQuery, and ASP.NET&lt;/a&gt;&lt;/strong&gt; – &lt;em&gt;1 to 5 PM       &lt;br /&gt;&lt;/em&gt;Ajax-enabled web applications use JavaScript and streamlined client/server communications to offer a highly interactive and responsive user experience. &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt; is a free, popular and powerful JavaScript library that ships with Visual Studio 2010 and greatly simplifies building Ajax-enabled web applications. This four hour class examines key Ajax concepts and techniques and walks through building a real-world Ajax-enabled web application using jQuery and ASP.NET.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Each class is $249 per student, but there is an ongoing early bird special price of $199 (available until August 28th). Students receive electronic access and printed copies of the training materials. Coffee, snacks and lunch are provided. The classes are held at the Sorrento Mesa Center (&lt;a href="http://fuzzylogicinc.net/InDepth/Directions.aspx"&gt;directions&lt;/a&gt;), which is located in Sorrento Valley and has free parking.&lt;/p&gt;  &lt;p&gt;If you are interested in signing up or would like detailed course outlines, visit &lt;a href="http://www.fuzzylogicinc.net/InDepth"&gt;www.fuzzylogicinc.net/InDepth&lt;/a&gt;. If you have any questions about the class, material, or logistics, shoot me an email at &lt;a href="mailto:mitchell@4guysfromrolla.com"&gt;mitchell@4guysfromrolla.com&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Hope to see you there!&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Signup: &lt;/strong&gt;&lt;a href="http://www.fuzzylogicinc.net/InDepth"&gt;www.fuzzylogicinc.net/InDepth&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=168128" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+Talk/default.aspx">ASP.NET Talk</category><category domain="http://scottonwriting.net/sowblog/archive/tags/Miscellaneous/default.aspx">Miscellaneous</category><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://scottonwriting.net/sowblog/archive/tags/jQuery/default.aspx">jQuery</category></item><item><title>I Am Now Tweeting (Or is it Twittering?)</title><link>http://scottonwriting.net/sowblog/archive/2010/08/10/i-am-now-tweeting-or-is-it-twittering.aspx</link><pubDate>Tue, 10 Aug 2010 03:12:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:167739</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=167739</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2010/08/10/i-am-now-tweeting-or-is-it-twittering.aspx#comments</comments><description>&lt;p&gt;Last week I received an email from &lt;a href="http://twitter.com/srikanthpragada" mce_href="http://twitter.com/srikanthpragada"&gt;Srikanth Pragada&lt;/a&gt;, a .NET trainer in southern India, asking why I did not have a Twitter account. I had two excuses. First, I am somewhat of a &lt;a href="http://en.wikipedia.org/wiki/Luddite" mce_href="http://en.wikipedia.org/wiki/Luddite"&gt;Luddite&lt;/a&gt; when it comes to social technologies like cell phones and web apps like LinkedIn, Facebook, etc. Also, I have the knack of verbosity, in that I can - and often do! - take 100 words to describe a point that could have been made in 50. Consequently, Twitter's 140 character limit sort of grates against my natural tendency to write as if I was being paid by the word.&lt;/p&gt;&lt;p&gt;But excuses be damned, for I have started tweeting! (Or is it, "I have started Twittering?" I need a teenager so that I can have the answers to questions like these.) You can follow me &lt;a href="http://twitter.com/ScottOnWriting" mce_href="http://twitter.com/ScottOnWriting"&gt;@ScottOnWriting&lt;/a&gt;. Like with this blog, my intent it to use this Twitter account exclusively for discussing and sharing information about ASP.NET and related technologies/topics. No tweets about what I had for breakfast or that my flight is delayed, promise!&lt;br&gt;&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=167739" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/Miscellaneous/default.aspx">Miscellaneous</category></item><item><title>Links to Scott Guthrie's Using LINQ to SQL Tutorials</title><link>http://scottonwriting.net/sowblog/archive/2010/07/27/links-to-scott-guthrie-s-using-linq-to-sql-tutorials.aspx</link><pubDate>Tue, 27 Jul 2010 19:56:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:167201</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=167201</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2010/07/27/links-to-scott-guthrie-s-using-linq-to-sql-tutorials.aspx#comments</comments><description>
&lt;p&gt;Back when Visual Studio 2008 came out, &lt;a href="http://weblogs.asp.net/scottgu/" mce_href="http://weblogs.asp.net/scottgu/"&gt;Scott Guthrie&lt;/a&gt; wrote an excellent series of blog posts on using &lt;a href="http://msdn.microsoft.com/en-us/library/bb425822.aspx" mce_href="http://msdn.microsoft.com/en-us/library/bb425822.aspx"&gt;LINQ to SQL&lt;/a&gt;. Unfortunately, the various installments are not easy to follow when starting from Part 1 and going onward, so I've decided to gather and organize the links here for myself and for anyone else interested in his tutorial.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Using LINQ to SQL&lt;/b&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2007/05/19/using-linq-to-sql-part-1.aspx" target="_blank" mce_href="http://weblogs.asp.net/scottgu/archive/2007/05/19/using-linq-to-sql-part-1.aspx"&gt;Part 1: Introduction to LINQ to SQL&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2007/05/29/linq-to-sql-part-2-defining-our-data-model-classes.aspx" target="_blank" mce_href="http://weblogs.asp.net/scottgu/archive/2007/05/29/linq-to-sql-part-2-defining-our-data-model-classes.aspx"&gt;Part 2: Defining our Data Model Classes&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2007/06/29/linq-to-sql-part-3-querying-our-database.aspx" target="_blank" mce_href="http://weblogs.asp.net/scottgu/archive/2007/06/29/linq-to-sql-part-3-querying-our-database.aspx"&gt;Part 3: Querying our Database&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2007/07/11/linq-to-sql-part-4-updating-our-database.aspx" target="_blank" mce_href="http://weblogs.asp.net/scottgu/archive/2007/07/11/linq-to-sql-part-4-updating-our-database.aspx"&gt;Part 4: Updating our Database&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2007/07/16/linq-to-sql-part-5-binding-ui-using-the-asp-linqdatasource-control.aspx" target="_blank" mce_href="http://weblogs.asp.net/scottgu/archive/2007/07/16/linq-to-sql-part-5-binding-ui-using-the-asp-linqdatasource-control.aspx"&gt;Part 5: Binding UI using the &amp;lt;asp:LinqDataSource&amp;gt; Control&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2007/08/16/linq-to-sql-part-6-retrieving-data-using-stored-procedures.aspx" target="_blank" mce_href="http://weblogs.asp.net/scottgu/archive/2007/08/16/linq-to-sql-part-6-retrieving-data-using-stored-procedures.aspx"&gt;Part 6: Retrieving Data Using Stored Procedures&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2007/08/23/linq-to-sql-part-7-updating-our-database-using-stored-procedures.aspx" target="_blank" mce_href="http://weblogs.asp.net/scottgu/archive/2007/08/23/linq-to-sql-part-7-updating-our-database-using-stored-procedures.aspx"&gt;Part 7: Updating our Database using Stored Procedures&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2007/08/27/linq-to-sql-part-8-executing-custom-sql-expressions.aspx" target="_blank" mce_href="http://weblogs.asp.net/scottgu/archive/2007/08/27/linq-to-sql-part-8-executing-custom-sql-expressions.aspx"&gt;Part 8: Executing Custom SQL Expressions&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2007/09/07/linq-to-sql-part-9-using-a-custom-linq-expression-with-the-lt-asp-linqdatasource-gt-control.aspx" mce_href="http://weblogs.asp.net/scottgu/archive/2007/09/07/linq-to-sql-part-9-using-a-custom-linq-expression-with-the-lt-asp-linqdatasource-gt-control.aspx"&gt;Part 9: Using a Custom LINQ Expression with the &amp;lt;asp:LinqDataSource&amp;gt; Control&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strike&gt;Also, there was (at one time) a single PDF containing all of these 
tutorials, but the website where it was hosted appears to be offline. 
Does anyone have a copy of that PDF they'd care to send me to host?&lt;/strike&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;UPDATE:&lt;/b&gt; Some time ago a developer by the name of Kadir Pekel compiled all nine tutorials into a single PDF and hosted them on his website, http://it-box.blogturk.net, but that website no longer is around. Helpful reader Milan had a copy of said PDF and sent it to me (thank you!), which you can download here, if interested: &lt;a href="http://www.datawebcontrols.com/classes/LINQToSql.zip" mce_href="http://www.datawebcontrols.com/classes/LINQToSql.zip"&gt;http://www.datawebcontrols.com/classes/LINQToSql.zip&lt;/a&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;Happy Programming! &lt;br&gt;&lt;/p&gt;
&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=167201" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+Talk/default.aspx">ASP.NET Talk</category><category domain="http://scottonwriting.net/sowblog/archive/tags/Miscellaneous/default.aspx">Miscellaneous</category></item><item><title>A Review of Desktop / Screen Sharing Software</title><link>http://scottonwriting.net/sowblog/archive/2010/07/18/a-review-of-desktop-screen-sharing-software.aspx</link><pubDate>Sat, 17 Jul 2010 20:32:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:166860</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>15</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=166860</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2010/07/18/a-review-of-desktop-screen-sharing-software.aspx#comments</comments><description>I work as an independent consultant and trainer. Most of my business involves me meeting with clients (in person or online), discussing their needs, and then building a new application or enhancing an existing one from my own desktop. However, a growing part of my business has been what I call "online consulting and training," which involves me using screen sharing software to remote into the client's computer. The client is seated at his computer and we are on the phone and during these meetings we'll either practice pair programming, hash out a particularly difficult block of code, or use the time as a one-on-one tutoring session. Some clients I meet with regularly (like 3 hours every week, say), while for others we meet when something comes up and they need a helping hand.
&lt;blockquote&gt;
&lt;p&gt;&lt;i&gt;If you're interested in such online consulting or training, please drop me a line at mitchell@4guysfromrolla.com. You can find out more about my experience and rates at &lt;a href="http://www.4guysfromrolla.com/ScottMitchell" mce_href="http://www.4guysfromrolla.com/ScottMitchell"&gt;http://www.4guysfromrolla.com/ScottMitchell&lt;/a&gt;.&lt;/i&gt;&lt;br&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In any event, I spend a fair amount of time - 5-15 hours a week, usually - sharing my desktop or working from the client's desktop. During these sessions there's the same sort of activities you perform when developing ASP.NET applications at your workstation: typing in code, switching between Visual Studio, the browser, running queries from SQL Server Management Studio, and so forth. I've evaluated four different screen sharing programs and thought I'd share what I liked best about each and what I liked least. Keep in mind that my rankings are based on my typical usage when sharing screens. If you are doing something different - showing a PowerPoint presentation, for instance - your mileage may vary.&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Here they are, from worst to first:&lt;/p&gt;&lt;p&gt;&lt;b&gt;#4.) &lt;a href="https://www.copilot.com/" mce_href="https://www.copilot.com/"&gt;FogCreek Copilot&lt;/a&gt;&lt;br&gt;&lt;/b&gt;Copilot has a couple of really nice selling points when compared to the other three competitors:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;It's the most affordable&lt;/b&gt; - starting at $244/year, or $24/month, Copilot is about half of what the other competitors charge. Plus you can buy a one-day pass for $5 during the week - on the weekends, it's free!&lt;/li&gt;&lt;li&gt;&lt;b&gt;It's especially easy to start the meeting&lt;/b&gt; - unlike some of the other options, which involve first time users to download and install software prior to joining the meeting, Copilot is run from an executable that doesn't require any installation steps. Just download the file, double-click it, and you're off and running. This can be helpful when assisting a computer "challenged" friend or when working with someone in a corporate environment that prohibits them from installing software on their machine.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The big problem with Copilot is that it is &lt;b&gt;slooooow&lt;/b&gt;. Switching from one full screen window to another can take a could one to three seconds. What's more, if you're not a slow typer you'll find that there is a noticeable lag when viewing a remote user's screen and typing into it. Type - wait a half-second - the letter appears. Type - wait a half-second - the letter appears. Needless to say, it can be quite frustrating to speedily type out a long line of code. I don't have the patience to type one character at a time, continuing only when the letter shows up. My clients, who are paying by the hour, wouldn't be satisfied with this approach either. So I end up typing a line of code and don't see the whole line complete until a couple of seconds after I finished typing. And if you transposed two letters or forgot a parenthesis you have to carefully (and slowly) move the cursor back to the right spot and then fix the mistake.&lt;/p&gt;&lt;p&gt;Another problem with Copilot is that you can't seamlessly switch control from one desktop to another. Say that I am viewing the client's remote computer and want to show them a diagram on my computer. It would be nice to be able to just click a button and have them see my screen, but that's not possible with Copilot. Also, Copilot only allows one-on-one screen sharing. You can't have a meeting with three (or more) attendees.&lt;/p&gt;&lt;p&gt;Copilot's ease of setup and low price point may make it attractive to people doing limited screen sharing or for those giving presentations or assisting a family member with a computer problem, but it is not a viable option for online consulting and training due, primarily, to its speed issues.&lt;/p&gt;&lt;p&gt;&lt;b&gt;#3.)&lt;/b&gt; &lt;a href="http://www.adobe.com/products/acrobatconnectpro/" mce_href="http://www.adobe.com/products/acrobatconnectpro/"&gt;&lt;b&gt;Adobe Connect Pro&lt;/b&gt;&lt;/a&gt;&lt;br&gt;Of all the desktop sharing products I evaluated, Adobe Connect Pro is certainly the easiest to get a meeting started. Adobe Connect Pro meetings are powered by Flash, which means if the participants have Flash installed on their computers (and, honestly, who doesn't these days?) then they can join the meeting. There's no software to download, nothing to install.&lt;/p&gt;&lt;p&gt;It seems that Adobe Connect Pro is more targeted to online meetings and eLearning scenarios than desktop sharing. While Adobe Connect Pro certainly allows the host (or a participant) to share their desktop with everyone else, it also has features like online quizzes, registration forms, and other features that would be useful for teaching an online class, but not at all needed for doing the type of online consulting and training that I do. And while I'm sure their online quizzes and other eLearning features are all top notch, I regret to report that their screen sharing is not - it suffers from the same speed issues found in Copilot. In short, there is a perceptible delay when typing on the remote user's computer; likewise with switching between windows on the remote computer.&lt;/p&gt;&lt;p&gt;Adobe Connect Pro is also the most expensive option out of the bunch. An annual plan will run you $540. By the month it's $55. Adobe offers a pay-per-use option, but that's $0.32 per minute per user, which can add up fast. While the two share similar speed problems, I decided to rank Adobe Connect Pro ahead of Copilot because it does offer more screen sharing features, like the ability to toggle between the host and participant's screens, and the ability to choose which monitor to share (if you have &lt;a href="http://scottonwriting.net/sowblog/archive/2008/07/10/163293.aspx" mce_href="http://scottonwriting.net/sowblog/archive/2008/07/10/163293.aspx"&gt;multiple monitors&lt;/a&gt;), and audio conferencing options. But for some these extra features might not be worth the added cost.&lt;br&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;#2.) &lt;a href="http://www.gotomeeting.com/" mce_href="http://www.gotomeeting.com/"&gt;GoToMeeting&lt;/a&gt;&lt;/b&gt;&lt;br&gt;After using Copilot and Adobe Connect Pro, the first thing you notice about GoToMeeting is that there is no longer a delay when typing. Sure, there may be a hiccup every now and then when the network gets congested, but for the most part every time you type a letter from your keyboard, wham, it appears on the remote computer instantly. Also, switching between windows on the remote computer is noticeably faster than with Copilot or Adobe Connect Pro.&lt;/p&gt;&lt;p&gt;Unlike the previous two products, GoToMeeting requires a bit more of an installation process to join (or host) a meeting. It's all very nicely automated - you only need to click a few "I Agree"s and "Next" buttons - but these extra steps might trip up a computer novice. And the need to install software may be a deal breaker in certain corporate environments.&lt;/p&gt;&lt;p&gt;My biggest gripe with GoToMeeting is that the client swallows (or outright disallows) certain keyboard shortcuts when typing from the host computer into a remote computer. And it's not just any keyboard shortcuts that are not permitted, but two of the most popular ones: Alt+Tab and Ctrl+C. Say you're writing code and want to copy some block of text and paste it elsewhere. If you're at all like me, you instinctively use the keyboard to highlight the selected text and then use Ctrl+C to copy it to the clipboard. However, this combination does not copy anything to the clipboard. Consequently, when you later hit Ctrl+V, what was previously in the clipboard gets emitted! In order to copy to the clipboard you need to select the text and then, using your mouse, right-click it and choose Copy from the context menu. Similarly, Alt+Tab doesn't work. Alt+Tab, when typed from the host computer, tabs out of the GoToMeeting window and to a different window on your desktop. If you want to switch between windows on the remote computer you have to use your mouse and click the appropriate window from the taskbar.&lt;/p&gt;&lt;p&gt;GoToMeeting has all of the screen sharing bells and whistles. You can have up to 15 participants. Sharing one participant's screen with the group or sharing the host's screen is quite simple, too. There's a phone number participants can optionally call to join an audio conference, or the conferencing can be done over the Internet using the computer's speakers and microphone.&lt;br&gt;&lt;/p&gt;&lt;p&gt;Price-wise, GoToMeeting falls in between CoPilot and Adobe Connect Pro. You can sign up for an annual plan for $468 or go monthly for $49.&lt;br&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;#1.) &lt;a href="http://www.webex.com/" mce_href="http://www.webex.com/"&gt;Webex&lt;/a&gt;&lt;/b&gt;&lt;br&gt;Webex is a lot like GoToMeeting. Both have a similar download and install story. Both cost the same. Both have comparable performance (although Webex does seem a tad bit faster to me). And both offer pretty much the same feature set. &lt;/p&gt;&lt;p&gt;The differences between the two are, by most accounts, minor ones, although as one who prefers using the keyboard over the mouse, these differences are important. Namely, the Webex client doesn't swallow keyboard shortcuts. Alt+C and Alt+Tab work as expected when typing from my keyboard to the remote client's computer. That's not to say the Webex client is not without its own annoyances. In fact, there are two that irk me. First, when the remote user is made the presenter and shares his screen with me, a little command window with various options appears on the remote computer's desktop in the lower right corner. These options are only displayed on the remote computer's screen and not on my screen. However, if I have control of the remote client's computer and move my mouse to the lower right corner and click it, my clicks are intercepted by that command window (even though I don't see it). The problem goes away if the remote client remembers to minimize that command window. It would be nice to have an option that would hide that command window right away (or not have it intercept my clicks or show it to me, as well).&lt;/p&gt;&lt;p&gt;The second issue is that when I have control of the remote client's computer a little bubble follows my mouse cursor that says to the remote client and me, "Scott has control of your computer. Click here to take control back." This bubble is supposed to be beneath the mouse cursor and offset to the right, but every now and then the mouse cursor gets positioned over it and, wouldn't you know, when that happens any mouse click is intercepted by that bubble. It doesn't revert control back to the remote client, but it does "swallow" my mouse click. I have to "jiggle the mouse" to get it off that bubble so that I can click what I meant to click in the first place.&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;In Conclusion...&lt;/b&gt;&lt;br&gt;So there you have it, Webex is the winner. You don't have to take my word for it, though - each of these products offers a free trial so you can experiment with each and find which one best fits your workload.&lt;br&gt;&lt;/p&gt;&lt;p&gt;For background, when I first started offering online consulting and training I used Copilot for several months, suffering through the speed issues. I incorrectly had presumed that all screen sharing products were going to have a little bit of lag. After one particularly frustrating day I decided to try GoToMeeting for giggles as they had a free 30 day trial. I was blown away by the difference in speed and immediately switched. The $25 extra each month was definitely worth it. Earlier this year, GoToMeeting updated their software to a new version where the Ctrl+C shortcut no longer worked. Their telephone support was helpful and was able to roll me back to the previous version so that I could continue to use the keyboard to copy and paste. A month ago (or so), they stopped supporting the old version of the software and upgraded me to the new version (which still did not support Ctrl+C). At that point I evaluated Adobe Connect Pro and then Webex, which is what I use today. &lt;/p&gt;&lt;p&gt;Happy (Remote) Programming! &lt;br&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;i&gt;In addition to evaluating these four products, I also tried &lt;a href="http://office.microsoft.com/en-us/live-meeting/" mce_href="http://office.microsoft.com/en-us/live-meeting/"&gt;Microsoft Live Meeting&lt;/a&gt;. Unfortunately, the client I attempted to evaluate this product with received error messages when attempting to download the software used by the meeting. This happened on two separate occasions, so I threw in the towel.&lt;/i&gt;&lt;br&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=166860" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/Miscellaneous/default.aspx">Miscellaneous</category></item><item><title>New Software Running ScottOnWriting.NET</title><link>http://scottonwriting.net/sowblog/archive/2010/05/27/new-software-running-scottonwriting-net.aspx</link><pubDate>Thu, 27 May 2010 18:50:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:163404</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=163404</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2010/05/27/new-software-running-scottonwriting-net.aspx#comments</comments><description>&lt;p&gt;When I &lt;a href="http://scottonwriting.net/sowblog/archive/2003/07/02/162659.aspx" mce_href="http://scottonwriting.net/sowblog/archive/2003/07/02/162659.aspx"&gt;started this blog in July 2003&lt;/a&gt; there weren't many available blog engines build atop ASP.NET. One of the more interesting ones at the time was &lt;a href="http://scottw.com/" mce_href="http://scottw.com/"&gt;Scott Watermasysk&lt;/a&gt;'s &lt;b&gt;.Text&lt;/b&gt; blog engine (which eventually became part of &lt;a href="http://telligent.com/" mce_href="http://telligent.com/"&gt;&lt;b&gt;Community Server&lt;/b&gt;&lt;/a&gt;. Over the past nearly seven years ScottOnWriting.NET has continued to be powered by .Text, even though the code base was discontinued circa 2004. There were two primary reasons I stuck with .Text for so long:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;I could find no easy way to migrate my existing content from .Text into Community Server. I believe there was such a tool created in the early days of Community Server, but I had no luck with it, as I recall. Eventually, this product disappeared and the only migration tools I could find were from older versions of Community Server to newer ones, but none for .Text.&lt;/li&gt;&lt;li&gt;There were URL changes between .Text and Community Server, so switching over would immediately result in a slew of broken URLs. I am &lt;a href="http://scottonwriting.net/sowblog/archive/2005/04/12/163063.aspx" mce_href="http://scottonwriting.net/sowblog/archive/2005/04/12/163063.aspx"&gt;a strong believer in URLs as public interfaces&lt;/a&gt; and view broken URLs and believe each broken URL makes the Internet that less useful. Plus it makes the Internet Founding Fathers - Tim Berners-Lee, Vint Cerf, and Al Gore - cry. &lt;img src="http://nbaweblog.com/emoticons/emotion-1.gif" alt="Smile" /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Well, this week I decided to take the plunge and move ScottOnWriting.NET and its hundreds of posts over to a new blog engine, namely Community Server (albeit an older version of Community Server - when will I learn?). I wrote some custom SQL scripts to (the best of my ability) move over all blog posts and categories (or tags, as they're called now-a-days). I also spent a good deal of time writing some regular expressions and very big switch statements to properly reroute URLs. For example, if you try to visit an old ScottOnWriting.NET URL, like http://scottonwriting.net/sowBlog/posts/145.aspx, you should be automatically redirected to the new URL, http://scottonwriting.net/sowBlog/archive/0000/00/00/162659.aspx. Likewise, if you visit an old category URL or an old moth/year archive URL you should be redirected to the new URLs. &lt;b&gt;If this is not the case, if you find a broken URL or other problem on this site, please &lt;a href="http://scottonwriting.net/sowblog/contact.aspx" mce_href="http://scottonwriting.net/sowblog/contact.aspx"&gt;let me know&lt;/a&gt;.&lt;/b&gt; &lt;/p&gt;&lt;p&gt;Note that I did not mention bringing over the past blog comments. I'm still on the fence as to whether I want to spend the time to do this. There were hundreds of comments left over the years, many of them quite helpful and many that added substantially to the discussion. However, I've already sunk a number of hours into this migration and am hesitant to burn too much more time. Plus I still have a number of aesthetic and cosmetic things to do, like update the site's CSS, add in some of the widgets from the original site that aren't part of the default Community Server setup, and so forth. My goal is to eventually import these past comments, but I wouldn't be at all surprised if this is still on my TODO list come 2011.&lt;/p&gt;&lt;p&gt;In closing, please do &lt;a href="http://scottonwriting.net/sowblog/contact.aspx" mce_href="http://scottonwriting.net/sowblog/contact.aspx"&gt;let me know if you run into any problems&lt;/a&gt; with the new blog engine.&lt;/p&gt;&lt;p&gt;Thanks! &lt;br&gt;&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=163404" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/Miscellaneous/default.aspx">Miscellaneous</category><category domain="http://scottonwriting.net/sowblog/archive/tags/Blog+Enhancements/default.aspx">Blog Enhancements</category></item><item><title>Authorize.Net, Silent Posts, and URL Rewriting Don't Mix</title><link>http://scottonwriting.net/sowblog/archive/2010/04/19/163378.aspx</link><pubDate>Mon, 19 Apr 2010 22:57:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:163378</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=163378</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2010/04/19/163378.aspx#comments</comments><description>&lt;p&gt;&lt;strong&gt;&lt;font color="#ff0000"&gt;The &lt;em&gt;too long, didn't read&lt;/em&gt; synopsis:&lt;/font&gt; If you use Authorize.Net and its silent post feature and it stops working, make sure that if your website uses URL rewriting to strip or add a www to the domain name that the URL you specify for the silent post matches the URL rewriting rule because Authorize.Net's silent post feature won't resubmit the post request to URL specified via the redirect response.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I have a client that uses Authorize.Net to manage and bill customers. Like many payment gateways, Authorize.Net supports recurring payments. For example, a website may charge members a monthly fee to access their services. With Authorize.Net you can provide the billing amount and schedule and at each interval Authorize.Net will automatically charge the customer's credit card and deposit the funds to your account.&lt;/p&gt;
&lt;p&gt;You may want to do something whenever Authorize.Net performs a recurring payment. For instance, if the recurring payment charge was a success you would extend the customer's service; if the transaction was denied then you would cancel their service (or whatever). To accomodate this, Authorize.Net offers a &lt;em&gt;silent post&lt;/em&gt; feature. Properly configured, Authorize.Net will send an HTTP request that contains details of the recurring payment transaction to a URL that you specify. This URL could be an ASP.NET page on your server that then parses the data from Authorize.Net and updates the specified customer's account accordingly. (Of course, you can always view the history of recurring payments through the reporting interface on Authorize.Net's website; the silent post feature gives you a way to programmatically respond to a recurring payment.)&lt;/p&gt;
&lt;p&gt;Recently, this client of mine that uses Authorize.Net informed me that several paying customers were telling him that their access to the site had been cut off even though their credit cards had been recently billed. Looking through our logs, I noticed that we had not shown any recurring payment log activity for over a month. I figured one of two things must be going on: either Authorize.Net wasn't sending us the silent post requests anymore or the page that was processing them wasn't doing so correctly. &lt;/p&gt;
&lt;p&gt;I started by verifying that our Authorize.Net account was properly setup to use the silent post feature and that it was pointing to the correct URL. Authorize.Net's site indicated the silent post was configured and that recurring payment transaction details were being sent to http://example.com/AuthorizeNetProcessingPage.aspx.&lt;/p&gt;
&lt;p&gt;Next, I wanted to determine what information was getting sent to that URL. The application was setup to log the &lt;em&gt;parsed results&lt;/em&gt; of the Authorize.Net request, such as what customer the recurring payment applied to; however, we were not logging the actual HTTP request coming from Authorize.Net. I contacted Authorize.Net's support to inquire if they logged the HTTP request send via the silent post feature and was told that they did not.&lt;/p&gt;
&lt;p&gt;I decided to add a bit of code to log the incoming HTTP request, which you can do by using the &lt;font face="Courier New"&gt;Request&lt;/font&gt; object's &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.httprequest.saveas.aspx"&gt;&lt;font face="Courier New"&gt;SaveAs&lt;/font&gt; method&lt;/a&gt;. This allowed me to save every incoming HTTP request to the silent post page to a text file on the server. Upon the next recurring payment, I was able to see the HTTP request being received by the page:&lt;/p&gt;
&lt;p&gt;&lt;font face="Courier New"&gt;GET /AuthorizeNetProcessingPage.aspx HTTP/1.1&lt;br /&gt;Connection: Close&lt;br /&gt;Accept: */*&lt;br /&gt;Host: &lt;/font&gt;&lt;font face="Courier New"&gt;www.example.com&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;That was it. Two things alarmed me: first, the request was obviously a GET and not a POST; second, there was no POST body (obviously), which is where Authorize.Net passes along the details of the recurring payment transaction. What stuck out was the &lt;font face="Courier New"&gt;Host&lt;/font&gt; header, which differed slightly from the silent post URL configured in Authorize.Net. Specifically, the &lt;font face="Courier New"&gt;Host&lt;/font&gt; header in the above logged request pointed to &lt;strong&gt;&lt;font color="#ff0000"&gt;www&lt;/font&gt;&lt;/strong&gt;.example.com, whereas the Authorize.Net configuration used example.com (no &lt;strong&gt;&lt;font color="#ff0000"&gt;www&lt;/font&gt;&lt;/strong&gt;). About a month ago - the same time these recurring payment transaction details were no longer being processed by our ASP.NET page - we had implemented IIS 7's URL rewriting feature to permanently redirect all traffic to example.com to &lt;strong&gt;&lt;font color="#ff0000"&gt;www&lt;/font&gt;&lt;/strong&gt;.example.com. &lt;/p&gt;
&lt;p&gt;Could that be the problem? I contacted Authorize.Net's support again and asked them if their silent post algorithm would follow the &lt;a href="http://en.wikipedia.org/wiki/HTTP_301"&gt;301 HTTP response&lt;/a&gt; and repost the recurring payment transaction details. They said, Yes, the silent post would follow redirects. Their reports didn't jive with my observations, so I went ahead and updated our Authorize.Net configuration to point to http://&lt;strong&gt;&lt;font face="Courier New"&gt;www&lt;/font&gt;&lt;/strong&gt;.example.com/AuthorizeNetProcessingPage.aspx instead of http://example.com/AuthorizeNetProcessingPage.aspx. And, I'm happy to report, recurring payments and correctly being processed again!&lt;/p&gt;
&lt;p&gt;If you use Authorize.Net and the silent post feature, and you notice that your processing page is not longer working, make sure you are not using any URL rewriting rules that may conflict with the silent post URL configuration. Hope this saves someone the time it took me to get to the bottom of this.&lt;/p&gt;
&lt;p&gt;Happy Programming!&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=163378" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/Miscellaneous/default.aspx">Miscellaneous</category></item><item><title>Determining Whether a String Is Contained Within a String Array (Case Insensitive)</title><link>http://scottonwriting.net/sowblog/archive/2010/03/09/163376.aspx</link><pubDate>Tue, 09 Mar 2010 19:14:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:163376</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=163376</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2010/03/09/163376.aspx#comments</comments><description>&lt;p&gt;About once every couple of months I need to write a bit of code that does one thing if a particular string is found within an array of strings and something else if it is not &lt;strong&gt;ignoring differences in case&lt;/strong&gt;. For whatever reason, I never seem to remember the code snippet to accomplish this, so after spending 10 minutes of research today I thought I'd write it down here in an effort to help commit it to memory or, at the very least, serve as a quick place to find the answer when the need arises again.&lt;/p&gt;
&lt;p&gt;So without further adieu, here it is:&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Visual Basic Version:&lt;/b&gt;&lt;/p&gt;&lt;pre class="brush: vb"&gt;If stringArrayName.Contains("valueToLookFor", StringComparer.OrdinalIgnoreCase) Then
    ...
Else
    ...
End If&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;C# Version:&lt;/b&gt;&lt;/p&gt;&lt;pre class="brush: c#"&gt;if (stringArrayName.Contains("valueToLookFor", StringComparer.OrdinalIgnoreCase))
    ...
else
    ...&lt;/pre&gt;
&lt;p&gt;Without the &lt;b&gt;StringComparer.OrdinalIgnoreCase&lt;/b&gt; the search will be case-sensitive. For more information on comparing strings, see: &lt;a href="http://msdn.microsoft.com/en-us/library/ms973919.aspx"&gt;New Recommendations for Using Strings in Microsoft .NET 2.0&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy Programming!&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=163376" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/Miscellaneous/default.aspx">Miscellaneous</category></item><item><title>SOLUTION: Outlook Is Stripping Line Breaks From Plain-Text Emails Auto-Generated From My ASP.NET Application!</title><link>http://scottonwriting.net/sowblog/archive/2009/12/08/163373.aspx</link><pubDate>Tue, 08 Dec 2009 16:36:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:163373</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=163373</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2009/12/08/163373.aspx#comments</comments><description>&lt;p&gt;Today I was working on an ASP.NET application that sends out plain-text emails to site administrators when certain conditions unfold. One problem I unearthed today is that when viewing these emails in Microsoft Outlook many of the carriage returns were being removed, making the email difficult to read. The code to generate the body of these emails is very simple and straightforward, looking something like:&lt;/p&gt;
&lt;pre class="brush: c#"&gt;StringBuilder body = new StringBuilder();
body.Append("Information of interest:").Append(Environment.NewLine);
body.AppendFormat("Item #1: {0}", someValue).Append(Environment.NewLine);
body.AppendFormat("Item #2: {0}", someOtherValue).Append(Environment.NewLine);
body.AppendFormat("Item #3: {0}", yetAnotherValue).Append(Environment.NewLine);
...&lt;/pre&gt;
&lt;p&gt;When viewing the message in Outlook it would come out like so:&lt;/p&gt;
&lt;p&gt;Information of interest:&lt;br /&gt;Item #1: blah Item #2: blah blah Item #3: blah blah blah&lt;/p&gt;
&lt;p&gt;Note how the carriage returns between each of the three items has been removed. Boo. The behavior is not due to the code that generates the email, but rather how Outlook displays a message. (For instance, GMail displays the carriage returns as you'd expect.) Outlook strips out what it identifies an unnecessary carriage returns. If you open the email in Outlook you'll see a little informational bar at the top of the email explaining that Outlook has removed extra line breaks and that you can click it to add them back in. Furthermore, you can configure Outlook to never remove such carriage returns by going to Tools --&amp;gt; Options, clicking the E-mail Options button, and then unchecking “Remove extra line breaks in plain text messages.“&lt;/p&gt;
&lt;p&gt;Of course, it's never a good strategy to tell you customers that the problem is on their end and that they need to do something to fix the problem. The good news is that there appears to be a way that you can format the line breaks so that Outlook won't automatically remove them. I got this tip from member &lt;a href="http://forums.asp.net/members/scarecrow_2D00_rye.aspx"&gt;scarecrow-rye&lt;/a&gt; at the ASP.NET Forums, in the post &lt;a href="http://forums.asp.net/p/1220479/2176064.aspx"&gt;Email text message line breaks not working&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote style="MARGIN-RIGHT: 0px" dir="ltr"&gt;
&lt;p&gt;Try including an empty space character at the end of each line. Certainlty seems to work for me.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p dir="ltr"&gt;And it worked for me, too. With this little adjustment to the code, Outlook stopped stripping out what it had earlier deemed as extra line breaks:&lt;/p&gt;
&lt;pre class="brush: c#"&gt;StringBuilder body = new StringBuilder();
body.Append("Information of interest:").Append(Environment.NewLine);
body.AppendFormat("Item #1: {0} ", someValue).Append(Environment.NewLine);
body.AppendFormat("Item #2: {0} ", someOtherValue).Append(Environment.NewLine);
body.AppendFormat("Item #3: {0} ", yetAnotherValue).Append(Environment.NewLine);
...&lt;/pre&gt;
&lt;p dir="ltr"&gt;Note the extra space between the value and the end of the string.&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=163373" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+Talk/default.aspx">ASP.NET Talk</category><category domain="http://scottonwriting.net/sowblog/archive/tags/Miscellaneous/default.aspx">Miscellaneous</category></item><item><title>SOLUTION: JSLint.VS Add-In Always Reports "No Errors" Even For Invalid JavaScript Files</title><link>http://scottonwriting.net/sowblog/archive/2009/10/15/163367.aspx</link><pubDate>Thu, 15 Oct 2009 19:49:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:163367</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=163367</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2009/10/15/163367.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://jslint.com/"&gt;&lt;strong&gt;JSLint&lt;/strong&gt;&lt;/a&gt; is a free JavaScript code quality tool created by &lt;a href="http://www.crockford.com/"&gt;Douglas Crockford&lt;/a&gt;. At the &lt;a href="http://jslint.com/"&gt;JSLint.com website&lt;/a&gt; you can paste in a block of JavaScript code and JSLint will examine the code and warn you when it encounters any script that violates its list of rules. Many of the rules JSLint checks against are configurable, and include checks for usage of undefined variables, use of the &lt;font face="Courier New"&gt;eval&lt;/font&gt; function, statements not terminated with semicolons, and other 'trouble waiting for a place to happen' coding patterns.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://jslint.codeplex.com/"&gt;&lt;strong&gt;JSLint.VS&lt;/strong&gt;&lt;/a&gt; is a free, open source Visual Studio Add-In created by Predrag Tomasevic that brings JSLint to the Visual Studio IDE. &lt;/p&gt;
&lt;p&gt;Today I installed JSLint.VS for the first time on a machine. The installation went smoothly, but anytime I used the Add-In it reported &lt;strong&gt;No Errors&lt;/strong&gt;, even though the JSLint.com website was finding errors with the same block of JavaScript code. The good news is that I was able to identify the problem and fix it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Just the Workaround, Please&lt;/strong&gt;&lt;br /&gt;For JSLint.VS to work the &lt;font face="Courier New"&gt;.js&lt;/font&gt; extension must be associated with the JScript WSH engine. Chances are, you have the JScript WSH engine already installed, but another program has claimed the association. In my case, the &lt;font face="Courier New"&gt;.js&lt;/font&gt; extension was associated with &lt;a href="http://www.ultraedit.com/"&gt;UltraEdit&lt;/a&gt;. Once I reassociated it with the JScript engine, the JSLint.VS Add-In worked as expected.&lt;/p&gt;
&lt;p&gt;To see what program the &lt;font face="Courier New"&gt;.js&lt;/font&gt; extension is associated with, drop to the command line and enter:&lt;/p&gt;
&lt;blockquote style="MARGIN-RIGHT: 0px" dir="ltr"&gt;
&lt;p&gt;&lt;font face="Courier New"&gt;assoc .js&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;The output should be: &lt;font face="Courier New"&gt;.js=JScript&lt;/font&gt;. If it's not, enter:&lt;/p&gt;
&lt;blockquote style="MARGIN-RIGHT: 0px" dir="ltr"&gt;
&lt;p&gt;&lt;font face="Courier New"&gt;assoc .js=JScript&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Now try JSLint.VS again.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For Those Who Care... The Why...&lt;/strong&gt;&lt;br /&gt;When you launch JSLint.VS from within the IDE it creates three files in the Application Data folder (&lt;font face="Courier New"&gt;My Documents\&lt;em&gt;User&lt;/em&gt;\Application Data&lt;/font&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;font face="Courier New"&gt;&lt;strong&gt;wsh.js&lt;/strong&gt;&lt;/font&gt; - contains the JSLint JavaScript code, which you can download from &lt;a href="http://www.jslint.com/fulljslint.js"&gt;http://www.jslint.com/fulljslint.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;font face="Courier New"&gt;&lt;strong&gt;temp.js&lt;/strong&gt;&lt;/font&gt; - contains the JavaScript code to check with JSLint&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;font face="Courier New"&gt;csh.cmd&lt;/font&gt;&lt;/strong&gt; - a batch file that executes the &lt;font face="Courier New"&gt;wsh.js&lt;/font&gt; file, passing in the &lt;font face="Courier New"&gt;temp.js&lt;/font&gt; contents as input.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Specifically, JSLint.VS executes the following command:&lt;/p&gt;
&lt;blockquote style="MARGIN-RIGHT: 0px" dir="ltr"&gt;
&lt;p&gt;&lt;font face="Courier New"&gt;csh.cmd wsh.js &amp;lt; temp.js&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;If the &lt;font face="Courier New"&gt;.js&lt;/font&gt; extension is not mapped to the JScript WSH engine the above command will result in the following error message: “There is no script engine for file extension .js”&lt;/p&gt;
&lt;p&gt;In the face of that error, JSLint.VS simply returns, “No Errors.” Once you associate the &lt;font face="Courier New"&gt;.js&lt;/font&gt; extension with the JScript WSH engine you should be good to go!&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=163367" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+Talk/default.aspx">ASP.NET Talk</category><category domain="http://scottonwriting.net/sowblog/archive/tags/Miscellaneous/default.aspx">Miscellaneous</category></item><item><title>Installing the FTP Service for IIS 6.0 On An Alternate Port Number and Configuring Windows Firewall</title><link>http://scottonwriting.net/sowblog/archive/2009/06/17/163352.aspx</link><pubDate>Wed, 17 Jun 2009 20:01:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:163352</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=163352</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2009/06/17/163352.aspx#comments</comments><description>&lt;p&gt;&lt;strong&gt;The Scenario&lt;br /&gt;&lt;/strong&gt;You need to setup the Windows FTP service that is part of IIS 6.0 on a port number other than the standard port 21 and are using Windows Firewall on the server.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Challenge&lt;/strong&gt;&lt;br /&gt;Getting an FTP server and the firewall to play nicely can be a bit of an adventure because FTP uses two ports for communicating - one for establishing the connection (typically port 21) and another one for transferring the data. I believe that the FTP service for IIS 6.0 uses port 20 as the data port when using port 21 as the connection port, but I am not 100% certain. What I am certain of is that the data port may be randomly selected from a wide range of ports, and that is certainly the case when you select an alternate port number for the FTP service. The challenge lies in configuring the firewall to accept incoming requests to both the alternate port and the randomly selected data port.&lt;/p&gt;
&lt;p&gt;If neither port is opened in the firewall then when you attempt to connect to the FTP server the client will hang and eventually report that it cannot connect. If only the connection port is open then the FTP client will connect successfully but will repor the error: &lt;em&gt;Failed to retrieve directory listing&lt;/em&gt;. The reason is because the connection can be established over the connection port, but the request made to the data port to get the directory listing was blocked by the firewall. Long story short, you need to make sure that the firewall will allow traffic for the randomly selected data port.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Solution&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create an FTP site on the port number of choice, such as 12345. Typically you'll want to use a high port number to minimize the likelihood of a conflict. See &lt;a href="http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/51f630b2-37c0-48a2-bbb0-ab35ceb6beef.mspx?mfr=true"&gt;Creating Multiple FTP Site (IIS 6.0)&lt;/a&gt; for more information on how to create multiple FTP sites using multiple ports.&lt;/li&gt;
&lt;li&gt;If you are using Windows Vista or Windows 2008 as the server, run the following command from the command line: &lt;strong&gt;sc sidtype MSFTPSVC unrestricted&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Stop and restart the FTP service. &lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Note:&lt;/strong&gt; I got an error when restarting the service that complained that an unrestricted service could not be started in the same host as restricted services. I'm sure there is a more elegant workaround, but what worked for me was to reboot the server.&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;Configure Windows Firewall to allow &lt;em&gt;all&lt;/em&gt; TCP traffic in for the MSFTPSVC service. This will allow traffic on the randomly selected data port to penetrate the firewall. You can do this from the Windows Firewall configuration GUI or from the command line via: &lt;strong&gt;netsh advfirewall firewall add rule name="FTP" service=MSFTPSVC action=allow protocol=TCP dir=in&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Ensure that the FTP filter for Windows Firewall is disabled. You can do this via the command line, as well: &lt;strong&gt;netsh advfirewall set global Statefulftp disable&lt;/strong&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;For more on Steps 2-5 see &lt;a href="http://blogs.iis.net/jaroslad/archive/2007/09/29/windows-firewall-setup-for-microsoft-ftp-publishing-service-for-iis-7-0.aspx"&gt;Windows Firewall Setup for Microsoft FTP Publishing Service for IIS 7.0&lt;/a&gt;. Some of the command line arguments are different in the article than what I have posted above because my commands are for the FTP Service that's part of IIS 6.0 whereas the article linked to looks at using the FTP Publishing Service for IIS 7.0.&lt;/p&gt;
&lt;p&gt;I spent the better part of an afternoon figuring out these five steps. I hope this blog entry saves someone else a few precious hours.&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=163352" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/Miscellaneous/default.aspx">Miscellaneous</category></item><item><title>Happy Pi Day</title><link>http://scottonwriting.net/sowblog/archive/2009/03/14/163345.aspx</link><pubDate>Sat, 14 Mar 2009 16:53:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:163345</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=163345</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2009/03/14/163345.aspx#comments</comments><description>&lt;p&gt;Our esteemed House of Representatives passed &lt;a href="http://thomas.loc.gov/cgi-bin/query/D?c111:1:./temp/~c111HwlT9j::"&gt;a resolution&lt;/a&gt; earlier this week, designating today - March 14th - National Pi Day. This is an American-centric 'holiday,' as we colloquially denote our dates in MM/DD format, hence March 14th is 3.14, the first three digits of Pi. Most other countries start with the least significant date part and work their way to the most significant - DD/MM/YY - which would mean the International Pi Day should fall on the 3rd day of the 14th month (hrm) or the 31st day of the 4th month, i.e., April 31st (hrm, again). Of course, God-fearing computer scientists denote dates from the most significant to the least, always using four digits for the year - YYYY/MM/DD - which would place Computer Scientist Pi Day on May 9th, 3141 if you were being flexible on parsing the month and day and allowing either one or two characters.&lt;/p&gt;
&lt;p&gt;As we all learned in elementary school, &lt;a href="http://en.wikipedia.org/wiki/Pi"&gt;Pi&lt;/a&gt; is the ratio between the area of a circle and its radius, squared, or the ratio between the circle's circumference and its diameter, and approximates 3.14159. One of the shortcomings of mathematical education in our schools is that math is initially introduced in a way that suggests that its rules and results are handed down by some oracle. Furthermore, children are taught that learning math involves mindless memorization. I think this turns a lot of kids against math; they end up thinking that it's some stuffy, boring pursuit that is of little interest. But there are interesting ways to present math, and ways in which the child discovers first hand why certain things are the way they are. And explaining why Pi approximates 3.14159 is a great example of a more involved and interactive form of math education.&lt;/p&gt;
&lt;p&gt;My daughter is 6 months old, but one day I plan on sharing the following math discovery with her. I don't know when this would be age appropriate. The first part - computing Pi as a ratio of the circumference and diameter - only requires understanding of division, and I imagine it could be introduced around age seven or eight. The second 'experiment' involves areas and necessitates understanding exponentiation and square roots, and would probably have to wait until age 10, or so.&lt;/p&gt;
&lt;p&gt;Start by drawing some circles (with a compass) and talking about the components of the circle - the circumference, the area, the radius, the diameter. It's pretty clear that there's some relationship between these components. A bigger radius means a larger area and a longer circumference. Next, get out some string and measure some of the circles' circumferences. It becomes clear that a circle with twice the radius has twice the circumference. But given just the radius, can one arrive at the circumference? There is some missing number that we need to arrive at this, and this can be approximated empirically: using the string, measure out the circumference for a circle and then hold the string up to a ruler. Divide this measurement by the diameter and you should arrive at a value that approximates Pi. Using this newly discovered number, tackle the problem the other way around - starting from a known diameter, what should the circumference be? Compute it, then measure it with the string and see how the values align.&lt;/p&gt;
&lt;p&gt;Can we devise some ratio between the radius and the area? When in doubt, get out the graph paper! Start by deciding on a radius and then determine what points on the graph paper are bounded by a circle with said radius. I'm not sure the best way to explain this to the pupil in a way that isn't along the lines of, "This is the way it is," but the square at coordinates (x,y) on the graph paper is bounded by the circle if the square root of x2 + y2 is less than or equal to the radius. Using that knowledge, visit each square on the graph paper and apply the formula. If the square root is indeed less than x&lt;sup&gt;2&lt;/sup&gt; + y&lt;sup&gt;2&lt;/sup&gt; then shade in the square, otherwise leave it empty. After enumerating the squares, count up the shaded ones and divide that total by the radius squared. And, lo!, the result is eerily similar to the number we were getting when dividing the circumference by the diameter. Repeat the graph paper process a couple times with larger radiuses. As the radius gets larger, the area is computed more accurately as the edges of the circle are less jagged. Consequently, the ratio of the area and the radius gets more and more refined and close to the true value of Pi.&lt;/p&gt;
&lt;p&gt;And if my daughter enjoys computers and likes spending time giving them instructions (fingers crossed), the final part of the lesson would be to have the computer do the grunt work for us. Why spend all afternoon shading in graph paper squares when a computer can shade in millions of squares for us in seconds? Here's a snippet of C# that approximates Pi.&lt;/p&gt;
&lt;div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Courier New"&gt;
&lt;p style="MARGIN: 0px"&gt;&lt;span style="COLOR: blue"&gt;const&lt;/span&gt; &lt;span style="COLOR: blue"&gt;int&lt;/span&gt; r = 10;&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;&lt;span style="COLOR: blue"&gt;int&lt;/span&gt; A = 0;&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt; &lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;&lt;span style="COLOR: blue"&gt;for&lt;/span&gt; (&lt;span style="COLOR: blue"&gt;int&lt;/span&gt; x = -r; x &amp;lt; r; x++)&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;    &lt;span style="COLOR: blue"&gt;for&lt;/span&gt; (&lt;span style="COLOR: blue"&gt;int&lt;/span&gt; y = -r; y &amp;lt; r; y++)&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;        &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (&lt;span style="COLOR: #2b91af"&gt;Math&lt;/span&gt;.Sqrt(x * x + y * y) &amp;lt;= r)&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;            A++;&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt; &lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;&lt;span style="COLOR: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="COLOR: #a31515"&gt;"Enjoy a slice of {0}"&lt;/span&gt;, &lt;span style="COLOR: #2b91af"&gt;Convert&lt;/span&gt;.ToDouble(A) / &lt;span style="COLOR: #2b91af"&gt;Convert&lt;/span&gt;.ToDouble(r * r));&lt;/p&gt;&lt;/div&gt;&lt;!--EndFragment--&gt;
&lt;p&gt;You can adjust the value of &lt;font face="Courier New"&gt;&lt;em&gt;r&lt;/em&gt;&lt;/font&gt; to see how the approximation becomes more refined. For example, when &lt;font face="Courier New"&gt;&lt;em&gt;r&lt;/em&gt;&lt;/font&gt; = 10 the approximation is 3.15. With &lt;font face="Courier New"&gt;&lt;em&gt;r&lt;/em&gt;&lt;/font&gt; = 100 it's 3.1415. Of course, too large of a radius results in an overflow, which is a great segue into a discussion on how computers represent numbers!&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=163345" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/Miscellaneous/default.aspx">Miscellaneous</category></item><item><title>Computer Science Is All About Tradeoffs</title><link>http://scottonwriting.net/sowblog/archive/2009/03/13/163344.aspx</link><pubDate>Sat, 14 Mar 2009 02:37:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:163344</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=163344</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2009/03/13/163344.aspx#comments</comments><description>&lt;p&gt;I oftentimes have a student or client remark, “I love how technology &lt;em&gt;X&lt;/em&gt; does &lt;em&gt;Y&lt;/em&gt;! However, I don't like &lt;em&gt;X&lt;/em&gt; because it does &lt;em&gt;Z&lt;/em&gt;.”&lt;/p&gt;
&lt;p&gt;I don't know what else to say other than, “Ok,” or “I concur,” because after all, that's what computer science, and perhaps all of engineering, is all about - tradeoffs. There is no silver bullet. There is no panacea. Solutions are created to solve a specific problem, but the solution has shortcomings or deficits in other areas. That's life as a software developer.&lt;/p&gt;
&lt;p&gt;If there were a silver bullet, if some technology existed that solved all the problems with no shortcomings elsewhere, we'd all be out of a job.&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=163344" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/Miscellaneous/default.aspx">Miscellaneous</category></item></channel></rss>