<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-18907707</id><updated>2012-02-02T05:23:59.537-08:00</updated><category term='Social Media'/><category term='Cookieless session'/><category term='Visual Studio'/><category term='XSD'/><category term='SQL'/><category term='Late'/><category term='Item Template'/><category term='VB.NET'/><category term='Query String'/><category term='open source'/><category term='Feedback'/><category term='Building Software'/><category term='Web'/><category term='ASP.NET'/><category term='Testing'/><category term='MongoDB'/><category term='Code'/><category term='Code Generation'/><category term='Linq2Sql'/><category term='High Level'/><category term='Object Graphs'/><category term='FTP'/><category term='Extension Methods'/><category term='Linq to SQL'/><category term='Documentation'/><category term='voting'/><category term='StackOverflow'/><category term='DataView'/><category term='CSS'/><category term='Obscurity'/><category term='What I&apos;m Doing'/><category term='Popup'/><category term='URL'/><category term='The TC'/><category term='teams'/><category term='Refactoring'/><category term='System Tables'/><category term='Playoffs'/><category term='VBA'/><category term='Semi-Agile'/><category term='iPhone'/><category term='A T and T'/><category term='MDI'/><category term='Mobipocket'/><category term='NFL'/><category term='Software Quality'/><category term='XML Comments'/><category term='Presentation Notes'/><category term='RickRoll'/><category term='nullabletypes'/><category term='Note to Work'/><category term='Polls'/><category term='Entity Framework'/><category term='GAX'/><category term='T4 Toolbox'/><category term='Kindle'/><category term='Twitter'/><category term='T4 Templates'/><category term='Microsoft'/><category term='Windows 8'/><category term='Evil'/><category term='Code Camp'/><category term='Non-Technical'/><category term='Frontpage'/><category term='The Gu'/><category term='Types'/><category term='Access'/><category term='Samus'/><category term='Portland Code Camp'/><category term='DataSet'/><category term='Framework'/><category term='FileInfo'/><category term='Alt .Net Seattle'/><category term='Small Business'/><category term='Writing'/><category term='Boise Code Camp'/><category term='Cut and Paste'/><category term='Flair'/><category term='HP'/><category term='Rick Astley'/><category term='Nortwind'/><category term='Small Projects'/><category term='CEO Pay'/><category term='Generics'/><category term='Seahawks'/><category term='ADO.NET'/><category term='C#'/><category term='Economy'/><category term='Linq'/><category term='Lame Laptop'/><category term='Groundhog Day'/><category term='Linq2DataSet'/><category term='Psycho Analysis'/><category term='Verizon'/><category term='career'/><category term='JQuery AJAX'/><category term='Tablet'/><category term='Alt .Net; TDD'/><category term='Macros'/><category term='Sports'/><category term='jrcs3.com'/><category term='Football'/><title type='text'>Jack Stephens' Geek Brochure</title><subtitle type='html'>A Trek through .NET Programming, Life, our current Universe, etc.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>74</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-18907707.post-5364270799055833800</id><published>2012-02-02T05:23:00.000-08:00</published><updated>2012-02-02T05:23:59.547-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Groundhog Day'/><title type='text'>Happy Groundhog Day!</title><content type='html'>&lt;p&gt;Punxsutawney Phil, some rodent 2,000 miles from me sees his shadow so we get 6 more weeks of winter. Had he not seen it, winter would only 42 days left. I will have my traditional Groundhog Day dinner of pork sausage.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-5364270799055833800?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/5364270799055833800/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=5364270799055833800' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5364270799055833800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5364270799055833800'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2012/02/happy-groundhog-day.html' title='Happy Groundhog Day!'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total><georss:featurename>Cliff Cannon, Spokane, WA, USA</georss:featurename><georss:point>47.65043081237029 -117.4223075255394</georss:point><georss:box>47.641955312370285 -117.4421415255394 47.65890631237029 -117.40247352553939</georss:box></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-3912991147143001188</id><published>2012-01-11T07:07:00.001-08:00</published><updated>2012-01-11T07:13:30.933-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Linq'/><title type='text'>Less Than Simple Group By LINQ Queries</title><content type='html'>&lt;p&gt; &lt;p&gt;Lately I have been going through LINQ. Most of it has been review, however I ran across something that I really didn’t understand. That area: Grouping.  &lt;p&gt;Suppose I wanted to write a LINQ query which would do the following:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;SELECT &lt;/span&gt;a&lt;span style="color: gray"&gt;.&lt;/span&gt;city&lt;span style="color: gray"&gt;, &lt;/span&gt;&lt;span style="color: magenta"&gt;COUNT&lt;/span&gt;&lt;span style="color: gray"&gt;(*) &lt;/span&gt;&lt;span style="color: blue"&gt;AS &lt;/span&gt;&lt;span style="color: magenta"&gt;Count&lt;br /&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;FROM &lt;/span&gt;authors a&lt;br /&gt;&lt;span style="color: blue"&gt;GROUP BY &lt;/span&gt;a&lt;span style="color: gray"&gt;.&lt;/span&gt;city&lt;/pre&gt;I can easily render this into LINQ as follows (&lt;a href="http://www.linqpad.net/"&gt;LINQPad&lt;/a&gt; C# Expression): &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;from &lt;/span&gt;&lt;span style="color: black"&gt;a &lt;/span&gt;&lt;span style="color: blue"&gt;in &lt;/span&gt;&lt;span style="color: black"&gt;Authors &lt;br /&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;group &lt;/span&gt;&lt;span style="color: black"&gt;a &lt;/span&gt;&lt;span style="color: blue"&gt;by &lt;/span&gt;&lt;span style="color: black"&gt;a.City &lt;/span&gt;&lt;span style="color: blue"&gt;into &lt;/span&gt;&lt;span style="color: black"&gt;c&lt;/span&gt;&lt;span style="color: blue"&gt; &lt;br /&gt;select new &lt;br /&gt;&lt;/span&gt;&lt;span style="color: black"&gt;{&lt;br /&gt;    City = c.Key, &lt;br /&gt;    Count = c.Count()&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;When things got just a little bit more complicated, I got lost. Suppose that I wanted to render this query:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;SELECT &lt;/span&gt;a&lt;span style="color: gray"&gt;.&lt;/span&gt;au_lname&lt;span style="color: gray"&gt;, &lt;/span&gt;a&lt;span style="color: gray"&gt;.&lt;/span&gt;au_fname&lt;span style="color: gray"&gt;, &lt;/span&gt;a&lt;span style="color: gray"&gt;.&lt;/span&gt;phone&lt;span style="color: gray"&gt;, &lt;/span&gt;&lt;span style="color: magenta"&gt;COUNT&lt;/span&gt;&lt;span style="color: gray"&gt;(*) &lt;/span&gt;&lt;span style="color: blue"&gt;AS &lt;/span&gt;&lt;span style="color: magenta"&gt;Count&lt;br /&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;FROM &lt;/span&gt;authors &lt;span style="color: blue"&gt;AS &lt;/span&gt;a&lt;br /&gt;&lt;span style="color: blue"&gt;GROUP BY &lt;/span&gt;a&lt;span style="color: gray"&gt;.&lt;/span&gt;au_lname&lt;span style="color: gray"&gt;, &lt;/span&gt;a&lt;span style="color: gray"&gt;.&lt;/span&gt;au_fname&lt;span style="color: gray"&gt;, &lt;/span&gt;a&lt;span style="color: gray"&gt;.&lt;/span&gt;phone&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;I figured out that the Key didn’t need to be a simple type. The type of the Key is determined by the type between &lt;strong&gt;&lt;font face="Courier New"&gt;by&lt;/font&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;font face="Courier New"&gt;into&lt;/font&gt;&lt;/strong&gt; in the &lt;strong&gt;&lt;font face="Courier New"&gt;group&lt;/font&gt;&lt;/strong&gt; clause. So here I create an anonymous type for the key and refer to the properties of &lt;strong&gt;&lt;font face="Courier New"&gt;Key&lt;/font&gt;&lt;/strong&gt; in the &lt;strong&gt;&lt;font face="Courier New"&gt;select&lt;/font&gt;&lt;/strong&gt; clause. So I can render it as follows (&lt;a href="http://www.linqpad.net/"&gt;LINQPad&lt;/a&gt; C# Expression):&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;from &lt;/span&gt;&lt;span style="color: black"&gt;a &lt;/span&gt;&lt;span style="color: blue"&gt;in &lt;/span&gt;&lt;span style="color: black"&gt;Authors &lt;br /&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;group &lt;/span&gt;&lt;span style="color: black"&gt;a &lt;/span&gt;&lt;span style="color: blue"&gt;by new &lt;br /&gt;&lt;/span&gt;&lt;span style="color: darkred"&gt;{&lt;br /&gt;    a.Au_lname, &lt;br /&gt;    a.Au_fname, &lt;br /&gt;    a.Phone&lt;br /&gt;} &lt;/span&gt;&lt;span style="color: blue"&gt;into &lt;/span&gt;&lt;span style="color: black"&gt;c&lt;br /&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;select new &lt;br /&gt;&lt;/span&gt;&lt;span style="color: black"&gt;{&lt;br /&gt;    Au_lname = c.Key.Au_lname,&lt;br /&gt;    Au_fname = c.Key.Au_fname,&lt;br /&gt;    Phone = c.Key.Phone,&lt;br /&gt;    Count = c.Count()&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;&lt;font face="Courier New"&gt;GroupBy()&lt;/font&gt;&lt;/strong&gt; (the extension method that &lt;strong&gt;&lt;font face="Courier New"&gt;group .. by&lt;/font&gt;&lt;/strong&gt; is translated into) returns an &lt;strong&gt;&lt;font face="Courier New"&gt;IQueryable&lt;/font&gt;&lt;/strong&gt; of &lt;strong&gt;&lt;font face="Courier New"&gt;IGrouping&lt;/font&gt;&lt;/strong&gt;(s), a &lt;strong&gt;&lt;font face="Courier New"&gt;IGrouping&lt;/font&gt;&lt;/strong&gt; is an &lt;strong&gt;&lt;font face="Courier New"&gt;IEnumerable&lt;/font&gt;&lt;/strong&gt; with a generic &lt;strong&gt;&lt;font face="Courier New"&gt;Key&lt;/font&gt;&lt;/strong&gt; property tacked on. Since &lt;strong&gt;&lt;font face="Courier New"&gt;Key&lt;/font&gt;&lt;/strong&gt; is generic, I can pass in a complex type. &lt;br /&gt;&lt;p&gt;NOTE: I haven’t been able to get it to work with a non-anonymous type In LINQ to SQL. &lt;br /&gt;&lt;p&gt;I didn’t use LINQ grouping in my production code. I don’t know if it is because I didn’t understand it or just didn’t need it. If I really needed it I would think I would have pushed harder and learned it earlier…&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-3912991147143001188?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/3912991147143001188/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=3912991147143001188' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/3912991147143001188'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/3912991147143001188'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2012/01/less-than-simple-group-by-linq-queries.html' title='Less Than Simple Group By LINQ Queries'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-6342456862588751932</id><published>2011-12-31T15:01:00.001-08:00</published><updated>2011-12-31T15:01:07.007-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='XML Comments'/><title type='text'>Example of Repetitive Comments</title><content type='html'>&lt;p&gt;Looking through some old code for a project I’m working on I saw a block of code similar to this:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// &lt;/span&gt;&lt;span style="color: green"&gt;This is MY method&lt;br /&gt;&lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;/// &amp;lt;param name="intValue"&amp;gt;&lt;/span&gt;&lt;span style="color: green"&gt;Some Number&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&amp;gt;&lt;br /&gt;/// &amp;lt;param name="stringValue"&amp;gt;&lt;/span&gt;&lt;span style="color: green"&gt;Some String&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&amp;gt;&lt;br /&gt;/// &amp;lt;returns&amp;gt;&lt;/span&gt;&lt;span style="color: green"&gt;An empty string&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/returns&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;public string &lt;/span&gt;MyMethod( &lt;span style="color: green"&gt;// Returns An empty string&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;int &lt;/span&gt;intValue,       &lt;span style="color: green"&gt;// Some Number&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;string &lt;/span&gt;stringValue) &lt;span style="color: green"&gt;// Some String&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span style="color: blue"&gt;return string&lt;/span&gt;.Empty;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;This code annoys me. Yet I see the problem: the XML comments are just a little too far away from the actual data. I think it would be cool to have tool tips for the parameters described in XML comments. It would have also helped name the parameters better. &lt;br /&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-6342456862588751932?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/6342456862588751932/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=6342456862588751932' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/6342456862588751932'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/6342456862588751932'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/12/example-of-repetitive-comments.html' title='Example of Repetitive Comments'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-4322580600120449669</id><published>2011-12-16T06:31:00.001-08:00</published><updated>2011-12-16T06:31:11.187-08:00</updated><title type='text'>Two devices to read a tech book</title><content type='html'>&lt;p&gt;Last week I bought some technical books from the internet; they were stolen from my front door and I needed them immediately, so I ordered the e-book version. I like e-readers for pure text that is meant to be read in order (novels, histories, etc.), but technical books have diagrams, tables and code samples (“figures”) that may be referenced several pages later. So I decided to try using two devices …&lt;/p&gt; &lt;p&gt;&lt;a href="http://lh5.ggpht.com/-7AP7l2pFg5I/TutWLL-54VI/AAAAAAAAAYc/CSeor4pwWT8/s1600-h/two_dev_code%25255B8%25255D.jpg"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="two_dev_code" border="0" alt="two_dev_code" src="http://lh4.ggpht.com/-RBlhf-S9fo4/TutWLmpqzTI/AAAAAAAAAYk/LvdhuOaHL-g/two_dev_code_thumb%25255B6%25255D.jpg?imgmax=800" width="318" height="504"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;I use the reader for the text and the tablet for the figures. I don’t like to read lots of text on a tablet because it is backlit. I really like reading plain text on a reader; I bought mine this spring and read the Lord of the Rings (+ the Hobbit) on it. I like reading on it better than reading books. &lt;p&gt;Since the reader doesn’t support zoom, I like to use the tablet to zoom the figures; actually, the image support on the reader is so bad that it would be difficult to read my current book without viewing images on the tablet. &lt;p&gt;This is not a supported way to read an e-book and will probably never be. Even with the hassle of juggling two devices it is better than the supported way. It would be nice if I could move between figures without shuffling through the text. Some UX designer better than me needs to do something to improve the tech book reading experience.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-4322580600120449669?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/4322580600120449669/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=4322580600120449669' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/4322580600120449669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/4322580600120449669'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/12/two-devices-to-read-tech-book.html' title='Two devices to read a tech book'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/-RBlhf-S9fo4/TutWLmpqzTI/AAAAAAAAAYk/LvdhuOaHL-g/s72-c/two_dev_code_thumb%25255B6%25255D.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-8115872053011284672</id><published>2011-11-17T06:54:00.001-08:00</published><updated>2011-11-17T06:54:08.547-08:00</updated><title type='text'>My Play</title><content type='html'>&lt;p&gt;In this week’s &lt;a href="http://thisdeveloperslife.com/post/2-0-6-play"&gt;This Developers Life, they discussed Play&lt;/a&gt;. Not to be out done, I thought I would write about my own play patterns. It was fun to hear about the race car driver and the home manufacturer, I want to hear more. To promote dialog, I am presenting my story. &lt;h4&gt;Improv&lt;/h4&gt; &lt;p&gt;Almost 2 years ago, I started taking Improv classes at the &lt;a href="http://www.bluedoortheatre.com/"&gt;Blue Door Theatre&lt;/a&gt; in Spokane because I heard about some consultancy in New York City that provided Improv classes to all their consultants. The local NPR station announced the class on their arts calendar and I just said what the F# and I took the class. At that point I had never even seen live Improv. &lt;p&gt;Like many programmers, I have an Aspergers personality. This serves me well when I am actually doing my core job; for the rest of my life, not so much. Improv gives me a chance to play at being in the world where everyone else lives. It gives me the opportunity to playing at being an extrovert. &lt;p&gt;Through something we call “Yes, And”, I am learning to accepting the current situation and adapting to the current situation. And I am learning to do it quickly. As a programmer, I like to work carefully and look for the perfect solution; in Improv I just don’t have the time. (The programmer in me is telling me that this blog post isn’t good enough; if it wins, no one else will ever read this.) &lt;p&gt;Am I taking Improv to become a great actor and become famous? No. My chances of ever performing Improv in public: about 50/50 (based on the fact that most of us underestimate our own talents). Do I really care? Do you take Kung Fu to fight? If memory serves me right, Cane was able to avoid fighting as much as he fought. I have presented at Code Camps 5 times since I started Improv. &lt;h4&gt;Technology&lt;/h4&gt; &lt;p&gt;My work project is frozen to the technology that existed when it was started. I like to play with the new stuff. I have Windows 8 installed on my laptop. I am slowing working my way through &lt;a href="http://www.amazon.com/WPF-4-Unleashed-Adam-Nathan/dp/0672331195"&gt;WPF 4 Unleashed&lt;/a&gt;. I am looking into writing for the Android Tablet. No, this is an extension of work. &lt;h4&gt;Music&lt;/h4&gt; &lt;p&gt;I have a guitar, a bass and a keyboard that I attempt to use to make sounds with. In the past I found that the guitar to be a great stress reliever. On second thought I haven’t really even touched these things since I started Improv. Since classes don’t start up again until next year, I would take out an instrument and …  &lt;h4&gt;Christine&lt;/h4&gt; &lt;p&gt;I have a 1982 Supra that I have tried to keep alive for the last dozen or so years. Due to some poor financial decisions on my part, I haven’t done much with her for the past couple of years. My dream is to restore her on YouTube. Yes, her name is a reference to the Stephen King book.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-8115872053011284672?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/8115872053011284672/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=8115872053011284672' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/8115872053011284672'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/8115872053011284672'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/11/in-this-weeks-this-developers-life-they.html' title='My Play'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-2772637327120016743</id><published>2011-11-09T06:58:00.000-08:00</published><updated>2011-11-09T06:58:23.675-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='open source'/><category scheme='http://www.blogger.com/atom/ns#' term='voting'/><title type='text'>Tablets and Open Source Voting Software</title><content type='html'>&lt;p&gt;Yesterday on NPR, they had a short piece on &lt;a href="http://www.npr.org/2011/11/08/142123499/the-last-word-in-business"&gt;iPad Voting&lt;/a&gt;. I don't like modern voting machines because of the closed nature of their software; very few people know what is going on inside those things.&lt;/p&gt;&lt;p&gt;If I had my way, the voting software would be written as an open source project. The voting machines would be common hardware that could be used in schools after election season. On Election Day morning, representatives from all interested parties would download the source from the project's site, build, run unit tests, install the software and generally verify that the software is correct.&lt;/p&gt;&lt;p&gt;The hardware would probably be tablet computers. Right now the market would be iPad, Android and, coming soon, Windows Metro. I would imagine that each vendor would sponsor voting machine projects that use their hardware. When the local community center would buy tablet computers of some after school program, the quality of its open source voting software may affect the buying decision. You wouldn’t need to buy new hardware every election cycle, schools could go without the iPad for the first week of November (“Hey kids, this is a ‘yellow pad’, we used these in the 20th century”).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-2772637327120016743?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/2772637327120016743/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=2772637327120016743' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2772637327120016743'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2772637327120016743'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/11/tablets-and-open-source-voting-software.html' title='Tablets and Open Source Voting Software'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-5773710656526477808</id><published>2011-10-31T06:52:00.001-07:00</published><updated>2011-10-31T06:52:44.146-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tablet'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows 8'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='career'/><title type='text'>Windows 8 and Fear of Change</title><content type='html'>&lt;p&gt;For Halloween, I will discuss Windows 8 and Metro. I hear lots of fear and loathing in regard to Microsoft’s strategy regarding Windows 8 and the tablet. &lt;/p&gt; &lt;p&gt;I’ve heard horror stories about how we will be forced to throw away all we’ve learned the last 10 years and learn to write apps in HTML5 and JavaScript. Tales that Silverlight is doomed to the bone yard and so on … In short, the technology world changing and all our skills will be null and void. In our next job, we will need to rehearse the phrase: “Do you want fries with that?”&lt;/p&gt; &lt;p&gt;Come on, part of being a developer is dealing with change and uncertainty. In the mid 1990s, we went from DOS and character based computers to the GUI Land of Windows 95. In the early 2000s it was .NET for everyone in Windows Land. And now there are rumors of doom about what Microsoft is up to with Windows 8.&lt;/p&gt; &lt;p&gt;Part of the bargain of working in this business is change; we get to work on the cool new things and we have to work on the cool new things. We spend more time keeping up, learning things we need to be up to date. By choosing what to learn, we are also placing bets on winners and losers. If I study Window 8, I am betting for Microsoft and against Google and Apple. Of course, I could hedge my bet by studying both Window 8 and Android (that would reduce my potential reward.&lt;/p&gt; &lt;h2&gt;Windows 8 etc.&lt;/h2&gt; &lt;p&gt;Windows 8 (WinRT, Metro, etc.) represents to response to iOS and Android tablets. I don’t know if Windows 8 will preserve the market share that Microsoft has enjoyed with Windows for the past generation. I don’t know if Windows 8 will be a second Vista. It is even possible that this is the beginning of the end of Windows or even Microsoft.&lt;/p&gt; &lt;p&gt;I can’t say that Microsoft is late to the Tablet game. There was the PocketPC that was a small tablet that used a “pen” and there was a tablet version of Windows XP (also used a “pen”). These are pen tablets, the cool new tablets are touch tablets. &lt;/p&gt; &lt;p&gt;Microsoft is taking a different approach than Apple. Apple has two Operating Systems: iOS for tablets and devices and OSX for full blown computers. Microsoft is going with One OS to Rule Them All: Windows 8 will be on desktop and little tablet devices. I suppose WP8 will be Windows 8.&lt;/p&gt; &lt;p&gt;There are as many changes in the other platforms. Change defines our industry. Every change represents risks to all participants. Not changing also represents risks. This is just part of the job.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-5773710656526477808?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/5773710656526477808/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=5773710656526477808' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5773710656526477808'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5773710656526477808'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/10/windows-8-and-fear-of-change.html' title='Windows 8 and Fear of Change'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-8375211335451697132</id><published>2011-09-25T17:14:00.001-07:00</published><updated>2011-09-29T20:28:38.558-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Note to Work'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='FileInfo'/><title type='text'>Filtering files by Date Range</title><content type='html'>&lt;p&gt;In this For Work post I am wrote a function that will return a list of files (FileInfo objects actually) for a given search string and date range.  &lt;/p&gt;&lt;h2&gt;The Problem&lt;/h2&gt; &lt;p&gt;My internal customer wants archive files in a given directory for a given date range. Right now I am working on the part where I get the files; the rest of the problem is beyond the scope of this post. &lt;/p&gt; &lt;h2&gt;My Solution&lt;/h2&gt; &lt;p&gt;I am using FileInfo.GetFiles() to get a list of FileInfo objects for a given filename filter and then use Linq to filter that list for the date range.  &lt;/p&gt;&lt;p&gt;So here’s my function: &lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// &lt;/span&gt;&lt;span style="color: green"&gt;Returns a List of FileInfo for a given serch pattern and date range.&lt;br /&gt;&lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;/// &amp;lt;param name="searchPath"&amp;gt;&lt;br /&gt;/// &lt;/span&gt;&lt;span style="color: green"&gt;The path + the search string&lt;br /&gt;&lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/param&amp;gt;&lt;br /&gt;/// &amp;lt;param name="startDt"&amp;gt;&lt;br /&gt;/// &lt;/span&gt;&lt;span style="color: green"&gt;The beginning date for the search (as of midnight)&lt;br /&gt;&lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/param&amp;gt;&lt;br /&gt;/// &amp;lt;param name="endDt"&amp;gt;&lt;br /&gt;/// &lt;/span&gt;&lt;span style="color: green"&gt;The end date of the search (as of midnight;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: gray"&gt;/// &lt;/span&gt;&lt;span style="color: green"&gt;use DateTime(y, m, d 23, 59, 59) to get the whole day)&lt;br /&gt;&lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/param&amp;gt;&lt;br /&gt;/// &amp;lt;param name="searchOp"&amp;gt;&lt;br /&gt;/// &lt;/span&gt;&lt;span style="color: green"&gt;Specifies whether to search the current directory, or the current directory&lt;br /&gt;&lt;/span&gt;&lt;span style="color: gray"&gt;/// &lt;/span&gt;&lt;span style="color: green"&gt;and all subdirectories.        &lt;br /&gt;&lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/param&amp;gt;&lt;br /&gt;/// &amp;lt;returns&amp;gt;&lt;br /&gt;/// &lt;/span&gt;&lt;span style="color: green"&gt;A List of FileInfo&lt;br /&gt;&lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/returns&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;public static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;FileInfo&lt;/span&gt;&amp;gt; SearchFiles(&lt;span style="color: blue"&gt;string &lt;/span&gt;searchPath, &lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;? startDt, &lt;br /&gt;    &lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;? endDt, &lt;span style="color: #2b91af"&gt;SearchOption &lt;/span&gt;searchOp)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: green"&gt;// Break searchPath into parts&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;string &lt;/span&gt;directory = &lt;span style="color: #2b91af"&gt;Path&lt;/span&gt;.GetDirectoryName(searchPath);&lt;br /&gt;    &lt;span style="color: blue"&gt;string &lt;/span&gt;pattern = &lt;span style="color: #2b91af"&gt;Path&lt;/span&gt;.GetFileName(searchPath);&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: green"&gt;// DirectoryInfo exposes GetFiles used below&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;dinfo = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DirectoryInfo&lt;/span&gt;(directory);&lt;br /&gt;    &lt;span style="color: green"&gt;// Get all of the files that meet the criteria&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;finfol = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;FileInfo&lt;/span&gt;&amp;gt;(dinfo.GetFiles(pattern, searchOp));&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: green"&gt;// Throw out the files that are out of the date range&lt;br /&gt;    // Here is where I would add aditional filters&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;return new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;FileInfo&lt;/span&gt;&amp;gt;(&lt;br /&gt;        &lt;span style="color: blue"&gt;from &lt;/span&gt;f &lt;span style="color: blue"&gt;in &lt;/span&gt;finfol&lt;br /&gt;        &lt;span style="color: blue"&gt;where &lt;/span&gt;(f.LastWriteTime &amp;gt;= (startDt ?? &lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;.MinValue)) &amp;amp;&amp;amp;&lt;br /&gt;              (f.LastWriteTime &amp;lt;= (endDt ?? &lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;.MaxValue))&lt;br /&gt;        &lt;span style="color: blue"&gt;select &lt;/span&gt;f);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-8375211335451697132?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/8375211335451697132/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=8375211335451697132' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/8375211335451697132'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/8375211335451697132'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/09/filtering-files-by-date-range.html' title='Filtering files by Date Range'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-7431904666917043398</id><published>2011-08-18T20:56:00.000-07:00</published><updated>2011-09-29T20:32:47.156-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><category scheme='http://www.blogger.com/atom/ns#' term='Item Template'/><title type='text'>Creating Simple Form Item Template for VS 2008</title><content type='html'>&lt;p&gt;In this For Work blog entry, I am going to create a Visual Studio Item Template for a Windows Form. We have several patterns of forms that we need to create over and over again. I want to be able to create my own Form with all my setting set by default, include some standard controls and derive from my base class, etc.  &lt;/p&gt;&lt;p&gt;I am not using Export Template because I want to see all the working parts.&lt;/p&gt; &lt;h2&gt;The Process&lt;/h2&gt; &lt;h3&gt;Create a Starter Form&lt;/h3&gt; &lt;p&gt;Create a form that has everything I want in my template in a WinForm project. In this case I will pretend that we created a WinForm called &lt;strong&gt;MyForm.cs&lt;/strong&gt;.  &lt;/p&gt;&lt;h3&gt;Gather the Template Files together&lt;/h3&gt; &lt;p&gt;I created a directory somewhere on the file system and copy the form’s source files into that directory. Add to those files an ico file and a new text files with a .vstemplate extension. So for my template, I would put the following files”&lt;/p&gt; &lt;table border="0" cellspacing="0" cellpadding="2" width="682"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="156"&gt;MyForm.cs&lt;/td&gt; &lt;td valign="top" width="524"&gt;The Form’s code file. Not yet changed, will replace class name and namespace later.&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="156"&gt;MyForm.Designer.cs&lt;/td&gt; &lt;td valign="top" width="524"&gt;The Form’s designer code files. Will also need replace class name and namespace.&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="156"&gt;MyForm.resx&lt;/td&gt; &lt;td valign="top" width="524"&gt;(Optional) Form’s resources, In this example, I use this to set a different icon.&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="156"&gt;BICYCLE.ICO&lt;/td&gt; &lt;td valign="top" width="524"&gt;The Icon file that appears in the Add New Item dialog&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="156"&gt;MyFormCS.vstemplate&lt;/td&gt; &lt;td valign="top" width="524"&gt;Empty file. Will be the Template metadata file.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;h3&gt;Add/Replace Template Parameters in Source files&lt;/h3&gt; &lt;p&gt;In the process Template Parameters are substituted with values created by the New Item Wizard when the new item is created. They are declared in the form of $parameter$  &lt;/p&gt;&lt;p&gt;In my demo, I use the following Template Parameters: &lt;/p&gt; &lt;table border="0" cellspacing="0" cellpadding="2" width="683"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="153"&gt;rootnamespace&lt;/td&gt; &lt;td valign="top" width="528"&gt;The full namespace of the item; “root” namespace suggests something different&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="153"&gt;safeitemrootname&lt;/td&gt; &lt;td valign="top" width="528"&gt;The name of the item (or class) being created.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;So given the following code:&lt;/p&gt;&lt;pre class="code"&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;System;&lt;br /&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Windows.Forms;&lt;br /&gt;&lt;span style="color: blue"&gt;namespace &lt;/span&gt;ItemTemplatePlayGround&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: blue"&gt;public partial class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MyForm &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;Form&lt;br /&gt;    &lt;/span&gt;{&lt;br /&gt;        &lt;span style="color: blue"&gt;public &lt;/span&gt;MyForm()&lt;br /&gt;        {&lt;br /&gt;            InitializeComponent();&lt;br /&gt;        } &lt;br /&gt;        …&lt;/p&gt;&lt;/pre&gt;&lt;p&gt;I change the code to read:&lt;/p&gt;&lt;pre class="code"&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;System;&lt;br /&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Windows.Forms;&lt;br /&gt;&lt;span style="color: blue"&gt;namespace &lt;/span&gt;&lt;span style="color: red"&gt;$rootnamespace$&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: blue"&gt;public partial class &lt;/span&gt;&lt;span style="color: red"&gt;$safeitemrootname$ &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;Form&lt;br /&gt;    &lt;/span&gt;{&lt;br /&gt;        &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: red"&gt;$safeitemrootname$&lt;/span&gt;()&lt;br /&gt;        {&lt;br /&gt;            InitializeComponent();&lt;br /&gt;        }&amp;nbsp;&amp;nbsp; &lt;br&gt;        …&lt;/p&gt;&lt;/pre&gt;&lt;h3&gt;Fill out the .vstemplate file&lt;/h3&gt;&lt;p&gt;The .vstemplate file contains most the metadata that Visual Studio needs use my template. Things like the name and description of the template, the icon that is displayed in the new New Item dialog, the project type, etc. It also contains a list of all the files that make up the templates and instructions on how to handle them. (NOTE: the physical location of the template file determines the Template’s “Language” and “Category”, so I can’t claim that it contains all the metadata).&lt;/p&gt;&lt;p&gt;Notice that Template Parameters appear in the .vstemplate file.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;VSTemplate &lt;/span&gt;&lt;span style="color: red"&gt;Type&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;"&lt;span style="color: blue"&gt;Item&lt;/span&gt;" &lt;span style="color: red"&gt;Version&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;"&lt;span style="color: blue"&gt;2.0.0&lt;/span&gt;" &lt;br /&gt;            &lt;span style="color: red"&gt;xmlns&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;"&lt;span style="color: blue"&gt;http://schemas.microsoft.com/developer/vstemplate/2005&lt;/span&gt;"&lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;TemplateData&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;Name&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;My Lame Form&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;Name&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;Description&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;An empty Form&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;Description&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;DefaultName&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;MyForm.cs&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;DefaultName&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;ProjectType&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;CSharp&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;ProjectType&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;Icon&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;BICYCLE.ico&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;Icon&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;  &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;TemplateData&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;TemplateContent&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;ProjectItem &lt;/span&gt;&lt;span style="color: red"&gt;TargetFileName&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;"&lt;span style="color: blue"&gt;$fileinputname$.cs&lt;/span&gt;"  &lt;br /&gt;                 &lt;span style="color: red"&gt;ReplaceParameters&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;"&lt;span style="color: blue"&gt;true&lt;/span&gt;" &lt;br /&gt;                 &lt;span style="color: red"&gt;SubType&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;"&lt;span style="color: blue"&gt;Form&lt;/span&gt;"&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;MyForm.cs&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;ProjectItem&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;ProjectItem &lt;/span&gt;&lt;span style="color: red"&gt;TargetFileName&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;"&lt;span style="color: blue"&gt;$fileinputname$.Designer.cs&lt;/span&gt;"  &lt;br /&gt;                 &lt;span style="color: red"&gt;ReplaceParameters&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;"&lt;span style="color: blue"&gt;true&lt;/span&gt;"&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;MyForm.Designer.cs&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;ProjectItem&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;ProjectItem &lt;/span&gt;&lt;span style="color: red"&gt;TargetFileName&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;"&lt;span style="color: blue"&gt;$fileinputname$.Designer.resx&lt;/span&gt;"&lt;br /&gt;                 &lt;span style="color: red"&gt;ReplaceParameters&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;"&lt;span style="color: blue"&gt;true&lt;/span&gt;"&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;MyForm.Designer.resx&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;ProjectItem&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;  &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;TemplateContent&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;VSTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;I have chosen not to go over every detail of the .vstemplate file. There are denser articles on the web that cover them in painful detail.&lt;/p&gt;&lt;p&gt;The &lt;strong&gt;TempateData&lt;/strong&gt; section gives data about the template as a whole. &lt;strong&gt;Name&lt;/strong&gt; and &lt;strong&gt;Description&lt;/strong&gt; are what you think they are. &lt;strong&gt;DefaultName&lt;/strong&gt; is used to propose a name in the Add New Item dialog. &lt;strong&gt;ProjectType&lt;/strong&gt; is the language of the item; either &lt;strong&gt;CSharp&lt;/strong&gt; or &lt;strong&gt;VisualBasic&lt;/strong&gt;. &lt;strong&gt;Icon&lt;/strong&gt; refers to the icon (.ico) file that provides the icon next to the project type name in the &lt;strong&gt;New Item&lt;/strong&gt; dialog.&lt;p&gt;The &lt;strong&gt;TemplateContent&lt;/strong&gt; contains &lt;strong&gt;ProjectItem&lt;/strong&gt; elements for each of the files in the template (except the icon file and the .vstemplate itself). If your project contains 5 files total, there should be 3 &lt;strong&gt;ProjectItem&lt;/strong&gt; elements.&lt;/p&gt;&lt;p&gt;Within the &lt;strong&gt;ProjectItem&lt;/strong&gt; element, the &lt;strong&gt;TargetFileName&lt;/strong&gt; attribute is the name of the new file created by the template. &lt;strong&gt;ReplaceParameters&lt;/strong&gt; determines if Template Parameters in this file are replaced. &lt;strong&gt;SubType&lt;/strong&gt; determines the Visual Studio Editor used to design this file; you only need this attribute if this file uses a designer. The Element’s inner text represents the name of the file within the template itself. The element value is the before file name and the TargetFileName is the after.&lt;h2&gt;Where are my template files?&lt;/h2&gt;&lt;p&gt;The default your item template files are located in &lt;strong&gt;My Documents\Visual Studio 2008\Templates\ItemTemplates\Language&lt;/strong&gt;. On my system, Visual Studio 2008 was looking in &lt;strong&gt;C:\Users\jacks\Documents\Visual Studio 2005\Templates\ItemTemplates&lt;/strong&gt;. So, it is a good idea to make sure that Visual Studio is looking in the right place. &lt;/p&gt;&lt;p&gt;To check/change the template location: Tools =&amp;gt; Options, select the Projects and Solutions group and the General tab.&lt;/p&gt;&lt;h3&gt;Links&lt;/h3&gt;&lt;p&gt;&lt;a href="https://docs.google.com/viewer?a=v&amp;amp;pid=explorer&amp;amp;chrome=true&amp;amp;srcid=0ByZJy7UqXWOuM2Y5OWYzMjgtN2Y1Mi00YTRlLWFiNjMtNWE3NzRkNzkwOWRi&amp;amp;hl=en_US" type="application/zip"&gt;Finished Template&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-7431904666917043398?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/7431904666917043398/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=7431904666917043398' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/7431904666917043398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/7431904666917043398'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/08/creating-simple-form-item-template-for_18.html' title='Creating Simple Form Item Template for VS 2008'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-5467859799950116303</id><published>2011-07-23T15:23:00.001-07:00</published><updated>2011-09-29T20:35:17.118-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='T4 Templates'/><category scheme='http://www.blogger.com/atom/ns#' term='T4 Toolbox'/><title type='text'>Generate several files from one template with the T4 Toolbox</title><content type='html'>&lt;p&gt;I have been playing with using &lt;a href="http://t4toolbox.codeplex.com/"&gt;T4Toolbox&lt;/a&gt; to generate more than one file from a single template within Visual Studio. &lt;/p&gt; &lt;h2&gt;T4Toolbox.Template&lt;/h2&gt; &lt;p&gt;The Template class is the T4Toolbox’s version of &lt;strong&gt;TextTransformation&lt;/strong&gt; that has a very special method called &lt;strong&gt;RenderToFile&lt;/strong&gt;(); this method writes the text to be generated to a file. So, If I wanted to generate a file for each item in a list (say a list of database tables), I could use a &lt;strong&gt;foreach&lt;/strong&gt; loop to create a new instance of my Template class and call Its &lt;strong&gt;RenderToFile&lt;/strong&gt; method with different file names.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: black"&gt;&amp;lt;#@ &lt;/span&gt;&lt;span style="color: brown"&gt;template &lt;/span&gt;&lt;span style="color: red"&gt;language&lt;/span&gt;&lt;span style="color: black"&gt;="&lt;/span&gt;&lt;span style="color: blue"&gt;C#v3.5&lt;/span&gt;&lt;span style="color: black"&gt;" &lt;/span&gt;&lt;span style="color: red"&gt;hostSpecific&lt;/span&gt;&lt;span style="color: black"&gt;="&lt;/span&gt;&lt;span style="color: blue"&gt;true&lt;/span&gt;&lt;span style="color: black"&gt;" #&amp;gt;&lt;br /&gt;&amp;lt;#@ &lt;/span&gt;&lt;span style="color: brown"&gt;output &lt;/span&gt;&lt;span style="color: red"&gt;extension&lt;/span&gt;&lt;span style="color: black"&gt;="&lt;/span&gt;&lt;span style="color: blue"&gt;txt&lt;/span&gt;&lt;span style="color: black"&gt;" #&amp;gt;&lt;br /&gt;&amp;lt;#@ &lt;/span&gt;&lt;span style="color: brown"&gt;include &lt;/span&gt;&lt;span style="color: red"&gt;file&lt;/span&gt;&lt;span style="color: black"&gt;="&lt;/span&gt;&lt;span style="color: blue"&gt;T4Toolbox.tt&lt;/span&gt;&lt;span style="color: black"&gt;" #&amp;gt;&lt;br /&gt;&amp;lt;#&lt;br /&gt;    Write(&lt;/span&gt;&lt;span style="color: maroon"&gt;"This file (minimum.txt) is also generated"&lt;/span&gt;&lt;span style="color: black"&gt;);&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;for &lt;/span&gt;&lt;span style="color: black"&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;int &lt;/span&gt;&lt;span style="color: black"&gt;i = &lt;/span&gt;&lt;span style="color: purple"&gt;7&lt;/span&gt;&lt;span style="color: black"&gt;; i &amp;lt;= &lt;/span&gt;&lt;span style="color: purple"&gt;11&lt;/span&gt;&lt;span style="color: black"&gt;; ++i)&lt;br /&gt;    {&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;string &lt;/span&gt;&lt;span style="color: black"&gt;fileName = &lt;/span&gt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&lt;span style="color: black"&gt;.Format(&lt;/span&gt;&lt;span style="color: maroon"&gt;"file{0:00}.lam"&lt;/span&gt;&lt;span style="color: black"&gt;, i);&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;&lt;span style="color: black"&gt;lt = &lt;/span&gt;&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: black"&gt;LameFileTemplate(fileName);&lt;br /&gt;        lt.RenderToFile(fileName);&lt;br /&gt;    }&lt;br /&gt;#&amp;gt;&lt;br /&gt;&amp;lt;#+&lt;br /&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;private class &lt;/span&gt;&lt;span style="color: black"&gt;LameFileTemplate : Template&lt;br /&gt;{&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: black"&gt;LameFileTemplate(&lt;/span&gt;&lt;span style="color: blue"&gt;string &lt;/span&gt;&lt;span style="color: black"&gt;fileName)&lt;br /&gt;    {&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.FileName = fileName;&lt;br /&gt;    }&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;private string &lt;/span&gt;&lt;span style="color: black"&gt;FileName {&lt;/span&gt;&lt;span style="color: blue"&gt;get&lt;/span&gt;&lt;span style="color: black"&gt;; &lt;/span&gt;&lt;span style="color: blue"&gt;set&lt;/span&gt;&lt;span style="color: black"&gt;;}&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: blue"&gt;public override string &lt;/span&gt;&lt;span style="color: black"&gt;TransformText()&lt;br /&gt;    {&lt;br /&gt;        #&amp;gt;&amp;lt;#=&lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;&lt;span style="color: black"&gt;.FileName#&amp;gt;&amp;lt;#+&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;return this&lt;/span&gt;&lt;span style="color: black"&gt;.GenerationEnvironment.ToString();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;#&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;When I save this file, Visual Studio runs the template and creates several files. Notice that creates a file that matches the file name of the template; this can’t be helped. Since the default output extension is “cs”, it is important to set this to something else.&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/-5mEqNQafH88/TitJ3Ph7MQI/AAAAAAAAAW8/mRjMoiXqzAc/s1600-h/image%25255B2%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/-7oEAZWUrgnA/TitJ3kO5skI/AAAAAAAAAXA/lfbL9E_PQSk/image_thumb.png?imgmax=800" width="184" height="132"&gt;&lt;/a&gt;&lt;br&gt;My template and generated files&lt;/p&gt;&lt;p&gt;NOTE: In a failed demo that I gave at the Portland Code camp this spring I wrote a template that would create a SELECT stored procedure for each table in a given database (each in its own file). The demonstration was too complicated and hard to follow. It used the Generator class SMO and a bunch of other stuff.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-5467859799950116303?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/5467859799950116303/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=5467859799950116303' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5467859799950116303'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5467859799950116303'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/07/generate-several-files-from-one.html' title='Generate several files from one template with the T4 Toolbox'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/-7oEAZWUrgnA/TitJ3kO5skI/AAAAAAAAAXA/lfbL9E_PQSk/s72-c/image_thumb.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-5354517151542439795</id><published>2011-06-23T07:17:00.000-07:00</published><updated>2011-06-23T07:17:59.484-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='T4 Templates'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Generation'/><category scheme='http://www.blogger.com/atom/ns#' term='GAX'/><title type='text'>The GAX Property Directive</title><content type='html'>&lt;p&gt;One of the things that really bother me about T4 templates is the lack of direct parameter support (at least in the Visual Studio 2008/.NET 3 timeframe). &lt;/p&gt;&lt;p&gt;In an &lt;a href="http://brochure.jrcs3.com/2010/12/generating-nullable-ado.html"&gt;earlier post&lt;/a&gt;, I passed parameter by writing the parameter data to a file outside of the template and reading the data from within. I used a common assembly linked to both sides of the divide. This works for me, but it is really hacky. &lt;/p&gt;&lt;h2&gt;GAX Template Host&lt;/h2&gt;&lt;p&gt; During my preparation for my Portland Code Camp presentation, I came across Guidance Automation Toolkit for Visual Studio 2008. It has its own TemplateHost that includes a Dictionary of parameters.&lt;/p&gt;&lt;p&gt;Parameters are exposed to the Template through a custom directive. On the template, the parameter is declared using a directive like this:&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ property processor="PropertyProcessor" name="MyName" type="String" #&amp;gt;&lt;br /&gt;&lt;/pre&gt;The directive contains the following parts:&lt;table style="border-width: 1px;"&gt;&lt;tr&gt;&lt;td style="width: 150px;"&gt;&lt;strong&gt;processor&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Should be "PropertyProcessor" (there may be a way to write your own processor, I haven’t gone down that rat hole yet).&lt;/td&gt;&lt;/tr&gt;&lt;/tr&gt;&lt;td&gt;&lt;strong&gt;name&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;The Variable name that can appear in your code. It works just like a variable, however, tangable T4 Editor doesn’t provide Intenesence (I wouldn’t have expected it).&lt;/td&gt;&lt;/tr&gt;&lt;/tr&gt;&lt;td&gt;&lt;strong&gt;type&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Any .NET Type that the template knows about. You should use the .NET type name (as opposed to C# or VB.NET type).&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;In C# the parameters are created like this:&lt;pre class="prettyprint"&gt;&lt;br /&gt;var arguments = new Dictionary&lt;string, PropertyData&gt;();&lt;br /&gt;arguments.Add("MyProperty", new PropertyData("String", typeof(string)));&lt;br /&gt;&lt;/pre&gt;To pass parameters from your code you need to create a Dictionary&amp;lt;string, PropertyData&amp;gt;, add your parameters and pass them as the second argument into the TemplateHost constructor (the first can be any string as far as I can tell).&lt;/p&gt;&lt;h2&gt;Simple Sample&lt;/h2&gt;&lt;p&gt;&lt;/p&gt;&lt;h3&gt;The Template&lt;/h3&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ template language="C#" debug="True" #&amp;gt;&lt;br /&gt;&amp;lt;#@ output extension="txt" #&amp;gt;&lt;br /&gt;&amp;lt;#@ assembly name="System.dll" #&amp;gt;&lt;br /&gt;&amp;lt;#@ import namespace="System" #&amp;gt;&lt;br /&gt;&amp;lt;#@ property processor="PropertyProcessor" name="MyProperty" type="Nullable&amp;lt;Int32&amp;gt;"#&amp;gt;&lt;br /&gt;&amp;lt;#@ property processor="PropertyProcessor" name="MyName" type="String"#&amp;gt;&lt;br /&gt;My Property Test&lt;br /&gt;&amp;lt;# if (MyProperty.HasValue) {#&amp;gt;&lt;br /&gt;Property Value: &amp;lt;#= MyProperty.Value #&amp;gt;!&lt;br /&gt;&amp;lt;#}#&amp;gt;&lt;br /&gt;Name: &amp;lt;#= MyName #&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;h3&gt;C# code&lt;/h3&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;static void Main(string[] args)&lt;br /&gt;{&lt;br /&gt;    // Prepare template parameters&lt;br /&gt;    var arguments = new Dictionary&amp;lt;string, PropertyData&amp;gt;();&lt;br /&gt;    arguments.Add("MyProperty", new PropertyData(42, typeof(int?)));&lt;br /&gt;    arguments.Add("MyName", new PropertyData("Jack Stephens", typeof(string)));&lt;br /&gt;&lt;br /&gt;    // Initialize GAX template host&lt;br /&gt;    // The Template Host is from GAX, not the default host&lt;br /&gt;    var host = new TemplateHost("Random String", arguments);&lt;br /&gt;    host.TemplateFile = Path.Combine(Directory.GetCurrentDirectory(), &lt;br /&gt;        "PropertyTest.tt");&lt;br /&gt;&lt;br /&gt;    // Transform template&lt;br /&gt;    string template = File.ReadAllText(host.TemplateFile);&lt;br /&gt;&lt;br /&gt;    ITextTemplatingEngine engine = new Engine();&lt;br /&gt;    string output = engine.ProcessTemplate(template, host);&lt;br /&gt;&lt;br /&gt;    Console.Write(output);&lt;br /&gt;    Console.ReadKey();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;References&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.olegsych.com/2008/04/t4-property-directive/"&gt;Understanding T4: &amp;lt;#@ property #&amp;gt; directive&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.microsoft.com/download/en/details.aspx?id=11392"&gt;Guidance Automation Extensions Download&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-5354517151542439795?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/5354517151542439795/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=5354517151542439795' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5354517151542439795'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5354517151542439795'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/06/gax-property-directive.html' title='The GAX Property Directive'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-2326427018104364517</id><published>2011-06-13T06:35:00.000-07:00</published><updated>2011-06-13T06:36:46.274-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Late'/><category scheme='http://www.blogger.com/atom/ns#' term='T4 Templates'/><category scheme='http://www.blogger.com/atom/ns#' term='Presentation Notes'/><category scheme='http://www.blogger.com/atom/ns#' term='Portland Code Camp'/><title type='text'>Portland Code Camp 2011 Presentation Notes</title><content type='html'>&lt;p&gt;Again, I'm late getting this up. I will give usual excuses of being busy. In the future I will not promise anything before the next weekend after the code camp.&lt;/p&gt;&lt;p&gt;Since I developed this talk on this blog, this entry will essentially be a link list. I put a copy of the slides in Google doc and you can reference it &lt;a href="https://docs.google.com/leaf?id=0ByZJy7UqXWOuNDdkZmQ2YzQtYzdhMi00MzVhLWJlMjctYzZlYmZkNzkwODgw&amp;hl=en_US&amp;authkey=CKiJ4_EB"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;p&gt;This presentation is similar, but not the same as a presentation I gave at the &lt;a href="http://brochure.jrcs3.com/2011/03/boise-code-camp-2011-presentation-notes.html"&gt;Boise Code Camp&lt;/a&gt; in February.  In the interest of being DRY (Don’t Repeat Yourself) I will reference the notes for that presentation.&lt;/p&gt;&lt;h2 id="T4Tools"&gt;Tools&lt;/h2&gt;&lt;p&gt;For this presentation, I used the &lt;a href="http://www.olegsych.com/2009/04/t4-editor-by-tangible-engineering/"&gt;Tangible T4 Editory&lt;/a&gt; and the &lt;a href="http://t4toolbox.codeplex.com/"&gt;T4 Toolbox&lt;/a&gt;.&lt;/p&gt;&lt;h2 id="TemplateParts"&gt;Template Parts&lt;/h2&gt;&lt;p&gt;I presented a slide that showed the basic template parts in a small mock template:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ template language="C#" #&amp;gt;&lt;br /&gt;&amp;lt;#@ directive property=“value” #&amp;gt;&lt;br /&gt;&amp;lt;# var item = "Statement Block"; #&amp;gt;&lt;br /&gt;Text Block &lt;br /&gt;&amp;lt;#= "Expression Block" #&amp;gt;&lt;br /&gt;&amp;lt;#+ &lt;br /&gt;    string ClassFeatureBlock(string thingy)&lt;br /&gt;    {&lt;br /&gt;        return thingy;&lt;br /&gt;    } &lt;br /&gt;#&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;Hello World Monty&lt;/h2&gt;&lt;p&gt;I showed some of the elementary features of T4 templates by refactoring a basic template that would create a text file that contained the infamous words “Hello World”. A script of that exercise is &lt;a href="http://jrcs3.blogspot.com/2011/03/t4-template-tour-of-first-gear.html"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;h2 id="BasicDemo"&gt;Basic Code Generation Demonstration&lt;/h2&gt;&lt;p&gt;To demonstrate Code Generation I set out to generate a simple T-SQL Select Statement using Sql Management Objects (SMO).&lt;/p&gt;&lt;p&gt;Here I will refer to the &lt;a href="http://brochure.jrcs3.com/2011/03/boise-code-camp-2011-presentation-notes.html#BasicDemo"&gt;Boise Code Camp Notes&lt;/a&gt;.&lt;/p&gt;&lt;h2&gt;Generating Multiple Files using T4 Toolbox&lt;/h2&gt;&lt;p&gt;I used the result of the Basic Code Generation Demonstration to attempt to generate select scripts for all the tables in a given database. This demonstration was based on a series of blog posts by Oleg Synch (&lt;a href="http://www.olegsych.com/2008/09/t4-tutorial-creatating-your-first-code-generator/"&gt;Part 1&lt;/a&gt;, &lt;a href="http://www.olegsych.com/2008/09/t4-tutorial-creating-reusable-code-generation-templates/"&gt;Part 2&lt;/a&gt;, &lt;a href="http://www.olegsych.com/2008/09/t4-tutorial-creating-complex-code-generators/"&gt;Part 3&lt;/a&gt; &amp;amp; &lt;a href="http://www.olegsych.com/2008/10/t4-tutorial-reusing-code-generators-on-multiple-projects/"&gt;Part 4&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;I do intend to give my take on this process. Perhaps that is why I'm over a week late on these notes. I will add a link to these notes later.&lt;/p&gt;&lt;h2&gt;GAX Property Directive&lt;/h2&gt;&lt;p&gt;I discussed using Guidance Automation Extensions's property directive to overcome T4's lack of native support for passing parameters into templates. This part was based on another Oleg Synch article &lt;a href="http://www.olegsych.com/2008/04/t4-property-directive/"&gt;Understanding T4: &amp;lt;#@ property #&amp;gt; directive&lt;/a&gt;. &lt;/p&gt;&lt;p&gt;Again, I will add links to future blogs post(s) on this subject here.&lt;/p&gt;&lt;h2&gt;Generating a Nullable ADO.NET DataSet Wrapper&lt;/h2&gt;&lt;p&gt;This is when I went to Show and Tell Mode. I demonstrate a Nullable DataSet Wrapper that I wrote in these blog entries. I wrote the templates in VB.NET to generate code in C#.&lt;/p&gt;&lt;p&gt;&lt;a href="http://jrcs3.blogspot.com/2010/11/nullable-ado.html"&gt;Part 1&lt;/a&gt;, &lt;a href="http://jrcs3.blogspot.com/2010/11/generating-nullable-ado.html"&gt;Part 2&lt;/a&gt;, &lt;a href="http://jrcs3.blogspot.com/2010/12/generating-nullable-ado.html"&gt;Part 3&lt;/a&gt; &amp;amp;&lt;a href="http://jrcs3.blogspot.com/2010/12/generating-nullable-ado_19.html"&gt;Part 4&lt;/a&gt;&lt;/p&gt;&lt;h2&gt;Last Word&lt;/h2&gt;&lt;p&gt;This presentation reached too far and, like Icarus, I failed to hit the mark. The number of forward links is a sign of that. I intend to back-blog in the areas the missing material and add links when I am done.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-2326427018104364517?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/2326427018104364517/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=2326427018104364517' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2326427018104364517'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2326427018104364517'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/06/portland-code-camp-2011-presentation.html' title='Portland Code Camp 2011 Presentation Notes'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-8492169396719933850</id><published>2011-05-31T21:17:00.000-07:00</published><updated>2011-05-31T21:17:53.497-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mobipocket'/><category scheme='http://www.blogger.com/atom/ns#' term='Kindle'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Camp'/><title type='text'>Writing Kindle Presentation Notes with MobiPocket Creator</title><content type='html'>&lt;p&gt;Next weekend I will be presenting on &lt;a href="http://www.portlandcodecamp.com/2011/Sessions/Details/146"&gt;Code Generation with T4 Templates&lt;/a&gt; at the &lt;a href="href="http://www.portlandcodecamp.com"&gt;Portland Code Camp&lt;/a&gt; and I bought a Kindle a week or so ago. So, how do I play with my new toy without getting behind on preparing for my presentation? &lt;/p&gt;&lt;h2&gt;Mobipocket Creator Publisher Edition&lt;/h2&gt;&lt;p&gt;I am creating small ebooks with Word and &lt;a href="http://www.mobipocket.com/en/downloadsoft/productdetailscreator.asp"&gt;Mobipocket Creator Publisher Edition&lt;/a&gt;. I work though a demo or other presentation block and write it in Word. Then I use the Mobipocket Creator to create an ebook. I put it on my Kindle and review it before I go to bed.&lt;/p&gt;&lt;p&gt;Is this really a net gain or just a way to justify playing with my new toy instead of doing real work? I will find out come Saturday in Portland&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-8492169396719933850?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/8492169396719933850/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=8492169396719933850' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/8492169396719933850'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/8492169396719933850'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/05/writing-kindle-presentation-notes-with.html' title='Writing Kindle Presentation Notes with MobiPocket Creator'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-4450479723966180438</id><published>2011-05-17T06:45:00.000-07:00</published><updated>2011-05-17T06:45:34.406-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Evil'/><category scheme='http://www.blogger.com/atom/ns#' term='Alt .Net Seattle'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><title type='text'>Hanselminutes #266 and Alt.Net Seattle’s "Open Source in Business"</title><content type='html'>&lt;p&gt;I just finished listening to Hanselminutes &lt;a href="http://www.hanselminutes.com/default.aspx?showID=286"&gt;Open Source vs. Making Money vs. Freaking Lasers - Are we all Evil? With Chris Sells&lt;/a&gt; and it reminded me of the &lt;a href="http://altnetseattle.pbworks.com/w/page/39917467/Open_Source_in_Business"&gt;Open Source in Business&lt;/a&gt; session that I attended at &lt;a href="http://altnet2011.heroku.com/"&gt;Alt.Net Seattle&lt;/a&gt;. This post is attempting to tie these two things together.&lt;/p&gt;&lt;h2&gt;Open Source vs. Commercial Software&lt;/h2&gt;&lt;p&gt;Should we share our non-core software? Scott and Chris suggest that open sourcing your software is a cost. If you open source a project to increase good will among the programmer community; it is a good thing but not necessarily profitable. &lt;/p&gt;&lt;p&gt;In Alt.Net Seattle’s Open Source in Business, a couple of participants claim that their companies benefited from "free" programming and used the contributor’s list to fill positions.&lt;/p&gt;&lt;p&gt;Scott and Chris talk about the Portland open source culture and how making money isn’t necessarily the biggest thing in Portland. Some of the open source that way to keep more of what they make. &lt;/p&gt;&lt;h2&gt;Companies Being Evil&lt;/h2&gt;&lt;p&gt;Apple and Google have done &lt;em&gt;evil&lt;/em&gt; things in the last few years, but Microsoft is still &lt;em&gt;evil&lt;/em&gt;. Scott and Chris suggested that Microsoft isn’t well organized enough to be &lt;em&gt;evil&lt;/em&gt;. No company of any size is beloved by everyone.&lt;/p&gt;&lt;p&gt;Is &lt;em&gt;evil&lt;/em&gt; associated with making money over customers? In any publicly traded company, stock holder value is king over everything else. Microsoft may feel more &lt;em&gt;evil&lt;/em&gt; because they charge us directly. People may like them better if pricing was less complicated (the pricing discussion goes on from there, but I won’t go there in this post). &lt;/p&gt;&lt;p&gt;Since Google and Facebook make money from advertising and don't charge us anything, they feel less &lt;em&gt;evil&lt;/em&gt; (Facebook privacy policy makes them feel more &lt;em&gt;evil&lt;/em&gt; to me).&lt;/p&gt;&lt;h2&gt;Originality of .NET Open Source&lt;/h2&gt;&lt;p&gt;At Alt.NET we also discussed the relative lack of originality in the .NET ecosystem. Many of the major open source projects (NHibernate, NUnit, etc.) are copies of Java open source projects. Perhaps many .NET developers are shy about starting ambitious open source project fearing that Microsoft will somehow co-opt it. Perhaps Microsoft is too disorganized to get out of the way of some cool open source project.&lt;/p&gt;&lt;p&gt;This may be the way that Microsoft is &lt;em&gt;evil&lt;/em&gt;. It also could be that the companies that use Microsoft software are more conservative and value safety over innovation. I've worked for a few companies that view open source as &lt;em&gt;evil&lt;/em&gt; -- to these companies, Microsoft is a crusader fighting against the chaos.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-4450479723966180438?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/4450479723966180438/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=4450479723966180438' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/4450479723966180438'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/4450479723966180438'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/05/hanselminutes-266-and-altnet-seattles.html' title='Hanselminutes #266 and Alt.Net Seattle’s &quot;Open Source in Business&quot;'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-9151793577123217423</id><published>2011-05-08T13:31:00.000-07:00</published><updated>2011-05-08T13:31:14.585-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Lame Laptop'/><category scheme='http://www.blogger.com/atom/ns#' term='HP'/><category scheme='http://www.blogger.com/atom/ns#' term='Alt .Net Seattle'/><title type='text'>Thoughts durring Alt .NET Seattle: Explaining my lame laptop.</title><content type='html'>&lt;p&gt;Confession: I cam to Alt .Net Seattle with a HP Pavilion Entertainment PC Laptop with a &lt;strong&gt;HUGE&lt;/strong&gt; screen. The thing is a monster. And it is totally uncool. I am not going to replace it for another year: I am not made of money.&lt;/p&gt;&lt;p&gt;I wonder if there are things I can to to acknowledge my folly in a light self deprecating way. Perhaps a sticker that says something like "I'm a slack jawed yokel from Spokane" or somehow making light of the fact that it isn't an Apple (it's 40% Apple here), but that seams too heavy to me. A sticker would be nice but what should is say? etc.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-9151793577123217423?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/9151793577123217423/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=9151793577123217423' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/9151793577123217423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/9151793577123217423'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/05/thoughts-durring-alt-net-seattle.html' title='Thoughts durring Alt .NET Seattle: Explaining my lame laptop.'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-580025034723551555</id><published>2011-05-02T05:12:00.000-07:00</published><updated>2011-05-17T06:37:54.251-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Alt .Net Seattle'/><category scheme='http://www.blogger.com/atom/ns#' term='jrcs3.com'/><title type='text'>Thoughts before Alt .NET Seattle: Part II: Using jrcs3.com</title><content type='html'>&lt;p&gt;I am going to &lt;a href="http://altnet2011.heroku.com/"&gt;Alt.Net 2011 Seattle Conference&lt;/a&gt; next weekend. Since I am not on the bleeding edge of technology at work, I’m looking into modern methods and technologies.&lt;/p&gt;&lt;h3&gt;Using my domain&lt;/h3&gt;&lt;p&gt;Several years ago, I bought the domain jrcs3.com; it the initials for my legal name &lt;em&gt;John Robert Chilton Stephens III&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Since I will be hanging out with the cool kid and in technology, all the cool kids have vanity domain, I need to make sure that my domain is visible on my cards, etc. So this weekend I:&lt;ul&gt;&lt;li&gt;Moved this blog from jrcs3.blogspot.com to brochure.jrcs3.com (it is “brochure” because someone said that it isn’t a blog until it gets comments). &lt;/li&gt;&lt;li&gt;Created a jrcs3.com event email address for the Alt.Net Seattle 2011. You will have to attend the event to see what it is.&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;When I get my next paycheck (Monday or Tuesday) I will:&lt;ul&gt;&lt;li&gt;Buy a year of hosting for jrcs3.com&lt;/li&gt;&lt;li&gt;Write a simple home page for it in Razor (linking to brochure.jrcs3.com). I have already created a WebMatrix project.&lt;/li&gt;&lt;li&gt;Print out a couple of sheets of business cards to hand out.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-580025034723551555?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/580025034723551555/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=580025034723551555' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/580025034723551555'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/580025034723551555'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/05/thoughts-before-alt-net-seattle-part-ii.html' title='Thoughts before Alt .NET Seattle: Part II: Using jrcs3.com'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-6815290653801286028</id><published>2011-04-29T06:46:00.000-07:00</published><updated>2011-04-29T06:46:17.556-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Alt .Net; TDD'/><title type='text'>Thoughts before Alt .NET Seattle: Part I: TDD</title><content type='html'>&lt;p&gt;I am going to &lt;a href="http://altnet2011.heroku.com/"&gt;Alt.Net 2011 Seattle Conference&lt;/a&gt; next weekend. Since I am not on the bleeding edge of technology at work, I’m looking into modern methods and technologies.&lt;/p&gt;&lt;h3&gt;TDD&lt;/h3&gt;&lt;p&gt;On my last couple of gigs, when I bring up Test Driven Development, I get a lecture about how it is overly academic and would never work "here" (one place even banned NUnit altogether). Yes, it may take more time to code, but at these places, we spend a lot of time fixing things after the fact.&lt;/p&gt;&lt;p&gt;I agree that it can be taken too far. There are times that it doesn’t make sense to write test before writing trivial code. UI is infamously un-testable. Be pragmatic, it is just as extreme to reject automated testing altogether&lt;/p&gt;&lt;p&gt;I like the way TDD appears to make you think. You know, this function needs to do these 5 things, and what about this edge case, etc. And I have some tests that I can use later, for less effort than if wrote the test later.&lt;/p&gt;&lt;p&gt;I have snuck some tests into the projects that I have more control over. Most of the tests are too large (cover more one thing) and break other TDD rules. Since I can’t get approval to use an IOC container, they are not unit test. Even with these lower quality tests, I have found bugs and have been able to safely re-factor.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-6815290653801286028?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/6815290653801286028/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=6815290653801286028' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/6815290653801286028'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/6815290653801286028'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/04/thoughts-before-alt-net-seattle-part-i.html' title='Thoughts before Alt .NET Seattle: Part I: TDD'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-4985334957379638977</id><published>2011-04-14T12:46:00.000-07:00</published><updated>2011-04-14T12:46:06.834-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Non-Technical'/><title type='text'>Going to St. Louis</title><content type='html'>&lt;p&gt;Nine years ago, my sister Susie was &lt;a href="http://www.seattlepi.com/default/article/Transportation-safety-expert-Stephens-killed-when-1083470.php"&gt;run over by a bus and killed&lt;/a&gt;. I am going to St. Louis to help my mother  &lt;a href="http://mobikefed.org/2011/04/april-16th-planting-tree-susie-stephens-bicycle-advocate-killed-st-louis"&gt; plant a tree in her honor&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;I both look forward to and dread this trip. After all, it is the place of her death. It is a city that looms large in my mind even though I have never been there. I should have gone years ago and face the demons, now is as good a time as any.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-4985334957379638977?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/4985334957379638977/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=4985334957379638977' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/4985334957379638977'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/4985334957379638977'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/04/going-to-st-louis.html' title='Going to St. Louis'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-5517073896903261321</id><published>2011-04-12T22:13:00.000-07:00</published><updated>2011-05-01T19:42:17.669-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='T4 Templates'/><category scheme='http://www.blogger.com/atom/ns#' term='Note to Work'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Generation'/><category scheme='http://www.blogger.com/atom/ns#' term='Linq to SQL'/><title type='text'>Generate Linq To Sql .DBML Fragments</title><content type='html'>&lt;p&gt;Another user for my post on getting the &lt;a href="/2011/03/getting-schema-of-stored-procedure.html"&gt;schema from a Stored Procedure&lt;/a&gt;. This time I am generating a Dbml fragment. &lt;/p&gt;&lt;p&gt;In the Column element, I am not providing a DbType. I don’t use Linq to Sql in such a way that it actually uses that value for anything important. I am also assuming that CanBeNull is true.&lt;/p&gt;&lt;p&gt;Yes, this is totally a message for work post. If you need detail as to what I’m doing, check &lt;a href="/2011/03/generate-dataset-xds.html"&gt;this&lt;/a&gt; out. &lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ assembly name="TsqlDesriptionUtil.dll" #&amp;gt;&lt;br /&gt;&amp;lt;#@ import namespace="Microsoft.VisualStudio.TextTemplating" #&amp;gt;&lt;br /&gt;&amp;lt;#@ import namespace="TsqlDesriptionUtil" #&amp;gt;&lt;br /&gt;&amp;lt;#@ import namespace="System.Collections.Generic" #&amp;gt;&lt;br /&gt;&amp;lt;#+&lt;br /&gt;    public class DbmlFunctionFromTSqlCmd : TextTransformation&lt;br /&gt;    {&lt;br /&gt;        public string FunctionName;&lt;br /&gt;        public string FunctionMethod;&lt;br /&gt;        public List&amp;lt;TableDescription&amp;gt; tables;&lt;br /&gt;&lt;br /&gt;        public override string TransformText()&lt;br /&gt;        {&lt;br /&gt;#&amp;gt;    &amp;lt;Function Name="&amp;lt;#= FunctionName&lt;br /&gt;                #&amp;gt;" Method="&amp;lt;#= FunctionMethod #&amp;gt;"&amp;gt;&lt;br /&gt;&amp;lt;#+ foreach(TableDescription table in tables)&lt;br /&gt;    { #&amp;gt;        &amp;lt;ElementType Name="&amp;lt;#= FunctionMethod #&amp;gt;Result_&amp;lt;#= table.TableName #&amp;gt;"&amp;gt;&lt;br /&gt;&amp;lt;#+ foreach(FieldDescription field in table.Fields)&lt;br /&gt;   { #&amp;gt;             &amp;lt;Column Name="&amp;lt;#= field.FieldName #&amp;gt;" &lt;br /&gt;                      Type="&amp;lt;#= field.FieldType.FullName  #&amp;gt;" &lt;br /&gt;                      CanBeNull="true" /&amp;gt;&lt;br /&gt;&amp;lt;#+ } #&amp;gt;&lt;br /&gt;         &amp;lt;/ElementType&amp;gt;&lt;br /&gt;&amp;lt;#+ } #&amp;gt;&lt;br /&gt;    &amp;lt;/Function&amp;gt;&lt;br /&gt;&amp;lt;#+ &lt;br /&gt;        return this.GenerationEnvironment.ToString();&lt;br /&gt;    }&lt;br /&gt;} #&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Again, for Demonstration purposes I wrote a simple T4 Template that includes the template above and uses the library I wrote in &lt;a href="/2011/03/getting-schema-of-stored-procedure.html"&gt;this post&lt;/a&gt; to get a description of the data. &lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ template language="C#v3.5" debug="true" &lt;br /&gt;#&amp;gt;&amp;lt;#@ output extension="txt" &lt;br /&gt;#&amp;gt;&amp;lt;#@ include file="DbmlFunctionFromTSqlCmd.tt" &lt;br /&gt;#&amp;gt;&amp;lt;#@ assembly name="TsqlDesriptionUtil.dll" &lt;br /&gt;#&amp;gt;&amp;lt;#@ import namespace="TsqlDesriptionUtil" &lt;br /&gt;#&amp;gt;&amp;lt;#&lt;br /&gt;    // Since I'm generating XML, I will go to extreme measures to avoid new &lt;br /&gt;    // line characters like the strange formatting of declarations above ^&lt;br /&gt; &lt;br /&gt;    // Get the table descriptions for given T-SQL&lt;br /&gt;    string conString = @"Data Source=localhost;" +&lt;br /&gt;      @"Initial Catalog=Northwind;Integrated Security=True";&lt;br /&gt;    string commandString = "EXEC  CustOrderHist @CustomerID='ALFKI'";&lt;br /&gt;    List&amp;lt;TableDescription&amp;gt; tables = &lt;br /&gt;      TsqlCommandSchema.GetFieldDescription(conString, commandString);&lt;br /&gt; &lt;br /&gt;    // Generate DBML Fragment:&lt;br /&gt;    var gen = new DbmlFunctionFromTSqlCmd();&lt;br /&gt;    gen.FunctionName = "dbo.GetBigTableDataUseTempTab";&lt;br /&gt;    gen.FunctionMethod = "MyNew";&lt;br /&gt;    gen.tables = tables;&lt;br /&gt;    Write(gen.TransformText()); &lt;br /&gt;#&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;(If I were more of a studman programmer dude, I'd write a Visual Studio Add-in that would insert this fragment directly into my .dbml file.)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-5517073896903261321?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/5517073896903261321/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=5517073896903261321' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5517073896903261321'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5517073896903261321'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/04/generate-linq-to-sql-dbml-fragments.html' title='Generate Linq To Sql .DBML Fragments'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-2996342294207651947</id><published>2011-03-29T06:36:00.000-07:00</published><updated>2011-03-31T20:47:12.847-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='T4 Templates'/><category scheme='http://www.blogger.com/atom/ns#' term='Note to Work'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Generation'/><category scheme='http://www.blogger.com/atom/ns#' term='DataSet'/><title type='text'>Generate DataSet .XDS</title><content type='html'>&lt;p&gt;Last week on my Brochure, I wrote about getting the schema of a &lt;a href="/2011/03/getting-schema-of-stored-procedure.html"&gt;Stored Procedure or other T-SQL command&lt;/a&gt;.  Now I am going to bring this a little farther and generate am .XDS file that can be used to generate a Typed DataSet. This T4 Template include file takes a List&lt;TableDescription&gt; and a DataSet name and generates the .XSD.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ assembly name="TsqlDesriptionUtil.dll" #&amp;gt;&lt;br /&gt;&amp;lt;#@ import namespace="Microsoft.VisualStudio.TextTemplating" #&amp;gt;&lt;br /&gt;&amp;lt;#@ import namespace="TsqlDesriptionUtil" #&amp;gt;&lt;br /&gt;&amp;lt;#@ import namespace="System.Collections.Generic" #&amp;gt;&lt;br /&gt;&amp;lt;#+&lt;br /&gt;    public class DataSetFromTSqlCmd: TextTransformation&lt;br /&gt;    {&lt;br /&gt;        public string dsName;&lt;br /&gt;        public List&amp;lt;TableDescription&amp;gt; tables;&lt;br /&gt;&lt;br /&gt;        public override string TransformText()&lt;br /&gt;        {&lt;br /&gt;#&amp;gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;xs:schema id="&amp;lt;#= dsName #&amp;gt;" &lt;br /&gt;  targetNamespace="http://jrcs3.blogspot.com/&amp;lt;#= dsName #&amp;gt;.xsd"&lt;br /&gt;  xmlns:mstns="http://jrcs3.blogspot.com/&amp;lt;#= dsName #&amp;gt;.xsd" &lt;br /&gt;  xmlns="http://jrcs3.blogspot.com/&amp;lt;#= dsName #&amp;gt;.xsd" &lt;br /&gt;  xmlns:xs="http://www.w3.org/2001/XMLSchema" &lt;br /&gt;  xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"&lt;br /&gt;  xmlns:msprop="urn:schemas-microsoft-com:xml-msprop" &lt;br /&gt;  attributeFormDefault="qualified" &lt;br /&gt;  elementFormDefault="qualified"&amp;gt;&lt;br /&gt;  &amp;lt;xs:annotation&amp;gt;&lt;br /&gt;    &amp;lt;xs:appinfo source="urn:schemas-microsoft-com:xml-msdatasource"&amp;gt;&lt;br /&gt;      &amp;lt;DataSource DefaultConnectionIndex="0" &lt;br /&gt;          FunctionsComponentName="QueriesTableAdapter"&lt;br /&gt;          Modifier="AutoLayout, AnsiClass, Class, Public" &lt;br /&gt;          SchemaSerializationMode="IncludeSchema" &lt;br /&gt;          xmlns="urn:schemas-microsoft-com:xml-msdatasource"&amp;gt;&lt;br /&gt;        &amp;lt;Connections /&amp;gt;&lt;br /&gt;        &amp;lt;Tables /&amp;gt;&lt;br /&gt;        &amp;lt;Sources /&amp;gt;&lt;br /&gt;      &amp;lt;/DataSource&amp;gt;&lt;br /&gt;    &amp;lt;/xs:appinfo&amp;gt;&lt;br /&gt;  &amp;lt;/xs:annotation&amp;gt;&lt;br /&gt; &amp;lt;xs:element name="&amp;lt;#= dsName #&amp;gt;" &lt;br /&gt;        msdata:IsDataSet="true" &lt;br /&gt;        msdata:UseCurrentLocale="true" &lt;br /&gt;        msprop:Generator_UserDSName="&amp;lt;#= dsName #&amp;gt;" &lt;br /&gt;        msprop:Generator_DataSetName="&amp;lt;#= dsName #&amp;gt;" &lt;br /&gt;        msprop:EnableTableAdapterManager="true"&amp;gt;&lt;br /&gt;    &amp;lt;xs:complexType&amp;gt;&lt;br /&gt;      &amp;lt;xs:choice minOccurs="0" maxOccurs="unbounded"&amp;gt;&lt;br /&gt;&amp;lt;#+ foreach(TableDescription table in tables)&lt;br /&gt;    { #&amp;gt;&lt;br /&gt;        &amp;lt;xs:element &lt;br /&gt;            name="&amp;lt;#= table.TableName #&amp;gt;"  &lt;br /&gt;            msprop:Generator_UserTableName="&amp;lt;#= table.TableName #&amp;gt;" &lt;br /&gt;            msprop:Generator_RowDeletedName="&amp;lt;#= table.TableName #&amp;gt;RowDeleted" &lt;br /&gt;            msprop:Generator_RowChangedName="&amp;lt;#= table.TableName #&amp;gt;RowChanged" &lt;br /&gt;            msprop:Generator_RowClassName="&amp;lt;#= table.TableName #&amp;gt;Row" &lt;br /&gt;            msprop:Generator_RowChangingName="&amp;lt;#= table.TableName #&amp;gt;RowChanging" &lt;br /&gt;            msprop:Generator_RowEvArgName="&amp;lt;#= table.TableName #&amp;gt;RowChangeEvent" &lt;br /&gt;            msprop:Generator_RowEvHandlerName="&amp;lt;#= table.TableName &lt;br /&gt;               #&amp;gt;RowChangeEventHandler" &lt;br /&gt;            msprop:Generator_TableClassName="&amp;lt;#= table.TableName #&amp;gt;DataTable" &lt;br /&gt;            msprop:Generator_TableVarName="table&amp;lt;#= table.TableName #&amp;gt;" &lt;br /&gt;            msprop:Generator_RowDeletingName="&amp;lt;#= table.TableName #&amp;gt;RowDeleting" &lt;br /&gt;            msprop:Generator_TablePropName="&amp;lt;#= table.TableName #&amp;gt;"&amp;gt;&lt;br /&gt;          &amp;lt;xs:complexType&amp;gt;&lt;br /&gt;            &amp;lt;xs:sequence&amp;gt;&lt;br /&gt;&amp;lt;#+ foreach(FieldDescription field in table.Fields)&lt;br /&gt; { #&amp;gt;&lt;br /&gt;                &amp;lt;xs:element &lt;br /&gt;                    name="&amp;lt;#= field.FieldName #&amp;gt;" &lt;br /&gt;                    msprop:Generator_UserColumnName="&amp;lt;#= field.FieldName #&amp;gt;"&lt;br /&gt;                    msprop:Generator_ColumnVarNameInTable="column&amp;lt;#= field.FieldName &lt;br /&gt;                      #&amp;gt;" &lt;br /&gt;                    msprop:Generator_ColumnPropNameInRow="&amp;lt;#= field.FieldName #&amp;gt;" &lt;br /&gt;                    msprop:Generator_ColumnPropNameInTable="&amp;lt;#= field.FieldName &lt;br /&gt;                      #&amp;gt;Column" &lt;br /&gt;                    type="xs:&amp;lt;#= field.XsdTypeName #&amp;gt;" &lt;br /&gt;                    minOccurs="0" /&amp;gt;&lt;br /&gt;&amp;lt;#+ } #&amp;gt;&lt;br /&gt;            &amp;lt;/xs:sequence&amp;gt;&lt;br /&gt;          &amp;lt;/xs:complexType&amp;gt;&lt;br /&gt;        &amp;lt;/xs:element&amp;gt;&lt;br /&gt;&amp;lt;#+ } #&amp;gt;&lt;br /&gt;      &amp;lt;/xs:choice&amp;gt;&lt;br /&gt;    &amp;lt;/xs:complexType&amp;gt;&lt;br /&gt;  &amp;lt;/xs:element&amp;gt;&lt;br /&gt;&amp;lt;/xs:schema&amp;gt;&lt;br /&gt;&amp;lt;#+ &lt;br /&gt;  return this.GenerationEnvironment.ToString();&lt;br /&gt; }&lt;br /&gt;} #&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;For Demonstration purposes I wrote a simple T4 Template that includes the template above and uses the library I wrote in &lt;a href="/2011/03/getting-schema-of-stored-procedure.html"&gt;this post&lt;/a&gt; to get a description of the data. &lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ template language="C#v3.5" debug="true" &lt;br /&gt;#&amp;gt;&amp;lt;#@ output extension="xsd" &lt;br /&gt;#&amp;gt;&amp;lt;#@ include file="DataSetFromTSqlCmd.tt" &lt;br /&gt;#&amp;gt;&amp;lt;#@ assembly name="TsqlDesriptionUtil.dll" &lt;br /&gt;#&amp;gt;&amp;lt;#@ import namespace="TsqlDesriptionUtil" &lt;br /&gt;#&amp;gt;&amp;lt;#&lt;br /&gt;    // Since I'm generating XML, I will go to extreme measures to avoid new line &lt;br /&gt;    // characters like the strange formatting of declarations above ^&lt;br /&gt;&lt;br /&gt;    // Get the table descriptions for given T-SQL&lt;br /&gt;    string conString = @"Data Source=localhost;" +&lt;br /&gt;      @"Initial Catalog=Northwind;Integrated Security=True";&lt;br /&gt;    string commandString = "EXEC  CustOrderHist @CustomerID='ALFKI'";&lt;br /&gt;    List&amp;lt;TableDescription&amp;gt; tables = &lt;br /&gt;      TsqlCommandSchema.GetFieldDescription(conString, commandString);&lt;br /&gt;&lt;br /&gt;    // Generate XSD:&lt;br /&gt;    var gen = new DataSetFromTSqlCmd();&lt;br /&gt;    gen.dsName = "MyNewDS";&lt;br /&gt;    gen.tables = tables;&lt;br /&gt;    Write(gen.TransformText()); &lt;br /&gt;#&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Since TsqlCommandSchema.GetFieldDescription supports multiple results sets and Stored Procedure that use temporary tables.&lt;/p&gt;&lt;p&gt;At work I will probably integrate this template into an existing code generation tool using my &lt;a href="/2010/12/generating-nullable-ado.html"&gt;TTCommucator&lt;/a&gt; tool.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-2996342294207651947?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/2996342294207651947/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=2996342294207651947' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2996342294207651947'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2996342294207651947'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/03/generate-dataset-xds.html' title='Generate DataSet .XDS'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-3281619912600771638</id><published>2011-03-22T06:39:00.000-07:00</published><updated>2011-03-31T20:48:54.230-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Note to Work'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Generation'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><title type='text'>Getting the Schema of a Stored Procedure Results Set</title><content type='html'>&lt;p&gt;Visual Studio is pretty good at discovering the schema of a stored procedure if the procedure doesn't use temporary tables and returns only one result set. You can drag the stored procedure on to a DataSet or Linq to Sql Design Surface and it is generated for you. In real life, stored procedures don’t fit into that neat box.&lt;/p&gt;&lt;p&gt;Since I am lazy and don’t like to build DataSets by hand, I wrote this little class. Note that I am actually executing the T-SQL command. Any side effect of the stored procedure will take place; this is acceptable in my environment, it may not be in yours.&lt;/p&gt;&lt;p&gt;I am getting less information from this method than I get from static sources like SQL Server’s SMO; for example, I am not getting the length of strings. I am getting enough information to do what I want to do.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Data;&lt;br /&gt;using System.Data.SqlClient;&lt;br /&gt;&lt;br /&gt;namespace TsqlDesriptionUtil&lt;br /&gt;{&lt;br /&gt;    public class TsqlCommandSchema&lt;br /&gt;    {&lt;br /&gt;        public static List&amp;lt;TableDescription&amp;gt; GetFieldDescription(&lt;br /&gt;            string conString, string commandString)&lt;br /&gt;        {&lt;br /&gt;            var rVal = new List&amp;lt;TableDescription&amp;gt;();&lt;br /&gt;            int tableNumber = 1;&lt;br /&gt;            using (var con = new SqlConnection(conString))&lt;br /&gt;            {&lt;br /&gt;                using (var com = new SqlCommand(commandString, con))&lt;br /&gt;                {&lt;br /&gt;                    con.Open();&lt;br /&gt;                    // WARNING: I am executing the command, beware of side effects!&lt;br /&gt;                    SqlDataReader reader = &lt;br /&gt;                        com.ExecuteReader(CommandBehavior.CloseConnection);&lt;br /&gt;                    // Table Loop&lt;br /&gt;                    do&lt;br /&gt;                    {&lt;br /&gt;                        var fieldDescriptionList = new List&amp;lt;FieldDescription&amp;gt;();&lt;br /&gt;                        // Field Loop&lt;br /&gt;                        for (int i = 0; i &amp;lt; reader.FieldCount; ++i)&lt;br /&gt;                        {&lt;br /&gt;                            Type fieldType = reader.GetProviderSpecificFieldType(i);&lt;br /&gt;                            fieldDescriptionList.Add(&lt;br /&gt;                                new FieldDescription(reader.GetName(i), &lt;br /&gt;                                reader.GetDataTypeName(i), reader.GetFieldType(i)));&lt;br /&gt;                        }&lt;br /&gt;                        // T-SQL doesn't give table names, so I will make up my own&lt;br /&gt;                        rVal.Add(new TableDescription(string.Format(&lt;br /&gt;                            "Table{0}", tableNumber++), fieldDescriptionList));&lt;br /&gt;                    } while (reader.NextResult());&lt;br /&gt;                    con.Close();&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            return rVal;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    public class TableDescription&lt;br /&gt;    {&lt;br /&gt;        public TableDescription(string tableName, List&amp;lt;FieldDescription&amp;gt; fields)&lt;br /&gt;        {&lt;br /&gt;            this.TableName = tableName;&lt;br /&gt;            this.Fields = fields;&lt;br /&gt;        }&lt;br /&gt;        public string TableName { get; set; }&lt;br /&gt;        public List&amp;lt;FieldDescription&amp;gt; Fields { get; set; }&lt;br /&gt;        public int Count&lt;br /&gt;        {&lt;br /&gt;            get&lt;br /&gt;            {&lt;br /&gt;                if (this.Fields != null)&lt;br /&gt;                    return this.Fields.Count;&lt;br /&gt;                else&lt;br /&gt;                    throw new Exception("Fields not loaded");&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    public class FieldDescription&lt;br /&gt;    {&lt;br /&gt;        public FieldDescription(string fieldName, string dataTypeName, Type fieldType)&lt;br /&gt;        {&lt;br /&gt;            this.FieldName = fieldName;&lt;br /&gt;            this.DataTypeName = dataTypeName;&lt;br /&gt;            this.FieldType = fieldType;&lt;br /&gt;        }&lt;br /&gt;        public string FieldName { get; set; }&lt;br /&gt;        public string DataTypeName { get; set; }&lt;br /&gt;        public Type FieldType { get; set; }&lt;br /&gt;        public string XsdTypeName&lt;br /&gt;        {&lt;br /&gt;            get&lt;br /&gt;            {&lt;br /&gt;                Type t = this.FieldType;&lt;br /&gt;                return getXsdTypeNameForType(t);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static string getXsdTypeNameForType(Type t)&lt;br /&gt;        {&lt;br /&gt;            string rVal = string.Empty;&lt;br /&gt;            //.NET Framework type XML Schema (XSD) type&lt;br /&gt;            switch (t.FullName)&lt;br /&gt;            {&lt;br /&gt;                case "System.Boolean": rVal = "Boolean"; break;&lt;br /&gt;                case "System.Byte": rVal = "unsignedByte"; break;&lt;br /&gt;                case "System.Byte[]": rVal = "base64Binary"; break;&lt;br /&gt;                case "System.DateTime": rVal = "dateTime"; break;&lt;br /&gt;                case "System.Decimal": rVal = "decimal"; break;&lt;br /&gt;                case "System.Double": rVal = "Double"; break;&lt;br /&gt;                case "System.Int16": rVal = "short"; break;&lt;br /&gt;                case "System.Int32": rVal = "int"; break;&lt;br /&gt;                case "System.Int64": rVal = "long"; break;&lt;br /&gt;                case "System.SByte": rVal = "Byte"; break;&lt;br /&gt;                case "System.String": rVal = "string"; break;&lt;br /&gt;                case "System.String[]": rVal = "ENTITIES"; break;&lt;br /&gt;                case "System.TimeSpan": rVal = "duration"; break;&lt;br /&gt;                case "System.UInt16": rVal = "unsignedShort"; break;&lt;br /&gt;                case "System.UInt32": rVal = "unsignedInt"; break;&lt;br /&gt;                case "System.UInt64": rVal = "unsignedLong"; break;&lt;br /&gt;                case "System.Uri": rVal = "anyURI"; break;&lt;br /&gt;                case "System.Xml.XmlQualifiedName": rVal = "QName"; break;&lt;br /&gt;            }&lt;br /&gt;            return rVal;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;I compiled the above C# source file into an assembly. Here is a xUnit test that demonstrates its use.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;[Fact(DisplayName = "Run SP 001")]&lt;br /&gt;public void RunSp001()&lt;br /&gt;{&lt;br /&gt;    string conString = @"Data Source=localhost;Initial Catalog=My_Db;" + &lt;br /&gt;        "Integrated Security=True";&lt;br /&gt;    string commandString = "EXEC  GetBigTableDataUseTempTab 101";&lt;br /&gt;    List&amp;lt;TableDescription&amp;gt; rVal = &lt;br /&gt;        TsqlCommandSchema.GetFieldDescription(conString, commandString);&lt;br /&gt;&lt;br /&gt;    foreach (var item in rVal) &lt;br /&gt;    {&lt;br /&gt;        Console.WriteLine(string.Format("{0}: {1}", item.TableName, item.Count));&lt;br /&gt;        foreach(var field in item.Fields)&lt;br /&gt;            Console.WriteLine(&lt;br /&gt;                string.Format("\t{0}\t{1}\t{2}\t{3}", &lt;br /&gt;                    field.FieldName, &lt;br /&gt;                    field.DataTypeName, &lt;br /&gt;                    field.FieldType, &lt;br /&gt;                    field.XsdTypeName));&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-3281619912600771638?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/3281619912600771638/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=3281619912600771638' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/3281619912600771638'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/3281619912600771638'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/03/getting-schema-of-stored-procedure.html' title='Getting the Schema of a Stored Procedure Results Set'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-3674039281604048051</id><published>2011-03-21T20:03:00.000-07:00</published><updated>2011-03-31T21:25:35.633-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Types'/><category scheme='http://www.blogger.com/atom/ns#' term='XSD'/><title type='text'>GetXsdTypeNameForType() function</title><content type='html'>&lt;p&gt;For a project I'm working on, I need to convert .NET Framework types into XML Schema (XSD) types. I wrote a little function to do the translation:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public static string GetXsdTypeNameForType(Type t)&lt;br /&gt;{&lt;br /&gt;    string rVal = string.Empty;&lt;br /&gt;    switch (t.FullName)&lt;br /&gt;    {&lt;br /&gt;        case "System.Boolean": rVal = "boolean"; break;&lt;br /&gt;        case "System.Byte": rVal = "unsignedByte"; break;&lt;br /&gt;        case "System.Byte[]": rVal = "base64Binary"; break;&lt;br /&gt;        case "System.DateTime": rVal = "dateTime"; break;&lt;br /&gt;        case "System.Decimal": rVal = "decimal"; break;&lt;br /&gt;        case "System.Double": rVal = "double"; break;&lt;br /&gt;        case "System.Int16": rVal = "short"; break;&lt;br /&gt;        case "System.Int32": rVal = "int"; break;&lt;br /&gt;        case "System.Int64": rVal = "long"; break;&lt;br /&gt;        case "System.SByte": rVal = "byte"; break;&lt;br /&gt;        case "System.String": rVal = "string"; break;&lt;br /&gt;        case "System.String[]": rVal = "ENTITIES"; break;&lt;br /&gt;        case "System.TimeSpan": rVal = "duration"; break;&lt;br /&gt;        case "System.UInt16": rVal = "unsignedShort"; break;&lt;br /&gt;        case "System.UInt32": rVal = "unsignedInt"; break;&lt;br /&gt;        case "System.UInt64": rVal = "unsignedLong"; break;&lt;br /&gt;        case "System.Uri": rVal = "anyURI"; break;&lt;br /&gt;        case "System.Xml.XmlQualifiedName": rVal = "QName"; break;&lt;br /&gt;    }&lt;br /&gt;    return rVal;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;NOTE: There are places where I gad to make a decision as to which XSD type would map to System.TimeDate, System.String, System.Byte[], etc. And there which XSD type will map my custom Employee, Appointment or Cow types!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-3674039281604048051?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/3674039281604048051/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=3674039281604048051' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/3674039281604048051'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/3674039281604048051'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/03/getxsdtypenamefortype-function.html' title='GetXsdTypeNameForType() function'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-5680824923378149128</id><published>2011-03-07T19:29:00.000-08:00</published><updated>2011-06-12T06:23:02.292-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Late'/><category scheme='http://www.blogger.com/atom/ns#' term='T4 Templates'/><category scheme='http://www.blogger.com/atom/ns#' term='Boise Code Camp'/><category scheme='http://www.blogger.com/atom/ns#' term='Presentation Notes'/><title type='text'>Boise Code Camp 2011 Presentation Notes</title><content type='html'>&lt;p&gt;Sorry I’m late getting this up. I will give usual excuses of being busy.&lt;/p&gt;&lt;p&gt;Since I developed this talk on this blog, this entry will essentially be a link list. I put a copy of the slides in Google doc and you can reference it &lt;a href="https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0ByZJy7UqXWOuN2FiMzFlZmQtZTg3Mi00MDcwLWFkMDMtMGQ4MzM2ZTlhMDBm&amp;hl=en"&gt;here&lt;/a&gt;&lt;h2 id="TemplateParts"&gt;Template Parts&lt;/h2&gt;&lt;p&gt;I presented a slide that showed the basic template parts in a small mock template:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ template language="C#" #&amp;gt;&lt;br /&gt;&amp;lt;#@ directive property=“value” #&amp;gt;&lt;br /&gt;&amp;lt;# var item = "Statement Block"; #&amp;gt;&lt;br /&gt;Text Block &lt;br /&gt;&amp;lt;#= "Expression Block" #&amp;gt;&lt;br /&gt;&amp;lt;#+ &lt;br /&gt;    string ClassFeatureBlock(string thingy)&lt;br /&gt;    {&lt;br /&gt;        return thingy;&lt;br /&gt;    } &lt;br /&gt;#&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;Hello World Monty&lt;/h2&gt;&lt;p&gt;I showed some of the elementary features of T4 templates by refactoring a basic template that would create a text file that contained the infamous words “Hello World”. A script of that exercise is &lt;a href="http://jrcs3.blogspot.com/2011/03/t4-template-tour-of-first-gear.html"&gt;here&lt;/a&gt;&lt;h2 id="BasicDemo"&gt;Basic Code Generation Demonstration&lt;/h2&gt;&lt;p&gt;To demonstrate Code Generation I set out to generate a simple T-SQL Select Statement using Sql Management Objects (SMO).&lt;/p&gt;&lt;p&gt;The Target Code looked something like this:&lt;/p&gt;&lt;h5&gt;Include (SelectSpInclude.tt)&lt;/h5&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ import namespace="Microsoft.VisualStudio.TextTemplating" #&amp;gt;&lt;br /&gt;&amp;lt;#@ assembly name="Microsoft.SqlServer.ConnectionInfo" #&amp;gt;&lt;br /&gt;&amp;lt;#@ assembly name="Microsoft.SqlServer.Smo" #&amp;gt;&lt;br /&gt;&amp;lt;#@ import namespace="Microsoft.SqlServer.Management.Smo" #&amp;gt;&lt;br /&gt;&amp;lt;#+&lt;br /&gt;    public class SelectSpInclude: TextTransformation&lt;br /&gt;    {&lt;br /&gt;        public string ServerName;&lt;br /&gt;        public string DbName;&lt;br /&gt;        public string TableName;&lt;br /&gt;&lt;br /&gt;        public override string TransformText()&lt;br /&gt;        {&lt;br /&gt; &lt;br /&gt;        Table table = getTable(ServerName, DbName, TableName);&lt;br /&gt;#&amp;gt;&lt;br /&gt;SELECT &amp;lt;#+ bool forgetComma = true;&lt;br /&gt; foreach (Column col in table.Columns)&lt;br /&gt;{ #&amp;gt;&amp;lt;#+if (!forgetComma) Write("      ,");#&amp;gt;[&amp;lt;#= col.Name #&amp;gt;]&lt;br /&gt;&amp;lt;#+ forgetComma = false;&lt;br /&gt;} #&amp;gt;&lt;br /&gt;FROM &amp;lt;#= table.Name #&amp;gt;&amp;lt;#+&lt;br /&gt;&lt;br /&gt;        return this.GenerationEnvironment.ToString();&lt;br /&gt;    } &lt;br /&gt;    Table getTable(string serverName, string dbName, string tableName)&lt;br /&gt;    {&lt;br /&gt;        Server server = new Server(serverName);&lt;br /&gt;        Database database = new Database(server, dbName);&lt;br /&gt;        Table table = new Table(database, tableName);&lt;br /&gt;        table.Refresh();&lt;br /&gt;        return table; &lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;#&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;h5&gt;Template (EmployeesSp.tt)&lt;/h5&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ template language="C#v3.5" #&amp;gt;&lt;br /&gt;&amp;lt;#@ output extension="sql" #&amp;gt;&lt;br /&gt;&amp;lt;#@ include file="SelectSpInclude.tt" #&amp;gt;&lt;br /&gt;&amp;lt;#&lt;br /&gt;    SelectSpInclude gen = new SelectSpInclude();&lt;br /&gt;    gen.ServerName = @"localhost\SQLEXPRESS";&lt;br /&gt;    gen.DbName = "Northwind";&lt;br /&gt;    gen.TableName = "Employees"; Write(gen.TransformText());&lt;br /&gt;#&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h5&gt;Result (EmployeesSp.sql)&lt;/h5&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;SELECT [EmployeeID]&lt;br /&gt;      ,[LastName]&lt;br /&gt;      ,[FirstName]&lt;br /&gt;      ,[Title]&lt;br /&gt;      ,[TitleOfCourtesy]&lt;br /&gt;      ,[BirthDate]&lt;br /&gt;      ,[HireDate]&lt;br /&gt;      ,[Address]&lt;br /&gt;      ,[City]&lt;br /&gt;      ,[Region]&lt;br /&gt;      ,[PostalCode]&lt;br /&gt;      ,[Country]&lt;br /&gt;      ,[HomePhone]&lt;br /&gt;      ,[Extension]&lt;br /&gt;      ,[Photo]&lt;br /&gt;      ,[Notes]&lt;br /&gt;      ,[ReportsTo]&lt;br /&gt;      ,[PhotoPath]&lt;br /&gt;FROM Employees&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Somewhere in this part of the presentation, someone asked if it is possible to generate a series of files from a single template, a separate code file for each table in a database. Oleg Sych has a blog post that does just that &lt;a href="http://www.olegsych.com/2008/09/t4-tutorial-creating-complex-code-generators/"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;h2&gt;Generating a Nullable ADO.NET DataSet Wrapper&lt;/h2&gt;&lt;p&gt;This is when I went to Show and Tell Mode. I demonstrate a Nullable DataSet Wrapper that I wrote in these blog entries. I wrote the templates in VB.NET to generate code in C#.&lt;/p&gt;&lt;p&gt;&lt;a href="http://jrcs3.blogspot.com/2010/11/nullable-ado.html"&gt;Part 1&lt;/a&gt;, &lt;a href="http://jrcs3.blogspot.com/2010/11/generating-nullable-ado.html"&gt;Part 2&lt;/a&gt;, &lt;a href="http://jrcs3.blogspot.com/2010/12/generating-nullable-ado.html"&gt;Part 3&lt;/a&gt; &amp;amp;&lt;a href="http://jrcs3.blogspot.com/2010/12/generating-nullable-ado_19.html"&gt;Part 4&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-5680824923378149128?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/5680824923378149128/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=5680824923378149128' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5680824923378149128'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5680824923378149128'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/03/boise-code-camp-2011-presentation-notes.html' title='Boise Code Camp 2011 Presentation Notes'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-2589147717783558792</id><published>2011-03-06T16:37:00.000-08:00</published><updated>2011-05-30T12:46:08.522-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='T4 Templates'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>T4 Template Tour of First Gear</title><content type='html'>&lt;p&gt;At the Boise Code Camp, I lead off with a demonstration of some basic features of T4 Templates. The point of the presentation is to get you from no T4 to the level of most blog examples. I got good reviews from the few who attended my session, so I thought I would attempt to write it down. Here goes…&lt;/p&gt;&lt;h2&gt;The Script&lt;/h2&gt;&lt;p&gt;First, create a Text file and change the extension to "tt". We’ll call it "Hello.tt". I will add a template directive and tell T4 that I want to use C#. I add the text "Hello World" below the directive. When I save it, "Hello.cs" appears below the template.&lt;/p&gt;&lt;h5&gt;Template (Hello.tt):&lt;/h5&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ template language="C#" #&amp;gt;&lt;br /&gt;Hello World&lt;br /&gt;&lt;/pre&gt;&lt;h5&gt;Output (Hello.cs):&lt;/h5&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;Hello World&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Also notice that Visual Studio complains that Hello.cs won’t compile. For this demonstration, I don’t want to create a C# code file, so I will tell the template to create a "txt" file with an &lt;em&gt;output directive&lt;/em&gt;.&lt;/p&gt;&lt;h5&gt;Template (Hello.tt):&lt;/h5&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ template language="C#" #&amp;gt;&lt;br /&gt;&amp;lt;#@ output extension="txt" #&amp;gt;&lt;br /&gt;Hello World&lt;br /&gt;&lt;/pre&gt;&lt;h5&gt;Output (Hello.txt):&lt;/h5&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;Hello World&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Visual Studio is happy because it doesn’t try to compile "txt" files. (Since it doesn't change, I won't repeat the output again.)&lt;/p&gt;&lt;p&gt;Now, let’s add some actual C# template code, I’m going to create a variable called "name" in a &lt;em&gt;Statement Block&lt;/em&gt; and reference it in an &lt;em&gt;Expression Block&lt;/em&gt;.&lt;/p&gt;&lt;h5&gt;Template (Hello.tt):&lt;/h5&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ template language="C#" #&amp;gt;&lt;br /&gt;&amp;lt;#@ output extension="txt" #&amp;gt;&lt;br /&gt;&amp;lt;# string name = "World"; #&amp;gt;&lt;br /&gt;Hello &amp;lt;#= name #&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Now I’m going to replace the variable with a function. The function will need to be in a &lt;em&gt;Class Feature Block&lt;/em&gt;. Just to speed things up, I’m going to use a Write call in a Statement Block to render the name. You can write text to the output using either Expression Blocks OR calls to Write().&lt;/p&gt;&lt;h5&gt;Template (Hello.tt):&lt;/h5&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ template language="C#" #&amp;gt;&lt;br /&gt;&amp;lt;#@ output extension="txt" #&amp;gt;&lt;br /&gt;Hello &amp;lt;# Write(GetName()); #&amp;gt;&lt;br /&gt;&amp;lt;#+ &lt;br /&gt;    string getName()&lt;br /&gt;    {&lt;br /&gt;        return "Word";&lt;br /&gt;    }&lt;br /&gt;#&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Now I want to move my function into an include file. I will create a new text file and call it "HelloFunctions.tt" I move the Class Feature Block into that file. Notice that there is no template directive. Also, you must save the include file BEFORE you save the template file.&lt;/p&gt;&lt;h5&gt;Include (HelloFunctions.tt)&lt;/h5&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#+ &lt;br /&gt;    string getName()&lt;br /&gt;    {&lt;br /&gt;        return "Word";&lt;br /&gt;    }&lt;br /&gt;#&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;h5&gt;Template (Hello.tt):&lt;/h5&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ template language="C#" #&amp;gt;&lt;br /&gt;&amp;lt;#@ include file="HelloFunctions.tt" #&amp;gt;&lt;br /&gt;&amp;lt;#@ output extension="txt" #&amp;gt;&lt;br /&gt;Hello &amp;lt;# Write(GetName()); #&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Now, for a brief look under the hood, I can show you the source code for the Text Transformation. Here I add "debug="true"" to the template file, save it and look in the temp directory (you can get your temp directory by typing "set temp" in a command prompt)&lt;/p&gt;&lt;h5&gt;Template (Hello.tt):&lt;/h5&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ template language="C#" #&amp;gt;&lt;br /&gt;&amp;lt;#@ include file="HelloFunctions.tt" #&amp;gt;&lt;br /&gt;&amp;lt;#@ output extension="txt" #&amp;gt;&lt;br /&gt;Hello &amp;lt;# &lt;br /&gt;// This comment will show up in .cs file&lt;br /&gt;Write(GetName()); &lt;br /&gt;#&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;h5&gt;Generated C# File (hcs3svyj.0.cs in this case)&lt;/h5&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;namespace Microsoft.VisualStudio.TextTemplatingBFD11436D0A4595408B06EA4E1B2A636 {&lt;br /&gt;    using System;&lt;br /&gt;    using Microsoft.VisualStudio.TextTemplating.VSHost;&lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;    #line 1 "c:\vsprojects\SimpleT4\Hello.tt"&lt;br /&gt;    public class GeneratedTextTransformation : &lt;br /&gt;        Microsoft.VisualStudio.TextTemplating.TextTransformation {&lt;br /&gt;        public override string TransformText() {&lt;br /&gt;            try {&lt;br /&gt;                this.Write("Hello ");&lt;br /&gt;&lt;br /&gt;                #line 4 "c:\vsprojects\SimpleT4\Hello.tt"&lt;br /&gt;&lt;br /&gt;// This comment will show up in .cs file&lt;br /&gt;Write(getName()); &lt;br /&gt;&lt;br /&gt;          &lt;br /&gt;                #line default&lt;br /&gt;                #line hidden&lt;br /&gt;            }&lt;br /&gt;            catch (System.Exception e) {&lt;br /&gt;                System.CodeDom.Compiler.CompilerError error = new &lt;br /&gt;                    System.CodeDom.Compiler.CompilerError();&lt;br /&gt;                error.ErrorText = e.ToString();&lt;br /&gt;                error.FileName = "c:\\vsprojects\\SimpleT4\\Hello.tt";&lt;br /&gt;                this.Errors.Add(error);&lt;br /&gt;            }&lt;br /&gt;            return this.GenerationEnvironment.ToString();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        #line 1 "c:\vsprojects\SimpleT4\HelloFunctions.tt"&lt;br /&gt;&lt;br /&gt; string getName()&lt;br /&gt; {&lt;br /&gt;  return "World";&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;        #line default&lt;br /&gt;        #line hidden&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    #line default&lt;br /&gt;    #line hidden&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;These source files have helped me understand what is going on behind the scenes. For example, I didn’t really get the difference between Statement Blocks (&amp;lt;# #&amp;gt;) and Class Feature Blocks (&amp;lt;#+ #&amp;gt;) until I saw the generated.&lt;p&gt;&lt;h2&gt;Afterthought&lt;/h2&gt;&lt;p&gt;This isn’t a transcription! Written and spoken communication is different by nature.&lt;/p&gt;&lt;p&gt;In the presentation I would change the value of "World" with different words ("Earth", "Boise", "Boise Code Camp", etc); In a presentation, this added proofiness that the templates were run and some lame humor to lighten the mood of the talk. In the written form, it would force me to repeat the Output after each sample (and make this longer).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-2589147717783558792?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/2589147717783558792/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=2589147717783558792' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2589147717783558792'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2589147717783558792'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/03/t4-template-tour-of-first-gear.html' title='T4 Template Tour of First Gear'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-9036873137757273152</id><published>2011-02-22T19:21:00.000-08:00</published><updated>2011-02-22T19:21:09.873-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='T4 Templates'/><category scheme='http://www.blogger.com/atom/ns#' term='Boise Code Camp'/><title type='text'>Boise Code Camp: Code Generation with T4 Templates</title><content type='html'>&lt;p&gt;I will be presenting at the Boise Code Camp on Saturday, February 26, 2011, 9:30 AM in the Farnsworth room in the BSU SUB!&lt;/p&gt;&lt;p&gt;T4 Templates (Text Template Transformation Toolkit) is the code generator built into Visual Studio. This session is a basic introduction to code generation in C# and .NET using T4 Templates in Visual Studio 2008. I will takes you on a journey starting from the basic "Hello World" template into a world where you can wrote reusable templates and interrogate SQL Server or an ADO.NET DataSet for table descriptions.&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.boisecodecamp.com/2011/Sessions/Details/59"&gt;Check it out!&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-9036873137757273152?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/9036873137757273152/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=9036873137757273152' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/9036873137757273152'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/9036873137757273152'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/02/boise-code-camp-code-generation-with-t4.html' title='Boise Code Camp: Code Generation with T4 Templates'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-8631451979249863917</id><published>2011-02-16T06:46:00.000-08:00</published><updated>2011-04-03T08:48:17.896-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='T4 Templates'/><title type='text'>Four Styles of T4 Template Code</title><content type='html'>&lt;p&gt;As I work through T4 templates as I get ready for Boise Code Camp, I’ve noticed a few styles of template code. Just for kicks, I am going to name them and give an example of each using a code generation that I blogged about early last year. Each template uses an include file that I present after the four samples. Each template relies on its style to the point of absurdity; I didn’t go as far as to eliminate all text blocks.&lt;/p&gt;&lt;p&gt;Real life templates are mixtures of these styles applied at appropriate places.&lt;/p&gt;&lt;p&gt;I adapted the code generation that I did &lt;a href="http://jrcs3.blogspot.com/2010/02/generate-stored-procedures-with-data.html"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;h2&gt;Embed&lt;/h2&gt;&lt;p&gt;This can also be called the Classic ASP style. All generated code is added as text blocks or expression blocks (&amp;lt;#= #&amp;gt;). The logic is contained in code blocks mixed in with the text and expression blocks. For simple logic, this style is probably OK. It can be difficult to read and maintain as the logic gets more complex. This is the most concrete approach.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ template language="C#v3.5" debug="true" #&amp;gt;&lt;br /&gt;&amp;lt;#@ output extension="sql" #&amp;gt;&lt;br /&gt;&amp;lt;#@ include file="TableDescriptionUtilCS.tt" #&amp;gt;&lt;br /&gt;&amp;lt;#&lt;br /&gt;    string ConnectionString = @"Data Source=localhost\SQLEXPRESS;" + &lt;br /&gt;        "Initial Catalog=Northwind;Integrated Security=True";&lt;br /&gt;    string Table = "Employees"; &lt;br /&gt;&lt;br /&gt;    TableDescriptionUtil tdu = new TableDescriptionUtil();&lt;br /&gt;    List&amp;lt;TableDescription&amp;gt; Columns = tdu.GetTableDescription(ConnectionString, Table); &lt;br /&gt;&lt;br /&gt;    int counter;&lt;br /&gt;#&amp;gt;&lt;br /&gt;CREATE PROCEDURE [dbo].[Insert&amp;lt;#=Table #&amp;gt;]&lt;br /&gt;&amp;lt;#&lt;br /&gt;    counter = 1;&lt;br /&gt;    foreach (TableDescription item in Columns)&lt;br /&gt;    {&lt;br /&gt;        #&amp;gt;    @&amp;lt;#= item.ColName #&amp;gt; &amp;lt;#= item.FullTypeName #&amp;gt;&amp;lt;#&lt;br /&gt;        if (item.Status == 0x80)&lt;br /&gt;            #&amp;gt; OUT&amp;lt;#&lt;br /&gt;        if (item.ColIsNullable != 0) &lt;br /&gt;            #&amp;gt; = NULL&amp;lt;#&lt;br /&gt;        if (counter &amp;lt; Columns.Count)&lt;br /&gt;            #&amp;gt;,&amp;lt;#&lt;br /&gt;        counter++;&lt;br /&gt;        #&amp;gt;&amp;lt;#= "\r\n"#&amp;gt;&amp;lt;#&lt;br /&gt;    }&lt;br /&gt;#&amp;gt;&lt;br /&gt;&lt;br /&gt;AS&lt;br /&gt;&lt;br /&gt;INSERT INTO [&amp;lt;#=Table #&amp;gt;] (&amp;lt;#&lt;br /&gt;    counter = 1;&lt;br /&gt;    foreach (TableDescription item in Columns)&lt;br /&gt;    {&lt;br /&gt;        if (item.Status != 0x80)&lt;br /&gt;        {&lt;br /&gt;            if (counter &amp;gt; 1)&lt;br /&gt;                #&amp;gt;, &amp;lt;#&lt;br /&gt;            if (counter % 5 == 0)&lt;br /&gt;                #&amp;gt;&amp;lt;#= "\r\n    " #&amp;gt;&amp;lt;#&lt;br /&gt;            counter++;&lt;br /&gt;            #&amp;gt;[&amp;lt;#= item.ColName #&amp;gt;]&amp;lt;#&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;#&amp;gt;)&lt;br /&gt;VALUES (&amp;lt;#&lt;br /&gt;    counter = 1;&lt;br /&gt;    foreach (TableDescription item in Columns)&lt;br /&gt;    {&lt;br /&gt;        if (item.Status != 0x80)&lt;br /&gt;        {&lt;br /&gt;            if (counter &amp;gt; 1)&lt;br /&gt;                #&amp;gt;, &amp;lt;#&lt;br /&gt;            if (counter % 5 == 0)&lt;br /&gt;                #&amp;gt;&amp;lt;#= "\r\n    " #&amp;gt;&amp;lt;#&lt;br /&gt;            counter++;&lt;br /&gt;            #&amp;gt;@&amp;lt;#= item.ColName #&amp;gt;&amp;lt;#&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;#&amp;gt;)&lt;br /&gt;&lt;br /&gt;SET @&amp;lt;#&lt;br /&gt;    foreach (TableDescription item in Columns)&lt;br /&gt;    {&lt;br /&gt;        if (item.Status == 0x80)&lt;br /&gt;        {&lt;br /&gt;            #&amp;gt;&amp;lt;#=item.ColName #&amp;gt;&amp;lt;#&lt;br /&gt;            break;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;#&amp;gt; = @@IDENTITY&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;Inline Write&lt;/h2&gt;&lt;p&gt;This style uses code blocks that contain Write(), WriteLine(), PushIndent(), PopIndent(), and other statements. &lt;/p&gt;&lt;p&gt;This approach is more abstract that Embed, it is easier for me to read than Embed or String Function.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ template language="C#v3.5" debug="true" #&amp;gt;&lt;br /&gt;&amp;lt;#@ output extension="sql" #&amp;gt;&lt;br /&gt;&amp;lt;#@ include file="TableDescriptionUtilCS.tt" #&amp;gt;&lt;br /&gt;&amp;lt;# &lt;br /&gt;    string ConnectionString = @"Data Source=localhost\SQLEXPRESS;" +&lt;br /&gt;        Initial Catalog=Northwind;Integrated Security=True";&lt;br /&gt;    string Table = "Employees";&lt;br /&gt;&lt;br /&gt;    TableDescriptionUtil tdu = new TableDescriptionUtil();&lt;br /&gt;    List&amp;lt;TableDescription&amp;gt; Columns = tdu.GetTableDescription(ConnectionString, Table);&lt;br /&gt;&lt;br /&gt;    int counter;&lt;br /&gt;#&amp;gt;&lt;br /&gt;CREATE PROCEDURE [dbo].[Insert&amp;lt;# Write(Table); #&amp;gt;]&lt;br /&gt;&amp;lt;#&lt;br /&gt;    PushIndent("    ");&lt;br /&gt;    counter = 1;&lt;br /&gt;    foreach (TableDescription item in Columns)&lt;br /&gt;    {&lt;br /&gt;        Write("@" + item.ColName + " " + item.FullTypeName);&lt;br /&gt;        if (item.Status == 0x80)&lt;br /&gt;            Write(" OUT");&lt;br /&gt;        if (item.ColIsNullable != 0)&lt;br /&gt;            Write(" = NULL");&lt;br /&gt;        if (counter &amp;lt; Columns.Count)&lt;br /&gt;            WriteLine(",");&lt;br /&gt;        counter++;&lt;br /&gt;    }&lt;br /&gt;    PopIndent();&lt;br /&gt;#&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;AS&lt;br /&gt;&lt;br /&gt;INSERT INTO [&amp;lt;# Write(Table); #&amp;gt;] (&amp;lt;#&lt;br /&gt;    PushIndent("    ");&lt;br /&gt;    counter = 1;&lt;br /&gt;    foreach (TableDescription item in Columns)&lt;br /&gt;    {&lt;br /&gt;        if (item.Status != 0x80)&lt;br /&gt;        {&lt;br /&gt;            if (counter &amp;gt; 1)&lt;br /&gt;                Write(", ");&lt;br /&gt;            if (counter % 5 == 0)&lt;br /&gt;                WriteLine(String.Empty);&lt;br /&gt;            counter++;&lt;br /&gt;            Write(string.Format("[{0}]", item.ColName));&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    PopIndent();&lt;br /&gt;#&amp;gt;)&lt;br /&gt;VALUES (&amp;lt;#&lt;br /&gt;    PushIndent("    ");&lt;br /&gt;    counter = 1;&lt;br /&gt;    foreach (TableDescription item in Columns)&lt;br /&gt;    {&lt;br /&gt;        if (item.Status != 0x80)&lt;br /&gt;        {&lt;br /&gt;            if (counter &amp;gt; 1)&lt;br /&gt;                Write(", ");&lt;br /&gt;            if (counter % 5 == 0)&lt;br /&gt;                WriteLine(string.Empty);&lt;br /&gt;            counter++;&lt;br /&gt;            Write(String.Format("@{0}", item.ColName));&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    PopIndent();&lt;br /&gt;#&amp;gt;)&lt;br /&gt;&lt;br /&gt;SET @&amp;lt;#&lt;br /&gt;    foreach (TableDescription item in Columns)&lt;br /&gt;    {&lt;br /&gt;        if (item.Status == 0x80)&lt;br /&gt;        {&lt;br /&gt;            Write(item.ColName);&lt;br /&gt;            break;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;#&amp;gt; = @@IDENTITY&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;String Function&lt;/h2&gt;&lt;p&gt;Here I call a function in an expression block that returns a bit of generated code as a string. The functions are in feature blocks (or include file, linked assemblies, etc.). &lt;/p&gt;&lt;p&gt;Since I did some primitive string based code gen for a number of years, I find myself relying on this approach. This approach can lead to code just as ugly as the Embed approach. This approach is good for adapting old fashioned code gen to T4. &lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ template language="C#v3.5" debug="true" #&amp;gt;&lt;br /&gt;&amp;lt;#@ output extension="sql" #&amp;gt;&lt;br /&gt;&amp;lt;#@ include file="TableDescriptionUtilCS.tt" #&amp;gt;&lt;br /&gt;&amp;lt;# &lt;br /&gt;    string ConnectionString = @"Data Source=localhost\SQLEXPRESS;" + &lt;br /&gt;        "Initial Catalog=Northwind;Integrated Security=True";&lt;br /&gt;    string Table = "Employees";&lt;br /&gt;&lt;br /&gt;    TableDescriptionUtil tdu = new TableDescriptionUtil();&lt;br /&gt;     List&amp;lt;TableDescription&amp;gt; Columns = tdu.GetTableDescription(ConnectionString, Table);&lt;br /&gt;&lt;br /&gt;     int counter;&lt;br /&gt;#&amp;gt;&lt;br /&gt;CREATE PROCEDURE [dbo].[Insert&amp;lt;#= getTableName(Table) #&amp;gt;]&lt;br /&gt;&amp;lt;#= getParameterList(Columns) #&amp;gt;&lt;br /&gt;&lt;br /&gt;AS&lt;br /&gt;&lt;br /&gt;INSERT INTO [&amp;lt;#= getTableName(Table) #&amp;gt;] (&amp;lt;#= getFieldNames(Columns) #&amp;gt;)&lt;br /&gt;VALUES (&amp;lt;#= getValueNames(Columns) #&amp;gt;)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SET @&amp;lt;#=getIdentityFieldName(Columns) #&amp;gt; = @@IDENTITY&lt;br /&gt;&amp;lt;#+&lt;br /&gt;    string getTableName(string table)&lt;br /&gt;    {&lt;br /&gt;        // Yes, this is hard core overkill&lt;br /&gt;        return table;&lt;br /&gt;    }&lt;br /&gt;    string getParameterList(List&amp;lt;TableDescription&amp;gt; columns)&lt;br /&gt;    {&lt;br /&gt;        string rVal = string.Empty;&lt;br /&gt;        int counter = 1;&lt;br /&gt;        foreach (TableDescription item in columns)&lt;br /&gt;        {&lt;br /&gt;           rVal += "    @" + item.ColName + " " + item.FullTypeName;&lt;br /&gt;           if (item.Status == 0x80)&lt;br /&gt;               rVal += " OUT";&lt;br /&gt;           if (item.ColIsNullable != 0)&lt;br /&gt;               rVal += " = NULL";&lt;br /&gt;           if (counter &amp;lt; columns.Count)&lt;br /&gt;               rVal += ",\r\n";&lt;br /&gt;           counter++;&lt;br /&gt;       }&lt;br /&gt;       return rVal;&lt;br /&gt;    }&lt;br /&gt;    string getFieldNames(List&amp;lt;TableDescription&amp;gt; columns)&lt;br /&gt;    {&lt;br /&gt;        string rVal = string.Empty;&lt;br /&gt;        int counter = 1;&lt;br /&gt;        foreach (TableDescription item in columns)&lt;br /&gt;        {&lt;br /&gt;            if (item.Status != 0x80)&lt;br /&gt;            {&lt;br /&gt;                if (counter &amp;gt; 1)&lt;br /&gt;                    rVal += ", ";&lt;br /&gt;                if (counter % 5 == 0)&lt;br /&gt;                    rVal += "\r\n    ";&lt;br /&gt;                counter++;&lt;br /&gt;                rVal += string.Format("[{0}]", item.ColName);&lt;br /&gt;           }&lt;br /&gt;        }&lt;br /&gt;        return rVal;&lt;br /&gt;    }&lt;br /&gt;    string getValueNames(List&amp;lt;TableDescription&amp;gt; columns)&lt;br /&gt;    {&lt;br /&gt;        string rVal = string.Empty;&lt;br /&gt;        int counter = 1;&lt;br /&gt;        foreach (TableDescription item in columns)&lt;br /&gt;        {&lt;br /&gt;        if (item.Status != 0x80)&lt;br /&gt;        {&lt;br /&gt;            if (counter &amp;gt; 1)&lt;br /&gt;                rVal += ", ";&lt;br /&gt;            if (counter % 5 == 0)&lt;br /&gt;                rVal += "\r\n    ";&lt;br /&gt;            counter++;&lt;br /&gt;            rVal += string.Format("@{0}", item.ColName);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    return rVal;&lt;br /&gt;    }&lt;br /&gt;    string getIdentityFieldName(List&amp;lt;TableDescription&amp;gt; columns)&lt;br /&gt;    {&lt;br /&gt;        string rVal = string.Empty;&lt;br /&gt;        foreach (TableDescription item in columns)&lt;br /&gt;        {&lt;br /&gt;            if (item.Status == 0x80)&lt;br /&gt;            {&lt;br /&gt;                rVal =item.ColName;&lt;br /&gt;                break;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        return rVal;&lt;br /&gt;    }&lt;br /&gt;#&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;Write Function&lt;/h2&gt;&lt;p&gt;Here I call a function to generate code a block of code with Write functions.&lt;/p&gt;&lt;p&gt;Unlike the String Function approach, the code generation is relying on a side effect of the function, so this approach isn’t functional.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ template language="C#v3.5" debug="true" #&amp;gt;&lt;br /&gt;&amp;lt;#@ output extension="sql" #&amp;gt;&lt;br /&gt;&amp;lt;#@ include file="TableDescriptionUtilCS.tt" #&amp;gt;&lt;br /&gt;&amp;lt;# &lt;br /&gt;    string ConnectionString = @"Data Source=localhost\SQLEXPRESS;" + &lt;br /&gt;        "Initial Catalog=Northwind;Integrated Security=True";&lt;br /&gt;    string Table = "Employees";&lt;br /&gt;&lt;br /&gt;    TableDescriptionUtil tdu = new TableDescriptionUtil();&lt;br /&gt;    List&amp;lt;TableDescription&amp;gt; Columns = tdu.GetTableDescription(ConnectionString, Table);&lt;br /&gt;&lt;br /&gt;    int counter;&lt;br /&gt;#&amp;gt;&lt;br /&gt;CREATE PROCEDURE [dbo].[Insert&amp;lt;# writeTableName(Table); #&amp;gt;]&lt;br /&gt;&amp;lt;# writeParameterList(Columns); #&amp;gt;&lt;br /&gt;&lt;br /&gt;AS&lt;br /&gt;&lt;br /&gt;INSERT INTO [&amp;lt;# writeTableName(Table); #&amp;gt;] (&amp;lt;# writeFieldNames(Columns); #&amp;gt;)&lt;br /&gt;VALUES (&amp;lt;# writeValueNames(Columns); #&amp;gt;)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SET @&amp;lt;# writeIdentityFieldName(Columns); #&amp;gt;  = @@IDENTITY&lt;br /&gt;&amp;lt;#+&lt;br /&gt;    void writeTableName(string table)&lt;br /&gt;    {&lt;br /&gt;        Write(table);&lt;br /&gt;    }&lt;br /&gt;    void  writeParameterList(List&amp;lt;TableDescription&amp;gt; columns)&lt;br /&gt;    {&lt;br /&gt;        PushIndent("    ");&lt;br /&gt;        int counter = 1;&lt;br /&gt;        foreach (TableDescription item in columns)&lt;br /&gt;        {&lt;br /&gt;            Write("@" + item.ColName + " " + item.FullTypeName);&lt;br /&gt;            if (item.Status == 0x80)&lt;br /&gt;                Write(" OUT");&lt;br /&gt;            if (item.ColIsNullable != 0)&lt;br /&gt;                Write(" = NULL");&lt;br /&gt;            if (counter &amp;lt; columns.Count)&lt;br /&gt;                WriteLine(",");&lt;br /&gt;            counter++;&lt;br /&gt;        }&lt;br /&gt;        PopIndent();&lt;br /&gt;    }&lt;br /&gt;    void writeFieldNames(List&amp;lt;TableDescription&amp;gt; columns)&lt;br /&gt;    {&lt;br /&gt;         PushIndent("    ");&lt;br /&gt;         int counter = 1;&lt;br /&gt;         foreach (TableDescription item in columns)&lt;br /&gt;         {&lt;br /&gt;             if (item.Status != 0x80)&lt;br /&gt;             {&lt;br /&gt;                 if (counter &amp;gt; 1)&lt;br /&gt;                     Write(", ");&lt;br /&gt;                 if (counter % 5 == 0)&lt;br /&gt;                     WriteLine(String.Empty);&lt;br /&gt;                 counter++;&lt;br /&gt;                 Write(string.Format("[{0}]", item.ColName));&lt;br /&gt;             }&lt;br /&gt;         }&lt;br /&gt;         PopIndent();&lt;br /&gt;    }&lt;br /&gt;    void writeValueNames(List&amp;lt;TableDescription&amp;gt; columns)&lt;br /&gt;    {&lt;br /&gt;        PushIndent("    ");&lt;br /&gt;        int counter = 1;&lt;br /&gt;        foreach (TableDescription item in columns)&lt;br /&gt;        {&lt;br /&gt;            if (item.Status != 0x80)&lt;br /&gt;            {&lt;br /&gt;                if (counter &amp;gt; 1)&lt;br /&gt;                    Write(", ");&lt;br /&gt;                if (counter % 5 == 0)&lt;br /&gt;                    WriteLine(string.Empty);&lt;br /&gt;                counter++;&lt;br /&gt;                Write(String.Format("@{0}", item.ColName));&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        PopIndent();&lt;br /&gt;    }&lt;br /&gt;    void writeIdentityFieldName(List&amp;lt;TableDescription&amp;gt; columns)&lt;br /&gt;    {&lt;br /&gt;        foreach (TableDescription item in columns)&lt;br /&gt;        {&lt;br /&gt;            if (item.Status == 0x80)&lt;br /&gt;            {&lt;br /&gt;                Write(item.ColName);&lt;br /&gt;                break;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;#&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;Include File: TableDescriptionUtil.tt&lt;/h2&gt;&lt;p&gt;I included this file in all the examples above.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ assembly name="System.Data.dll" #&amp;gt;&lt;br /&gt;&amp;lt;#@ import namespace="System.Data.SqlClient" #&amp;gt;&lt;br /&gt;&amp;lt;#@ import namespace="System.Collections.Generic" #&amp;gt;&lt;br /&gt;&amp;lt;#@ import namespace="Microsoft.VisualStudio.TextTemplating" #&amp;gt;&lt;br /&gt;&amp;lt;#+&lt;br /&gt;public class TableDescriptionUtil : TextTransformation&lt;br /&gt;{&lt;br /&gt;    /// &amp;lt;remarks&amp;gt;&lt;br /&gt;    /// I don't actually call this, but it is necessary for T4 Templates to work&lt;br /&gt;    /// &amp;lt;/remarks&amp;gt;&lt;br /&gt;    public override string TransformText()&lt;br /&gt;    {&lt;br /&gt;        return "";&lt;br /&gt;    }&lt;br /&gt;    /// &amp;lt;summary&amp;gt;&lt;br /&gt;    /// Gets a DataReader containing selected column information for all of the&lt;br /&gt;    /// columns in the indecated table from SQL Server System Tables&lt;br /&gt;    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;    /// &amp;lt;param name="tableName"&amp;gt;Get information on THIS table&amp;lt;/param&amp;gt;&lt;br /&gt;    /// &amp;lt;param name="conn"&amp;gt;An existing open connection to be used &amp;lt;/param&amp;gt;&lt;br /&gt;    /// &amp;lt;returns&amp;gt;A DataReader pointing to the results&amp;lt;/returns&amp;gt;&lt;br /&gt;    private SqlDataReader GetTableDefReader(string tableName , SqlConnection conn )&lt;br /&gt;    {&lt;br /&gt;        SqlDataReader reader;// = new SqlDataReader();&lt;br /&gt;        string getDataForTable = &lt;br /&gt;             " SELECT c.name AS col_name, " +&lt;br /&gt;             "   t.name AS type_name, " +&lt;br /&gt;             "   CAST(c.length AS INT) AS length, " +&lt;br /&gt;             "   c.isnullable, " +&lt;br /&gt;             "   CAST(c.status AS INT) AS status " +&lt;br /&gt;             " FROM " +&lt;br /&gt;             "  sysObjects o " +&lt;br /&gt;             "  JOIN sysColumns c ON c.id = o.id " +&lt;br /&gt;             "  JOIN systypes t on c.xtype = t.xtype AND t.status = 0 " +&lt;br /&gt;             " WHERE o.name = @tableName " +&lt;br /&gt;             " ORDER BY c.colid ";&lt;br /&gt;        using (var cmd = new SqlCommand(getDataForTable, conn))&lt;br /&gt;        {&lt;br /&gt;            cmd.Parameters.AddWithValue("@tableName", tableName);&lt;br /&gt;            reader = cmd.ExecuteReader();&lt;br /&gt;        }&lt;br /&gt;        return reader;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /// &amp;lt;summary&amp;gt;&lt;br /&gt;    /// Gets a List of column descriptions for a given table&lt;br /&gt;    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;    /// &amp;lt;param name="ConnectionString"&amp;gt;Connection string to the database&amp;lt;/param&amp;gt;&lt;br /&gt;    /// &amp;lt;param name="Table"&amp;gt;The name of the table to describe&amp;lt;/param&amp;gt;&lt;br /&gt;    /// &amp;lt;returns&amp;gt;A list of column descriptions&amp;lt;/returns&amp;gt;&lt;br /&gt;    public List&amp;lt;TableDescription&amp;gt; GetTableDescription(string ConnectionString, &lt;br /&gt;         string Table) &lt;br /&gt;    {&lt;br /&gt;        SqlDataReader reader;&lt;br /&gt;        List&amp;lt;TableDescription&amp;gt; Columns = new List&amp;lt;TableDescription&amp;gt;();&lt;br /&gt;        using (var conn = new SqlConnection(ConnectionString))&lt;br /&gt;        {&lt;br /&gt;            conn.Open();&lt;br /&gt;            reader = GetTableDefReader(Table, conn);&lt;br /&gt;            while (reader.Read())&lt;br /&gt;            {&lt;br /&gt;                TableDescription Column = new TableDescription();&lt;br /&gt;                Column.ColName = reader.GetString(0);&lt;br /&gt;                Column.TypeName = reader.GetString(1);&lt;br /&gt;                Column.ColLength = reader.GetInt32(2);&lt;br /&gt;                Column.ColIsNullable = reader.GetInt32(3);&lt;br /&gt;                Column.Status = reader.GetInt32(4);&lt;br /&gt;                Column.FullTypeName = GetTypeName(Column.TypeName, Column.ColLength);&lt;br /&gt;                Columns.Add(Column);&lt;br /&gt;            }&lt;br /&gt;            conn.Close();&lt;br /&gt;        }&lt;br /&gt;        return Columns;&lt;br /&gt;    }&lt;br /&gt;    /// &amp;lt;summary&amp;gt;&lt;br /&gt;    /// Gets the TypeName as it should appear in a SP Parameter List&lt;br /&gt;    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;    /// &amp;lt;param name="TypeName"&amp;gt;&amp;lt;/param&amp;gt;&lt;br /&gt;    /// &amp;lt;param name="ColLength"&amp;gt;&amp;lt;/param&amp;gt;&lt;br /&gt;    /// &amp;lt;returns&amp;gt;The processed Type Name as a string&amp;lt;/returns&amp;gt;&lt;br /&gt;    private string GetTypeName(string typeName , int ColLength )&lt;br /&gt;    {&lt;br /&gt;        switch (typeName.ToLower())&lt;br /&gt;        {&lt;br /&gt;        case "varchar":&lt;br /&gt;        case "nvarchar":&lt;br /&gt;            string lenString  = ColLength.ToString();&lt;br /&gt;            if (ColLength == -1 )&lt;br /&gt;                lenString = "MAX";&lt;br /&gt;            return string.Format("{0}({1})", typeName, lenString);&lt;br /&gt;        default:&lt;br /&gt;            return typeName;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;public class TableDescription&lt;br /&gt;{&lt;br /&gt;    public string ColName {get; set;}&lt;br /&gt;    public string TypeName {get; set;}&lt;br /&gt;    public string FullTypeName {get; set;}&lt;br /&gt;    public int ColLength {get; set;}&lt;br /&gt;    public int Status {get; set;}&lt;br /&gt;    public int ColIsNullable {get; set;}&lt;br /&gt;}&lt;br /&gt;#&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-8631451979249863917?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/8631451979249863917/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=8631451979249863917' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/8631451979249863917'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/8631451979249863917'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/02/four-styles-of-t4-template-code.html' title='Four Styles of T4 Template Code'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-8770499688898216113</id><published>2011-02-02T06:41:00.000-08:00</published><updated>2012-02-02T05:21:51.847-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Groundhog Day'/><title type='text'>Happy Groundhog Day!</title><content type='html'>Traditionally we have pork sausage for dinner. I leave it as an exercise to the reader to work out the bad pun.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-8770499688898216113?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/8770499688898216113/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=8770499688898216113' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/8770499688898216113'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/8770499688898216113'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/02/happy-groundhog-day.html' title='Happy Groundhog Day!'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-4749631307229793373</id><published>2011-01-23T08:41:00.000-08:00</published><updated>2011-03-31T20:57:16.723-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='T4 Templates'/><title type='text'>Referencing Assemblies: T4 Gotcha</title><content type='html'>&lt;p&gt;When I run T4 Templates through Visual Studio 2008, I don't have to give the full path to reference GAC assemblies:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ assembly name="System.Data.dll" #&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;But when I run the template in my own executable using Microsoft.VisualStudio.TextTemplating.Engine, I have problems.&lt;/p&gt;&lt;p&gt;If the Template code is in VB.NET, I get:&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;vbc : Command line (0,0) : error BC2006: Compiling transformation: option 'r' requires ': &amp;lt;file_list&amp;gt;'&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;If the Template code is in C#, I get:&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;c:\Users\jacks\AppData\Local\Temp\rnftuopt.0.cs(3,18) : error CS0234: Compiling transformation: The type or namespace name 'Data' does not exist in the namespace 'System' (are you missing an assembly reference?)&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;To fix this, I referenced the full path of the assembly.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ assembly name="C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Data.dll" #&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;NOTE: This doesn't seam to apply to non-GAC assemblies; I have noticed that I don't have give the full path of my own assemblies as long as they are in the same folder as my executable.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-4749631307229793373?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/4749631307229793373/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=4749631307229793373' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/4749631307229793373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/4749631307229793373'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/01/referencing-assemblies-t4-gotcha.html' title='Referencing Assemblies: T4 Gotcha'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-5615830179300987743</id><published>2011-01-14T05:53:00.000-08:00</published><updated>2011-01-14T06:31:22.813-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='A T and T'/><category scheme='http://www.blogger.com/atom/ns#' term='iPhone'/><category scheme='http://www.blogger.com/atom/ns#' term='Verizon'/><title type='text'>Fulfilled my contract with AT&amp;T</title><content type='html'>&lt;p&gt;Just over a two years ago, I bought an iPhone 3G (no S).&lt;/p&gt;&lt;p&gt;In Spokane, I haven't have any problems AT&amp;amp;T. But Spokane is the first place named in AT&amp;amp;T's &lt;a href="http://www.youtube.com/watch?v=vJEIzL0jpcc"&gt;Postcard Commercial&lt;/a&gt; in 2009, so AT&amp;amp;T knows that we get better than average service here in Spocompton.&lt;/p&gt;&lt;p&gt;If I was to stay in Spokane, I would probably be safe getting an upgrade from AT&amp;amp;T. The trouble is that I am working month to month as a temp and I don't know where I will be working if/when my current contract runs out.&lt;/p&gt;&lt;p&gt;I've hear horror stories of bad service in real cities like New York or Chicago. And Verizon will offer the iPhone 4 next month; some say that AT&amp;amp;T's problems are caused by the popularity of the iPhone and Verizon will degrade too.&lt;/p&gt;&lt;p&gt;I think I will stay with my antique phone for awhile.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-5615830179300987743?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/5615830179300987743/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=5615830179300987743' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5615830179300987743'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5615830179300987743'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/01/fulfilled-my-contract-with-at.html' title='Fulfilled my contract with AT&amp;T'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-4686536078973080822</id><published>2011-01-05T05:44:00.000-08:00</published><updated>2011-09-12T05:55:26.564-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='FTP'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Running FTP.EXE from C#</title><content type='html'>&lt;p&gt;&lt;strong&gt;NOTE: Ultimately, I didn't go with this solution.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Since I need to log on to various FTP servers with various security configurations and FTP.EXE seams to figure out these configurations and the free FTP libraries I’ve played with can’t I have decided to wrap FTP.EXE with C#.&lt;/p&gt;&lt;h3&gt;Telling it what to do&lt;/h3&gt;&lt;p&gt;I wanted to avoid sending my commands to FTP.EXE via command files because I would have to dynamically write text files and make sure that they are secure. System.Diagnostics.Process allows me to send commands to its StandardInput stream, but I can’t figure out how to make it accept passwords. To solve these problems, I log in using command files (which I can secure and only allow myself and the program to see, and then write the rest of the commands to the StandardInput stream.&lt;/p&gt;&lt;h3&gt;The Command File&lt;/h3&gt;&lt;p&gt;The command file needs to reside in a directory with no spaces and the file needs to be saved using ANSI encoding. Here I open a server and login, the rest is up to the commands that I send to the stream.&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;open localhost&lt;br /&gt;username&lt;br /&gt;password&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h3&gt;Sample Application&lt;/h3&gt;&lt;p&gt;This simple console application demonstrates using the command file to log in and StandardInput to send a List command (and Quit). &lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Diagnostics;&lt;br /&gt;using System.IO;&lt;br /&gt;&lt;br /&gt;namespace DemoFtp&lt;br /&gt;{&lt;br /&gt;    class Program&lt;br /&gt;    {&lt;br /&gt;        private const string FTP_EXE_LOCATION = @"C:\Windows\System32\ftp.exe";&lt;br /&gt;        private const string DEFAULT_COMMAND_FILE_LOCATION = @"C:\temp\localhost.txt";&lt;br /&gt;&lt;br /&gt;        static void Main(string[] args)&lt;br /&gt;        {&lt;br /&gt;            try&lt;br /&gt;            {&lt;br /&gt;                string commandFileLocation = getCommandFileLocation(args);&lt;br /&gt;&lt;br /&gt;                var commands = new List&amp;lt;string&amp;gt;();&lt;br /&gt;                commands.Add("ls -la");&lt;br /&gt;                commands.Add("quit");   // Don't forget to log out!&lt;br /&gt;                string output = RunWithResponses(&lt;br /&gt;                    FTP_EXE_LOCATION, &lt;br /&gt;                    string.Format("-s:{0}", commandFileLocation), &lt;br /&gt;                    commands);&lt;br /&gt;                Console.WriteLine(output);&lt;br /&gt;            }&lt;br /&gt;            catch (Exception ex)&lt;br /&gt;            {&lt;br /&gt;                Console.WriteLine(ex.Message);&lt;br /&gt;            }&lt;br /&gt;            Console.ReadKey();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static string getCommandFileLocation(string[] args)&lt;br /&gt;        {&lt;br /&gt;            string commandFileLocation;&lt;br /&gt;            if (args.Length &amp;gt; 0)&lt;br /&gt;                commandFileLocation = args[0];&lt;br /&gt;            else&lt;br /&gt;                commandFileLocation = DEFAULT_COMMAND_FILE_LOCATION;&lt;br /&gt;            return commandFileLocation;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public static string RunWithResponses(string exeName, string argsLine,&lt;br /&gt;            List&amp;lt;string&amp;gt; commands)&lt;br /&gt;        {&lt;br /&gt;            StreamReader outputStream = StreamReader.Null;&lt;br /&gt;            StreamReader errorStream = StreamReader.Null;&lt;br /&gt;            StreamWriter inputStream = StreamWriter.Null;&lt;br /&gt;            string output = string.Empty;&lt;br /&gt;            try&lt;br /&gt;            {&lt;br /&gt;                // Setup the process&lt;br /&gt;                Process newProcess = new Process();&lt;br /&gt;                newProcess.StartInfo.FileName = exeName;&lt;br /&gt;                newProcess.StartInfo.Arguments = argsLine;&lt;br /&gt;                newProcess.StartInfo.UseShellExecute = false;&lt;br /&gt;                newProcess.StartInfo.CreateNoWindow = true;&lt;br /&gt;                newProcess.StartInfo.RedirectStandardInput = true;&lt;br /&gt;                newProcess.StartInfo.RedirectStandardOutput = true;&lt;br /&gt;                newProcess.StartInfo.RedirectStandardError = true;&lt;br /&gt;                newProcess.Start();&lt;br /&gt;                inputStream = newProcess.StandardInput;&lt;br /&gt;                outputStream = newProcess.StandardOutput;&lt;br /&gt;                errorStream = newProcess.StandardError;&lt;br /&gt;                inputStream.AutoFlush = true;&lt;br /&gt;&lt;br /&gt;                // Issue My commands&lt;br /&gt;                foreach (string command in commands)&lt;br /&gt;                {&lt;br /&gt;                    inputStream.WriteLine(command);&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                // Get the rsults and wait for it to end&lt;br /&gt;                output = outputStream.ReadToEnd();&lt;br /&gt;                newProcess.WaitForExit();&lt;br /&gt;            }&lt;br /&gt;            finally&lt;br /&gt;            {&lt;br /&gt;                // Clean up&lt;br /&gt;                if (outputStream != StreamReader.Null)&lt;br /&gt;                    outputStream.Close();&lt;br /&gt;                if (errorStream != StreamReader.Null)&lt;br /&gt;                    errorStream.Close();&lt;br /&gt;                if (inputStream != StreamWriter.Null)&lt;br /&gt;                    inputStream.Close();&lt;br /&gt;            }&lt;br /&gt;            return output;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-4686536078973080822?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/4686536078973080822/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=4686536078973080822' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/4686536078973080822'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/4686536078973080822'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2011/01/running-ftpexe-from-c.html' title='Running FTP.EXE from C#'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-393313406226902927</id><published>2010-12-30T21:41:00.000-08:00</published><updated>2011-01-07T06:27:37.504-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NFL'/><category scheme='http://www.blogger.com/atom/ns#' term='Sports'/><category scheme='http://www.blogger.com/atom/ns#' term='Seahawks'/><category scheme='http://www.blogger.com/atom/ns#' term='Playoffs'/><category scheme='http://www.blogger.com/atom/ns#' term='Non-Technical'/><category scheme='http://www.blogger.com/atom/ns#' term='Football'/><title type='text'>The Seahawks and the Playoffs</title><content type='html'>&lt;p&gt;If the Seattle Seahawks win their football game against the Rams early next year, a team with a losing record will make the NFL playoffs!&lt;/p&gt;&lt;p&gt;If I were the King of Football (or any other sport), I’d make a rule that a team would have to win at least as many games as they lose to make the playoffs. &lt;/p&gt;&lt;p&gt;If a division winner had a losing record, that playoff position would go to an additional wild card team. The New York Giants and Tampa Bay (both have 9-6 records and would lose tie breakers to Green Bay) may be home watching the Seahawks. Under my scheme New Orleans could host a game. &lt;/p&gt;&lt;p&gt;In College Football, a team must have an even record to qualify for a bowl game. There was a big deal around here about the Washington Huskies having to win the Apple Cup in Pullman to get to 6-6 to qualify for a bowl.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-393313406226902927?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/393313406226902927/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=393313406226902927' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/393313406226902927'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/393313406226902927'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2010/12/seahawks-and-playoffs-if-seattle.html' title='The Seahawks and the Playoffs'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-2697280901768966100</id><published>2010-12-19T16:56:00.000-08:00</published><updated>2011-03-31T21:00:18.150-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='T4 Templates'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Generation'/><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='DataSet'/><title type='text'>Generating a Nullable ADO.NET DataSet Wrapper</title><content type='html'>&lt;h2&gt;Part 4: The Template and putting it all together&lt;/h2&gt;So, I have my target code, my DataSet describer and some T4 template tools (including the ITextTemplatingEngineHost class I took from MSDN), but I haven’t generated any DataSet Wrapper code! It is Christmas time, but that’s still a lame excuse.&lt;h4&gt;Running the Template&lt;/h4&gt;In Part 3, I created a class to pass parameters to a T4 Template and an overly simple template that echoed the parameters to the generated document. Here I’m using the same basic from the Test Console Application, but I am referencing a template that will generate the DataSet Wrapper and passing the appropriate parameters to generate the wrapper I want. This code use a DataSet in an assembly.&lt;pre class="prettyprint"&gt;&lt;br /&gt;// Set up some parameters:&lt;br /&gt;var parms = new TTCommucator.GetParams("setting.txt");&lt;br /&gt;parms.CurrentParameters.Add("DsSource", "Assembly");&lt;br /&gt;parms.CurrentParameters.Add("AssembyPath", @"C:\GeneratorProject\MyAssembly.dll");&lt;br /&gt;parms.CurrentParameters.Add("DataSetName", "MyDS");&lt;br /&gt;parms.CurrentParameters.Add("FileNameSpace", "MyAssembly.DataSets");&lt;br /&gt;parms.CurrentParameters.Add("DsNameSpace", "NewProject.DataSetWrappers");&lt;br /&gt;parms.Save();&lt;br /&gt;&lt;br /&gt;// Set the Template File&lt;br /&gt;string templateFileName = "DataSetX.tt";&lt;br /&gt;&lt;br /&gt;// Set up host and engine&lt;br /&gt;CustomCmdLineHost host = new CustomCmdLineHost();&lt;br /&gt;Engine engine = new Engine();&lt;br /&gt;host.TemplateFileValue = templateFileName;&lt;br /&gt;&lt;br /&gt;//Read the text template.&lt;br /&gt;string input = File.ReadAllText(templateFileName);&lt;br /&gt;&lt;br /&gt;//Transform the text template.&lt;br /&gt;string result = engine.ProcessTemplate(input, host);&lt;br /&gt;// Save logic would be here…&lt;br /&gt;&lt;/pre&gt;&lt;h4&gt;Notes on the Template&lt;/h4&gt;In the template, I am using TTCommucator.GetParams to read the parameter I’ve written in code above; same as in Part 3. I use the DataSetDesciber.ReflectDataSet.DataSetDef from Part 2 to get the tables, columns, types, etc. from the target DataSet. The generated code will be different from the target code in Part 1. For example:&lt;ul&gt;&lt;li&gt;I’m using .NET type names (like System.Int32) instead of C# type names (like int). That’s what Type.ToString() returns and I see no reason to convert it just to look pretty.&lt;/li&gt;&lt;li&gt;I’m not using Nullable&lt;t&gt;’s ? operator. No good reason, it just seems more consistent with the .NET types in code (I don’t see System.Int32? in code all that often).&lt;/t&gt;&lt;/li&gt;&lt;/ul&gt;The purpose of the target code is to provide a starting point for generation. The code will change as a result of what you learn in writing the generation and testing. In the Template I am generating C# code, but the template code is in VB.NET; it is easier for me to keep straight which is which.&lt;h4&gt;The Template&lt;/h4&gt;&lt;pre class="prettyprint lang-vb"&gt;&lt;br /&gt;&amp;lt;#@ template debug="true" hostspecific="true" language="VB" #&amp;gt;&lt;br /&gt;&amp;lt;#@ output extension=".cs" #&amp;gt;&lt;br /&gt;&amp;lt;#@ assembly name="C:\GeneratorProject\TTCommucator.dll" #&amp;gt;&lt;br /&gt;&amp;lt;#@ assembly name="C:\GeneratorProject\DataSetDesciber.dll" #&amp;gt;&lt;br /&gt;&amp;lt;#@ import namespace="DataSetDesciber.ReflectDataSet" #&amp;gt;&lt;br /&gt;&amp;lt;#@ import namespace="TTCommucator" #&amp;gt;&lt;br /&gt;&amp;lt;# &lt;br /&gt;    ' Load the Parameter object&lt;br /&gt;    Dim parms As new GetParams(Host.ResolvePath("setting.txt"))&lt;br /&gt;    parms.Load()&lt;br /&gt;&lt;br /&gt;    ' Get the namespace&lt;br /&gt;    Dim FileNameSpace As String = parms.CurrentParameters.Item("FileNameSpace")&lt;br /&gt;    Dim DsNameSpace As String = parms.CurrentParameters.Item("DsNameSpace")&lt;br /&gt;&lt;br /&gt;    ' a description of the DataSet to be wrapped&lt;br /&gt;    Dim refx As DataSetDef = GetDsDescripter(parms)&lt;br /&gt;#&amp;gt;&lt;br /&gt;// Generated with DataSetWrapper Version 1&lt;br /&gt;using System;&lt;br /&gt;using System.Collections;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using &amp;lt;#=DsNameSpace #&amp;gt;;&lt;br /&gt;&lt;br /&gt;namespace &amp;lt;#=FileNameSpace #&amp;gt;&lt;br /&gt;{&lt;br /&gt;    public class &amp;lt;#=refx.DataSetName #&amp;gt;X&lt;br /&gt;    {&lt;br /&gt;        private &amp;lt;#=refx.DataSetName #&amp;gt; _ds;&lt;br /&gt;        public &amp;lt;#=refx.DataSetName #&amp;gt;X(&amp;lt;#=refx.DataSetName #&amp;gt; ds)&lt;br /&gt;        {&lt;br /&gt;            _ds = ds;&lt;br /&gt;        }&lt;br /&gt;&amp;lt;#For Each table As TableDef In refx.TableDefList #&amp;gt;&lt;br /&gt;        public &amp;lt;#=table.TableName#&amp;gt;DataTableX &amp;lt;#=table.TableName#&amp;gt;&lt;br /&gt;        {&lt;br /&gt;            get { return new &amp;lt;#=table.TableName#&amp;gt;DataTableX(_ds.&amp;lt;#=table.TableName#&amp;gt;); }&lt;br /&gt;            //set { _ds.&amp;lt;#=table.TableName#&amp;gt; = value; }&lt;br /&gt;        }&lt;br /&gt;&amp;lt;#Next#&amp;gt;&lt;br /&gt;        public &amp;lt;#=refx.DataSetName #&amp;gt; DataSet&lt;br /&gt;        {&lt;br /&gt;            get { return _ds; }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&amp;lt;#For Each table As TableDef In refx.TableDefList #&amp;gt;&lt;br /&gt;    public class &amp;lt;#=table.TableName#&amp;gt;DataTableX: IEnumerable&amp;lt;&amp;lt;#=table.TableName#&amp;gt;RowX&amp;gt;&lt;br /&gt;    {&lt;br /&gt;        private &amp;lt;#=refx.DataSetName #&amp;gt;.&amp;lt;#=table.TableName#&amp;gt;DataTable _theTable;&lt;br /&gt;        public &amp;lt;#=table.TableName#&amp;gt;DataTableX(&amp;lt;#=refx.DataSetName #&amp;gt;.&amp;lt;#=table.TableName#&amp;gt;DataTable table)&lt;br /&gt;        {&lt;br /&gt;            _theTable = table;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public &amp;lt;#=refx.DataSetName #&amp;gt;.&amp;lt;#=table.TableName#&amp;gt;DataTable Table&lt;br /&gt;        {&lt;br /&gt;            get { return _theTable; }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        #region IEnumerable&amp;lt;&amp;lt;#=table.TableName#&amp;gt;RowX&amp;gt; Members&lt;br /&gt;&lt;br /&gt;        public IEnumerator&amp;lt;&amp;lt;#=table.TableName#&amp;gt;RowX&amp;gt; GetEnumerator()&lt;br /&gt;        {&lt;br /&gt;            //return new &amp;lt;#=table.TableName#&amp;gt;RowXEnum(_rows);&lt;br /&gt;            return new &amp;lt;#=table.TableName#&amp;gt;TableEnum(_theTable);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        #endregion&lt;br /&gt;&lt;br /&gt;        #region IEnumerable Members&lt;br /&gt;&lt;br /&gt;        IEnumerator IEnumerable.GetEnumerator()&lt;br /&gt;        {&lt;br /&gt;            return (IEnumerator)this;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        #endregion&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public class &amp;lt;#=table.TableName#&amp;gt;TableEnum : IEnumerator&amp;lt;&amp;lt;#=table.TableName#&amp;gt;RowX&amp;gt;&lt;br /&gt;    {&lt;br /&gt;        private &amp;lt;#=refx.DataSetName #&amp;gt;.&amp;lt;#=table.TableName#&amp;gt;DataTable _collection;&lt;br /&gt;        private int curIndex;&lt;br /&gt;        private &amp;lt;#=table.TableName#&amp;gt;RowX curBox;&lt;br /&gt;&lt;br /&gt;        public &amp;lt;#=table.TableName#&amp;gt;TableEnum(&amp;lt;#=refx.DataSetName #&amp;gt;.&amp;lt;#=table.TableName#&amp;gt;DataTable collection)&lt;br /&gt;        {&lt;br /&gt;            _collection = collection;&lt;br /&gt;            curIndex = -1;&lt;br /&gt;            curBox = default(&amp;lt;#=table.TableName#&amp;gt;RowX);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public bool MoveNext()&lt;br /&gt;        {&lt;br /&gt;            //Avoids going beyond the end of the collection.&lt;br /&gt;            if (++curIndex &amp;gt;= _collection.Count)&lt;br /&gt;                return false;&lt;br /&gt;            else&lt;br /&gt;                // Set current &amp;lt;#=table.TableName#&amp;gt;RowX to next item in collection.&lt;br /&gt;                curBox = new &amp;lt;#=table.TableName#&amp;gt;RowX((&amp;lt;#=refx.DataSetName #&amp;gt;.&amp;lt;#=table.TableName#&amp;gt;Row)_collection.Rows[curIndex]);&lt;br /&gt;            return true;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void Reset() { curIndex = -1; }&lt;br /&gt;&lt;br /&gt;        public void Dispose() { }&lt;br /&gt;&lt;br /&gt;        public &amp;lt;#=table.TableName#&amp;gt;RowX Current&lt;br /&gt;        {&lt;br /&gt;            get { return curBox; }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        object IEnumerator.Current&lt;br /&gt;        {&lt;br /&gt;            get { return curBox; }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public class &amp;lt;#=table.TableName#&amp;gt;RowX&lt;br /&gt;    {&lt;br /&gt;        &amp;lt;#=refx.DataSetName #&amp;gt;.&amp;lt;#=table.TableName#&amp;gt;Row _row;&lt;br /&gt;        public &amp;lt;#=table.TableName#&amp;gt;RowX(&amp;lt;#=refx.DataSetName #&amp;gt;.&amp;lt;#=table.TableName#&amp;gt;Row row)&lt;br /&gt;        {&lt;br /&gt;            _row = row;&lt;br /&gt;        }&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// The wrapped DataRow&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        public &amp;lt;#=refx.DataSetName #&amp;gt;.&amp;lt;#=table.TableName#&amp;gt;Row Row&lt;br /&gt;        {&lt;br /&gt;            get { return _row; }&lt;br /&gt;        }&lt;br /&gt;        #region Properties&lt;br /&gt;        &amp;lt;#For Each column As ColumnDef In table.ColumnDefList#&amp;gt;&lt;br /&gt;            &amp;lt;#If column.AllowDBNull Then#&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        public &amp;lt;#=GetNullableType(column.DataType.ToString())#&amp;gt; &amp;lt;#=column.ColumnName#&amp;gt;&lt;br /&gt;        {&lt;br /&gt;            get&lt;br /&gt;            {&lt;br /&gt;                if (_row.Is&amp;lt;#=column.ColumnName#&amp;gt;Null())&lt;br /&gt;                    return null;&lt;br /&gt;                else&lt;br /&gt;                    return _row.&amp;lt;#=column.ColumnName#&amp;gt;;&lt;br /&gt;            }&lt;br /&gt;            set&lt;br /&gt;            {&lt;br /&gt;                if (&amp;lt;#=GetHasValueFunction(column.DataType.ToString())#&amp;gt;)&lt;br /&gt;                    _row.Set&amp;lt;#=column.ColumnName#&amp;gt;Null();&lt;br /&gt;                else&lt;br /&gt;                    _row.&amp;lt;#=column.ColumnName#&amp;gt; =  &lt;br /&gt;                        &amp;lt;#=GetNullableValueName(column.DataType.ToString())#&amp;gt;;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        &amp;lt;#Else#&amp;gt;&lt;br /&gt;&lt;br /&gt;        public &amp;lt;#=column.DataType.ToString()#&amp;gt; &amp;lt;#=column.ColumnName#&amp;gt;&lt;br /&gt;        {&lt;br /&gt;            get { return _row.&amp;lt;#=column.ColumnName#&amp;gt;; }&lt;br /&gt;            set { _row.&amp;lt;#=column.ColumnName#&amp;gt; = value; }&lt;br /&gt;        }&lt;br /&gt;        &amp;lt;#End If#&amp;gt;&lt;br /&gt;    &amp;lt;#Next#&amp;gt;&lt;br /&gt;&lt;br /&gt;        #endregion Properties&lt;br /&gt;    }&lt;br /&gt;&amp;lt;#Next#&amp;gt;&lt;br /&gt;}&lt;br /&gt;&amp;lt;#+ &lt;br /&gt;    ''' &amp;lt;summary&amp;gt;&lt;br /&gt;    ''' Gets a DataSetDef bases on parms passed in&lt;br /&gt;    ''' &amp;lt;/summary&amp;gt;&lt;br /&gt;    ''' &amp;lt;param name="parms"&amp;gt;&lt;br /&gt;    ''' The GetParms object containing parameters needed to create DataSetDef:&amp;lt;br /&amp;gt;&lt;br /&gt;    ''' AssembyPath: The path of the assembly containig the DataSet&amp;lt;br /&amp;gt;&lt;br /&gt;    ''' DataSetName: The fully qualified name of the dataset&lt;br /&gt;    ''' &amp;lt;/param&amp;gt;&lt;br /&gt;    ''' &amp;lt;returns&amp;gt;The DataSetDef&amp;lt;/returns&amp;gt;&lt;br /&gt;    Function GetDsDescripter(parms As GetParams) AS DataSetDef&lt;br /&gt;        Dim AssembyPath As String = parms.CurrentParameters.Item("AssembyPath")&lt;br /&gt;        Dim DataSetName As String = parms.CurrentParameters.Item("DataSetName")&lt;br /&gt;        Return DataSetReflector.GetDataSetDef(AssembyPath, DataSetName)&lt;br /&gt;    End Function&lt;br /&gt;    ''' &amp;lt;summary&amp;gt;&lt;br /&gt;    ''' Gets the nullable type name for a given type name&lt;br /&gt;    ''' &amp;lt;/summary&amp;gt;&lt;br /&gt;    ''' &amp;lt;param name="typeName"&amp;gt;&lt;br /&gt;    ''' The type name as a string (as returned from Type.ToString())&amp;lt;/param&amp;gt;&lt;br /&gt;    ''' &amp;lt;returns&amp;gt;The Nullable type name&amp;lt;/returns&amp;gt;&lt;br /&gt;    ''' &amp;lt;remarks&amp;gt;&lt;br /&gt;    ''' Since strings are nullable and not compatible with Generic Nullable class, &lt;br /&gt;    ''' must be treated special &lt;br /&gt;    ''' &amp;lt;/remarks&amp;gt;&lt;br /&gt;    Function GetNullableType(typeName As String) As String&lt;br /&gt;        Dim rVal as string&lt;br /&gt;        Select Case typeName&lt;br /&gt;        Case "System.String"&lt;br /&gt;            rVal = typeName&lt;br /&gt;        Case Else&lt;br /&gt;            rVal = "Nullable&amp;lt;" &amp;amp; typeName &amp;amp; "&amp;gt;"&lt;br /&gt;        End Select&lt;br /&gt;        Return rVal&lt;br /&gt;    End Function&lt;br /&gt;    ''' &amp;lt;summary&amp;gt;&lt;br /&gt;    ''' Gets the string used to check nullablity in a set property method&lt;br /&gt;    ''' &amp;lt;/summary&amp;gt;&lt;br /&gt;    ''' &amp;lt;param name="typeName"&amp;gt;&lt;br /&gt;    ''' The type name as a string (as returned from Type.ToString())&lt;br /&gt;    ''' &amp;lt;/param&amp;gt;&lt;br /&gt;    ''' &amp;lt;returns&amp;gt;&lt;br /&gt;    ''' string of an expression that will return true if value is null&lt;br /&gt;    ''' &amp;lt;/returns&amp;gt;&lt;br /&gt;    ''' &amp;lt;remarks&amp;gt;&lt;br /&gt;    ''' Most nullable types have a HasValue property but not all&lt;br /&gt;    ''' &amp;lt;/remarks&amp;gt;&lt;br /&gt;    Function GetHasValueFunction(typeName As String) As String&lt;br /&gt;        Dim rVal as string&lt;br /&gt;        Select Case typeName&lt;br /&gt;        Case "System.String"&lt;br /&gt;            rVal = "System.String.IsNullOrEmpty(value)"&lt;br /&gt;        Case Else&lt;br /&gt;            rVal = "!value.HasValue"&lt;br /&gt;        End Select&lt;br /&gt;        Return rVal&lt;br /&gt;    End Function&lt;br /&gt;    ''' &amp;lt;summary&amp;gt;&lt;br /&gt;    ''' Gets the string used on the right side of set property method&lt;br /&gt;    ''' &amp;lt;/summary&amp;gt;&lt;br /&gt;    ''' &amp;lt;param name="typeName"&amp;gt;&lt;br /&gt;    ''' The type name as a string (as returned from Type.ToString())&lt;br /&gt;    ''' &amp;lt;/param&amp;gt;&lt;br /&gt;    ''' &amp;lt;returns&amp;gt;The Value property name&amp;lt;/returns&amp;gt;&lt;br /&gt;    ''' &amp;lt;remarks&amp;gt;&lt;br /&gt;    ''' Most nullable types have a Value property but not all&lt;br /&gt;    ''' &amp;lt;/remarks&amp;gt;&lt;br /&gt;    Function GetNullableValueName(typeName As String) As String&lt;br /&gt;        Dim rVal as string&lt;br /&gt;        Select Case typeName&lt;br /&gt;        Case "System.String"&lt;br /&gt;            rVal = "value"&lt;br /&gt;        Case Else&lt;br /&gt;            rVal = "value.Value"&lt;br /&gt;        End Select&lt;br /&gt;        Return rVal&lt;br /&gt;    End Function&lt;br /&gt;#&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h3&gt;Generating a Nullable ADO.NET DataSet Wrapper: The Series&lt;/h3&gt;&lt;ul&gt;   &lt;li&gt;&lt;a href="/2010/11/nullable-ado.html"&gt;Part 1: The Target Code &lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;a href="/2010/11/generating-nullable-ado.html"&gt;Part 2: Describing the DataSet&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;a href="/2010/12/generating-nullable-ado.html"&gt;Part 3: Detour hacking parameters for T4 Templates (VS 2008)&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;strong&gt;Part 4: The Template and putting it all together&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-2697280901768966100?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/2697280901768966100/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=2697280901768966100' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2697280901768966100'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2697280901768966100'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2010/12/generating-nullable-ado_19.html' title='Generating a Nullable ADO.NET DataSet Wrapper'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-2440301576095078493</id><published>2010-12-09T20:08:00.000-08:00</published><updated>2011-03-31T21:01:45.176-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='T4 Templates'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Generation'/><title type='text'>Generating a Nullable ADO.NET DataSet Wrapper</title><content type='html'>&lt;h2&gt;Part 3: Detour hacking parameters for T4 Templates (VS 2008)&lt;/h2&gt;&lt;p&gt;I decided to use T4 Templates instead of my home grown code generation techniques. I didn’t want to spend several pages on my way; besides, I probably need to get with the times and play with the same toys as the cool kids.&lt;/p&gt;&lt;p&gt;This post is to describe a punt. I couldn’t find a way to pass parameters to a VS 2008 .tt file. I know that VS 2010 has the &lt;a href="http://www.olegsych.com/2010/05/t4-parameter-directive/"&gt;parameter directive&lt;/a&gt;, but I don’t have VS 2010, so thus the hack below.&lt;/p&gt;&lt;h4&gt;TTCommucator.GetParams&lt;/h4&gt;&lt;p&gt;Since I can reference .NET assemblies, I am storing my parameters as a Dictionary to a file outside of the template and then reading it in from inside the template.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Linq;&lt;br /&gt;using System.Text;&lt;br /&gt;using System.IO;&lt;br /&gt;&lt;br /&gt;namespace TTCommucator&lt;br /&gt;{&lt;br /&gt;    /// &amp;lt;summary&amp;gt;&lt;br /&gt;    /// Used to pass parameters to a T4 Template&lt;br /&gt;    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;    public class GetParams&lt;br /&gt;    {&lt;br /&gt;        private const char SEPERATOR_CHAR = '|';&lt;br /&gt;        private string _fileName;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// The Dictionary containing the Parameters&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        public Dictionary&amp;lt;string, string&amp;gt; CurrentParameters { get; set; }&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Creates a GetParmas with a Filename&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="fileName"&amp;gt;The name of the file to store the parameters&amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;remarks&amp;gt;Both sides of the transaction must agree on file name&amp;lt;/remarks&amp;gt;&lt;br /&gt;        public GetParams(string fileName)&lt;br /&gt;        {&lt;br /&gt;            CurrentParameters = new Dictionary&amp;lt;string, string&amp;gt;();&lt;br /&gt;            this._fileName = fileName;&lt;br /&gt;        }&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Loads the data from the file into the Dictionary CurrentParameters &lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        public void Load()&lt;br /&gt;        {&lt;br /&gt;            CurrentParameters = new Dictionary&amp;lt;string, string&amp;gt;();&lt;br /&gt;            string line;&lt;br /&gt;            using (TextReader tr = new StreamReader(_fileName))&lt;br /&gt;            {&lt;br /&gt;                while ((line = tr.ReadLine()) != null)&lt;br /&gt;                {&lt;br /&gt;                    string[] parts = line.Split(new char[] { SEPERATOR_CHAR }, 2);&lt;br /&gt;                    if (parts.Count() &amp;gt; 1)&lt;br /&gt;                        CurrentParameters.Add(parts[0], parts[1]);&lt;br /&gt;                }&lt;br /&gt;                tr.Close();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Saves the data in the Dictionary CurrentParameters to the file&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        public void Save()&lt;br /&gt;        {&lt;br /&gt;            using (TextWriter tw = new StreamWriter(_fileName))&lt;br /&gt;            {&lt;br /&gt;                foreach (var item in CurrentParameters)&lt;br /&gt;                {&lt;br /&gt;                    tw.WriteLine(item.Key + SEPERATOR_CHAR + item.Value);&lt;br /&gt;                }&lt;br /&gt;                tw.Close();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;h4&gt;Test Template&lt;/h4&gt;&lt;p&gt;I created a simple template to demonstrate that I can receive parameters using my GetParams class. Note that I use VB.NET for code in my templates. Since I usually generate C# code, I find it easier to read templates when the template code isn’t C#, besides “&lt;#}#&gt;” is downright nasty looking. &lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;#@ template debug="true" hostspecific="true" language="VB" #&amp;gt;&lt;br /&gt;&amp;lt;#@ assembly name="C:\Projects\TTCommucator\TTCommucator.dll" #&amp;gt;&lt;br /&gt;&amp;lt;#@ import namespace="TTCommucator" #&amp;gt;&lt;br /&gt;&amp;lt;#@ import namespace="System.Collections.Generic" #&amp;gt;&lt;br /&gt;&amp;lt;#@ output extension=".txt" #&amp;gt;&lt;br /&gt;&amp;lt;# &lt;br /&gt; ' Load the Parameters here:&lt;br /&gt; Dim parms As new GetParams(Host.ResolvePath("setting.txt"))&lt;br /&gt; parms.Load()&lt;br /&gt;#&amp;gt;&lt;br /&gt;Values in parms:&lt;br /&gt;&amp;lt;#For Each item As KeyValuePair(Of String, String) In parms.CurrentSettings#&amp;gt;&lt;br /&gt;    &amp;lt;#=item.Key#&amp;gt; = &amp;lt;#=item.Value#&amp;gt;&lt;br /&gt;&amp;lt;#Next#&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h4&gt;Test Console Application&lt;/h4&gt;&lt;p&gt;Here is a simple program to test with. It doesn’t do anything more than necessary. NOTE: You will need to install &lt;a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=59EC6EC3-4273-48A3-BA25-DC925A45584D"&gt;Visual Studio 2008 SDK v1.1&lt;/a&gt; to run this code:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.IO;&lt;br /&gt;using Microsoft.VisualStudio.TextTemplating;&lt;br /&gt;using TTCommucator;&lt;br /&gt;&lt;br /&gt;namespace TTCommunicatorConsole&lt;br /&gt;{&lt;br /&gt;    class Program&lt;br /&gt;    {&lt;br /&gt;        static void Main(string[] args)&lt;br /&gt;        {&lt;br /&gt;            // Set up some parameters:&lt;br /&gt;            var parms = new GetParams("setting.txt");&lt;br /&gt;            parms.CurrentParameters.Add("Greeting", "Hello World!");&lt;br /&gt;            parms.CurrentParameters.Add("Run Time", DateTime.Now.ToString());&lt;br /&gt;            parms.Save();&lt;br /&gt;&lt;br /&gt;            string templateFileName = "SimpleTemplate.tt";&lt;br /&gt;&lt;br /&gt;            // Set up host and engine&lt;br /&gt;            CustomCmdLineHost host = new CustomCmdLineHost();&lt;br /&gt;            Engine engine = new Engine();&lt;br /&gt;            host.SetTemplateFile(templateFileName);&lt;br /&gt;&lt;br /&gt;            //Read the text template.&lt;br /&gt;            string input = File.ReadAllText(templateFileName);&lt;br /&gt;&lt;br /&gt;            //Transform the text template.&lt;br /&gt;            string output = engine.ProcessTemplate(input, host);&lt;br /&gt;&lt;br /&gt;            // Show your work&lt;br /&gt;            Console.WriteLine(output);&lt;br /&gt;&lt;br /&gt;            // Wait for me&lt;br /&gt;            Console.ReadKey();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h4&gt;Host Class&lt;/h4&gt;&lt;p&gt;I lifted this class from MSDN and removed the comments to save space. You can learn more about it by going &lt;a href="http://msdn.microsoft.com/en-us/library/bb126579%28v=VS.90%29.aspx"&gt; here&lt;/a&gt;. NOTE: The MSDN code doesn't include the Serializable attribute, but I needed to add it to avoid errors. You will need to include a reference to &lt;strong&gt;Microsoft.VisualStudio.TextTemplating&lt;/strong&gt;.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.CodeDom.Compiler;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.IO;&lt;br /&gt;using System.Text;&lt;br /&gt;using Microsoft.VisualStudio.TextTemplating;&lt;br /&gt;&lt;br /&gt;namespace TTCommucator&lt;br /&gt;{&lt;br /&gt;    [Serializable]&lt;br /&gt;    public class CustomCmdLineHost : ITextTemplatingEngineHost&lt;br /&gt;    {&lt;br /&gt;        internal string _templateFile;&lt;br /&gt;        public string TemplateFile&lt;br /&gt;        {&lt;br /&gt;            get { return _templateFile; }&lt;br /&gt;        }&lt;br /&gt;        private string _fileExtension = ".txt";&lt;br /&gt;        public string FileExtension&lt;br /&gt;        {&lt;br /&gt;            get { return _fileExtension; }&lt;br /&gt;        }&lt;br /&gt;        private Encoding _fileEncoding = Encoding.UTF8;&lt;br /&gt;        public Encoding FileEncoding&lt;br /&gt;        {&lt;br /&gt;            get { return _fileEncoding; }&lt;br /&gt;        }&lt;br /&gt;        private CompilerErrorCollection _errors;&lt;br /&gt;        public CompilerErrorCollection Errors&lt;br /&gt;        {&lt;br /&gt;            get { return _errors; }&lt;br /&gt;        }&lt;br /&gt;        public IList&lt;string&gt; StandardAssemblyReferences&lt;br /&gt;        {&lt;br /&gt;            get { return new string[] { typeof(System.Uri).Assembly.Location }; }&lt;br /&gt;        }&lt;br /&gt;        public IList&lt;string&gt; StandardImports&lt;br /&gt;        {&lt;br /&gt;            get { return new string[] { "System" }; }&lt;br /&gt;        }&lt;br /&gt;        public bool LoadIncludeText(string requestFileName, out string content, &lt;br /&gt;            out string location)&lt;br /&gt;        {&lt;br /&gt;            content = string.Empty;&lt;br /&gt;            location = string.Empty;&lt;br /&gt;            if (File.Exists(requestFileName))&lt;br /&gt;            {&lt;br /&gt;                content = File.ReadAllText(requestFileName);&lt;br /&gt;                return true;&lt;br /&gt;            }&lt;br /&gt;            else&lt;br /&gt;                return false;&lt;br /&gt;        }&lt;br /&gt;        public object GetHostOption(string optionName)&lt;br /&gt;        {&lt;br /&gt;            object returnObject;&lt;br /&gt;            switch (optionName)&lt;br /&gt;            {&lt;br /&gt;                case "CacheAssemblies":&lt;br /&gt;                    returnObject = true;&lt;br /&gt;                    break;&lt;br /&gt;                default:&lt;br /&gt;                    returnObject = null;&lt;br /&gt;                    break;&lt;br /&gt;            }&lt;br /&gt;            return returnObject;&lt;br /&gt;        }&lt;br /&gt;        public string ResolveAssemblyReference(string assemblyReference)&lt;br /&gt;        {&lt;br /&gt;            if (File.Exists(assemblyReference))&lt;br /&gt;                return assemblyReference;&lt;br /&gt;            string candidate = Path.Combine(Path.GetDirectoryName(this.TemplateFile), &lt;br /&gt;                assemblyReference);&lt;br /&gt;            if (File.Exists(candidate))&lt;br /&gt;                return candidate;&lt;br /&gt;            return string.Empty;&lt;br /&gt;        }&lt;br /&gt;        public Type ResolveDirectiveProcessor(string processorName)&lt;br /&gt;        {&lt;br /&gt;            if (string.Compare(processorName, "XYZ", StringComparison.OrdinalIgnoreCase) &lt;br /&gt;                == 0)&lt;br /&gt;            {&lt;br /&gt;            }&lt;br /&gt;            throw new Exception("Directive Processor not found");&lt;br /&gt;        }&lt;br /&gt;        public string ResolvePath(string fileName)&lt;br /&gt;        {&lt;br /&gt;            if (fileName == null)&lt;br /&gt;                throw new ArgumentNullException("the file name cannot be null");&lt;br /&gt;            if (File.Exists(fileName))&lt;br /&gt;                return fileName;&lt;br /&gt;            string candidate = Path.Combine(Path.GetDirectoryName(this.TemplateFile), &lt;br /&gt;                fileName);&lt;br /&gt;            if (File.Exists(candidate))&lt;br /&gt;                return candidate;&lt;br /&gt;            return fileName;&lt;br /&gt;        }&lt;br /&gt;        public string ResolveParameterValue(string directiveId, string processorName, &lt;br /&gt;            string parameterName)&lt;br /&gt;        {&lt;br /&gt;            if (directiveId == null)&lt;br /&gt;                throw new ArgumentNullException("the directiveId cannot be null");&lt;br /&gt;            if (processorName == null)&lt;br /&gt;                throw new ArgumentNullException("the processorName cannot be null");&lt;br /&gt;            if (parameterName == null)&lt;br /&gt;                throw new ArgumentNullException("the parameterName cannot be null");&lt;br /&gt;            return string.Empty;&lt;br /&gt;        }&lt;br /&gt;        public void SetFileExtension(string extension)&lt;br /&gt;        {&lt;br /&gt;            _fileExtension = extension;&lt;br /&gt;        }&lt;br /&gt;        public void SetTemplateFile(string templateFile)&lt;br /&gt;        {&lt;br /&gt;            _templateFile = templateFile;&lt;br /&gt;        }&lt;br /&gt;        public void SetOutputEncoding(Encoding encoding, &lt;br /&gt;            bool fromOutputDirective)&lt;br /&gt;        {&lt;br /&gt;            _fileEncoding = encoding;&lt;br /&gt;        }&lt;br /&gt;        public void LogErrors(CompilerErrorCollection errors)&lt;br /&gt;        {&lt;br /&gt;            _errors = errors;&lt;br /&gt;        }&lt;br /&gt;        public AppDomain ProvideTemplatingAppDomain(string content)&lt;br /&gt;        {&lt;br /&gt;            return AppDomain.CreateDomain("Generation App Domain");&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h3&gt;Generating a Nullable ADO.NET DataSet Wrapper: The Series&lt;/h3&gt;&lt;ul&gt;   &lt;li&gt;&lt;a href="/2010/11/nullable-ado.html"&gt;Part 1: The Target Code &lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;a href="/2010/11/generating-nullable-ado.html"&gt;Part 2: Describing the DataSet&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;strong&gt;Part 3: Detour hacking parameters for T4 Templates (VS 2008)&lt;/strong&gt;&lt;/li&gt;   &lt;li&gt;&lt;a href="/2010/12/generating-nullable-ado_19.html"&gt;Part 4: The Template and putting it all together&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-2440301576095078493?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/2440301576095078493/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=2440301576095078493' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2440301576095078493'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2440301576095078493'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2010/12/generating-nullable-ado.html' title='Generating a Nullable ADO.NET DataSet Wrapper'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-7385098390006650969</id><published>2010-11-30T19:50:00.000-08:00</published><updated>2011-04-03T08:50:05.666-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Code Generation'/><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='DataSet'/><title type='text'>Generating a Nullable ADO.NET DataSet Wrapper</title><content type='html'>&lt;h3&gt;Part 2: Describing the DataSet&lt;/h3&gt;&lt;p&gt;The next thing I need for code generation is a reliable source of meta data describing the code I want to generate. Here I merely ask the DataSet to describe itself and store the description into a set of simplified description objects. I am moving the metadata from the DataSet into a simpler object to make it easier to deal with when I start generating code in later parts of this series.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public static DataSetDef GetDataSetDefFromDS(DataSet ds) &lt;br /&gt;{ &lt;br /&gt;    // Code for this class is in “The Describer Classes” section below &lt;br /&gt;    var dsDef = new DataSetDef(ds.DataSetName, ds.Namespace); &lt;br /&gt;    // The DataSet has a collection of DataTables &lt;br /&gt;    foreach (var rawTable in ds.Tables) &lt;br /&gt;    { &lt;br /&gt;        DataTable tab = (DataTable)rawTable; &lt;br /&gt;        // See “The Describer Classes” &lt;br /&gt;        var tabDef = new TableDef(tab.TableName); &lt;br /&gt;        // And each DataTable has a collection of DataColumns &lt;br /&gt;        foreach (var rawColumn in tab.Columns) &lt;br /&gt;        { &lt;br /&gt;            DataColumn col = (DataColumn)rawColumn; &lt;br /&gt;            // See “The Describer Classes” &lt;br /&gt;            var colDef = new ColumnDef(col.ColumnName, col.DataType, col.AllowDBNull); &lt;br /&gt;            tabDef.ColumnDefList.Add(colDef); &lt;br /&gt;        } &lt;br /&gt;        dsDef.TableDefList.Add(tabDef); &lt;br /&gt;    } &lt;br /&gt;    return dsDef; &lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;h3&gt;Getting the DataSet to Interrogate&lt;/h3&gt;&lt;p&gt;OK, I can generate a description of the data from a DataSet, but the DataSet is in a different project. I want to make a tool that I can use &lt;/p&gt;&lt;h4&gt;XSD Schema File&lt;/h4&gt;&lt;p&gt;When you create a typed DataSet in Visual Studio, creates a .xsd file that it uses to generate your DataSet code. I can read the schema from an XSD file into a DataSet using the ReadXmlSchema() method:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public static DataSetDef GetDataSetDefFromXsd(string XsdPath) &lt;br /&gt;{ &lt;br /&gt;    DataSet ds = new DataSet(); &lt;br /&gt;    try &lt;br /&gt;    { &lt;br /&gt;        ds.ReadXmlSchema(XsdPath); &lt;br /&gt;        // Call the method above: &lt;br /&gt;        return GetDataSetDefFromDS(ds); &lt;br /&gt;    } &lt;br /&gt;    catch // I don’t care what it is right now &lt;br /&gt;    { &lt;br /&gt;        return null; &lt;br /&gt;    } &lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;h4&gt;In an Assembly&lt;/h4&gt;&lt;p&gt;The DataSet may exist in a previously existing assembly; we may not even have access to the source code. Using reflection, we can activate the type and cast it as a DataSet:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public static DataSetDef doRefelctDataSetFromType(Type myObjectType) &lt;br /&gt;{ &lt;br /&gt;    // Create an instance of the Type: &lt;br /&gt;    object obj = Activator.CreateInstance(myObjectType); &lt;br /&gt;    // Try to cast it as a DataSet: &lt;br /&gt;    DataSet ds = obj as DataSet; &lt;br /&gt;    if (ds != null) &lt;br /&gt;    { &lt;br /&gt;        // Call the method above: &lt;br /&gt;        return GetDataSetDefFromDS(ds); &lt;br /&gt;    } &lt;br /&gt;    return null; &lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;h3&gt;The Describer Classes&lt;/h3&gt;&lt;p&gt;These are the classes to make the objects loaded in GetDataSetDefFromDS(). They represent a simplified description of the data. I only get the data that I think I need to generate the code later. If I later need more data, I can alter GetDataSetDefFromDS() and these classes add what I need.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public class DataSetDef &lt;br /&gt;{ &lt;br /&gt;    public List&lt;TableDef&gt; TableDefList { get; private set; } &lt;br /&gt;    public DataSetDef() &lt;br /&gt;    { &lt;br /&gt;        TableDefList = new List&lt;TableDef&gt;(); &lt;br /&gt;    } &lt;br /&gt;    public DataSetDef(string dataSetName, string nameSpace) : &lt;br /&gt;        this() &lt;br /&gt;    { &lt;br /&gt;        DataSetName = dataSetName; &lt;br /&gt;        NameSpace = nameSpace; &lt;br /&gt;    } &lt;br /&gt;    public string DataSetName { get; set; } &lt;br /&gt;    public string NameSpace { get; set; } &lt;br /&gt;} &lt;br /&gt;public class TableDef &lt;br /&gt;{ &lt;br /&gt;    public List&lt;ColumnDef&gt; ColumnDefList { get; private set; } &lt;br /&gt;    public TableDef() &lt;br /&gt;    { &lt;br /&gt;        ColumnDefList = new List&lt;ColumnDef&gt;(); &lt;br /&gt;    } &lt;br /&gt;    public TableDef(string tableName) : &lt;br /&gt;        this() &lt;br /&gt;    { &lt;br /&gt;        TableName = tableName; &lt;br /&gt;    } &lt;br /&gt;    public string TableName { get; set; } &lt;br /&gt;} &lt;br /&gt;public class ColumnDef &lt;br /&gt;{ &lt;br /&gt;    public ColumnDef(string columnName, Type dataType, bool allowDBNull) &lt;br /&gt;    { &lt;br /&gt;        ColumnName = columnName; &lt;br /&gt;        DataType = dataType; &lt;br /&gt;        AllowDBNull = allowDBNull; &lt;br /&gt;    } &lt;br /&gt;    public string ColumnName { get; set; } &lt;br /&gt;    public Type DataType { get; set; }  // .NET Type, not SQL Type &lt;br /&gt;    public bool AllowDBNull { get; set; } &lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;h3&gt;Generating a Nullable ADO.NET DataSet Wrapper: The Series&lt;/h3&gt;&lt;ul&gt;   &lt;li&gt;&lt;a href="/2010/11/nullable-ado.html"&gt;Part 1: The Target Code &lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;strong&gt;Part 2: Describing the DataSet&lt;/strong&gt;&lt;/li&gt;   &lt;li&gt;&lt;a href="/2010/12/generating-nullable-ado.html"&gt;Part 3: Detour hacking parameters for T4 Templates (VS 2008)&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;a href="/2010/12/generating-nullable-ado_19.html"&gt;Part 4: The Template and putting it all together&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-7385098390006650969?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/7385098390006650969/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=7385098390006650969' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/7385098390006650969'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/7385098390006650969'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2010/11/generating-nullable-ado.html' title='Generating a Nullable ADO.NET DataSet Wrapper'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-2498657510513608593</id><published>2010-11-24T06:06:00.000-08:00</published><updated>2011-04-03T08:52:42.850-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Code Generation'/><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='DataSet'/><title type='text'>Generating a Nullable ADO.NET DataSet Wrapper</title><content type='html'>&lt;h2&gt;Part 1: The Target Code&lt;/h2&gt;&lt;p&gt;Classic ADO.NET is the most successful client side database technology in the history of Microsoft. Even if the Entity Framework (officially "ADO.NET Entity Framework") is as successful as Microsoft thinks it will be, ADO.NET DataSets will be around for years. &lt;/p&gt;&lt;p&gt;One of the biggest weaknesses of the ADO.NET DataSet is the turn of the century way it handles nullability. Since Nullable&lt;T&gt; didn’t exist until .NET 2, the designers of the DataSet handled nullability with two methods and one exception. I decided to generate a nullable wrapper for ADO.NET DataSets.&lt;/p&gt;&lt;h3&gt;Target Code&lt;/h3&gt;&lt;p&gt;To generate code, I need sample target code, so I know where I am going&lt;h4&gt;DataRow&lt;/h4&gt;&lt;p&gt;I plan on wrapping each typed DataRow in my own proxy class:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public class EmployeesRowX&lt;br /&gt;{&lt;br /&gt;    // The wrapped row&lt;br /&gt;    NorthwindDS.EmployeesRow _row;&lt;br /&gt;    public EmployeesRowX(NorthwindDS.EmployeesRow row)&lt;br /&gt;    {&lt;br /&gt;        _row = row;&lt;br /&gt;    }&lt;br /&gt;    // Direct access to the row, if you need something I didn’t implement&lt;br /&gt;    public NorthwindDS.EmployeesRow Row&lt;br /&gt;    {&lt;br /&gt;        get { return _row; }&lt;br /&gt;    }&lt;br /&gt;    // …&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;For a non-nullable field, I just pass the data back without doing anything fancy:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public string FirstName&lt;br /&gt;{&lt;br /&gt;    get { return _row.FirstName; }&lt;br /&gt;    set { Row.FirstName = value; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;For a nullable field, I have to translate ADO.NET the pre-nullable logic (IsXXXNull() &amp; SetXXXNull()) to a modern nullable:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public DateTime? BirthDate&lt;br /&gt;{&lt;br /&gt;    get&lt;br /&gt;    {&lt;br /&gt;        if (_row.IsBirthDateNull())&lt;br /&gt;            return null;&lt;br /&gt;        else&lt;br /&gt;            return _row.BirthDate;&lt;br /&gt;    }&lt;br /&gt;    set&lt;br /&gt;    {&lt;br /&gt;        if (!value.HasValue)&lt;br /&gt;            _row.SetBirthDateNull();&lt;br /&gt;        else&lt;br /&gt;           _row.BirthDate = value.Value;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;h4&gt;DataSet and DataTables&lt;/h4&gt;&lt;p&gt;I will wrap the DataSet and DataTables in their own proxies:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public class NorthwindDSX&lt;br /&gt;{&lt;br /&gt;    private NorthwindDS _ds;&lt;br /&gt;    public NorthwindDSX(NorthwindDS ds)&lt;br /&gt;    {&lt;br /&gt;        _ds = ds;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public EmployeesDataTableX Employees&lt;br /&gt;    {&lt;br /&gt;        get { return new EmployeesDataTableX(_ds.Employees); }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public NorthwindDS DataSet&lt;br /&gt;    {&lt;br /&gt;        get { return _ds; }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class EmployeesDataTableX: IEnumerable&lt;EmployeesRowX&gt;&lt;br /&gt;{&lt;br /&gt;    private NorthwindDS.EmployeesDataTable _theTable;&lt;br /&gt;    public EmployeesDataTableX(NorthwindDS.EmployeesDataTable table)&lt;br /&gt;    {&lt;br /&gt;        _theTable = table;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public NorthwindDS.EmployeesDataTable Table&lt;br /&gt;    {&lt;br /&gt;        get { return _theTable; }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    #region IEnumerable&lt;EmployeesRowX&gt; Members&lt;br /&gt;    public IEnumerator&lt;EmployeesRowX&gt; GetEnumerator()&lt;br /&gt;    {&lt;br /&gt;        return new EmployeesTableEnum(_theTable);&lt;br /&gt;    }&lt;br /&gt;    #endregion&lt;br /&gt;&lt;br /&gt;    #region IEnumerable Members&lt;br /&gt;    IEnumerator IEnumerable.GetEnumerator()&lt;br /&gt;    {&lt;br /&gt;        return (IEnumerator)this;&lt;br /&gt;    }&lt;br /&gt;    #endregion&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;h4&gt;DataTable’s IEnumberator&amp;lt;T&amp;gt;&lt;/h4&gt;&lt;p&gt;And each Table needs an Enumerator:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public class EmployeesTableEnum : IEnumerator&lt;EmployeesRowX&gt;&lt;br /&gt;{&lt;br /&gt;    private NorthwindDS.EmployeesDataTable _collection;&lt;br /&gt;    private int curIndex;&lt;br /&gt;    private EmployeesRowX curBox;&lt;br /&gt;&lt;br /&gt;    public EmployeesTableEnum(NorthwindDS.EmployeesDataTable collection)&lt;br /&gt;    {&lt;br /&gt;        _collection = collection;&lt;br /&gt;        curIndex = -1;&lt;br /&gt;        curBox = default(EmployeesRowX);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public bool MoveNext()&lt;br /&gt;    {&lt;br /&gt;        //Avoids going beyond the end of the collection.&lt;br /&gt;        if (++curIndex &gt;= _collection.Count)&lt;br /&gt;            return false;&lt;br /&gt;        else&lt;br /&gt;            // Set current EmployeesRowX to next item in collection.&lt;br /&gt;            curBox = new EmployeesRowX(&lt;br /&gt;                (NorthwindDS.EmployeesRow)_collection.Rows[curIndex]);&lt;br /&gt;        return true;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void Reset() { curIndex = -1; }&lt;br /&gt;&lt;br /&gt;    void IDisposable.Dispose() { }&lt;br /&gt;&lt;br /&gt;    public EmployeesRowX Current&lt;br /&gt;    {&lt;br /&gt;        get { return curBox; }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    object IEnumerator.Current&lt;br /&gt;    {&lt;br /&gt;        get { return Current; }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h3&gt;Summing it up&lt;/h3&gt;&lt;p&gt;So now that I know where I am going, I can get started at making generating code. The code will change as I work through the process.&lt;/p&gt;&lt;p&gt;Since a Typed DataSet is generated, it is possible to generate a full DataSet with nullable fields; that is a job for Microsoft.&lt;/p&gt;&lt;h3&gt;Generating a Nullable ADO.NET DataSet Wrapper: The Series&lt;/h3&gt;&lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Part 1: The Target Code&lt;/strong&gt;&lt;/li&gt;   &lt;li&gt;&lt;a href="/2010/11/generating-nullable-ado.html"&gt;Part 2: Describing the DataSet&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;a href="/2010/12/generating-nullable-ado.html"&gt;Part 3: Detour hacking parameters for T4 Templates (VS 2008)&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;a href="/2010/12/generating-nullable-ado_19.html"&gt;Part 4: The Template and putting it all together&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-2498657510513608593?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/2498657510513608593/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=2498657510513608593' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2498657510513608593'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2498657510513608593'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2010/11/nullable-ado.html' title='Generating a Nullable ADO.NET DataSet Wrapper'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-4770258340320590982</id><published>2010-10-24T19:28:00.000-07:00</published><updated>2011-04-09T06:48:15.137-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Samus'/><category scheme='http://www.blogger.com/atom/ns#' term='MongoDB'/><category scheme='http://www.blogger.com/atom/ns#' term='Linq'/><title type='text'>Adding MongoDB samus / mongodb-csharp to the Linq Comparison</title><content type='html'>&lt;p&gt;Last month I &lt;a href="/2010/09/comparing-different-linq-providers-ive.html"&gt;compared several Linq providers&lt;/a&gt;. Lately I’ve been playing with &lt;a href="http://www.mongodb.org"&gt;MongoDB&lt;/a&gt;. MongoDB is a Document (read NoSQL) database that runs on windows and has a .NET provider.&lt;/p&gt;&lt;p&gt;To do this, I am going to set up an environment with the same data as I used in the previous examples (the infamous Northwind database from SQL Server).&lt;/p&gt;&lt;h3&gt;Create the Data&lt;/h3&gt;&lt;p&gt;To recreate the data from Northwind, I wrote the following query to create insert statements.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;SELECT 'db.Product.insert({' &lt;br /&gt;    + 'ProductID: ' + CAST(p.ProductID AS VARCHAR(10)) + ', '&lt;br /&gt;    + 'ProductName: "' + p.ProductName + '", '&lt;br /&gt;    + 'SupplierID: ' + CAST(p.SupplierID AS VARCHAR(10)) + ', '&lt;br /&gt;    + 'CategoryID: ' + CAST(p.CategoryID AS VARCHAR(10)) + ', '&lt;br /&gt;    + 'QuantityPerUnit: "' + p.QuantityPerUnit + '", '&lt;br /&gt;    + 'UnitPrice: ' + CAST(p.UnitPrice AS VARCHAR(10)) + ', '&lt;br /&gt;    + 'UnitsInStock: ' + CAST(p.UnitsInStock AS VARCHAR(10)) + ', '&lt;br /&gt;    + 'UnitsOnOrder: ' + CAST(p.UnitsOnOrder AS VARCHAR(10)) + ', '&lt;br /&gt;    + 'ReorderLevel: ' + CAST(p.ReorderLevel AS VARCHAR(10)) + ', '&lt;br /&gt;    + 'Discontinued: ' + CASE WHEN p.Discontinued = 1 THEN '"true"' ELSE '"false"' END + ', '&lt;br /&gt;    + 'CategoryName: "' + c.CategoryName + '"'&lt;br /&gt;    + '})'&lt;br /&gt;FROM Northwind.dbo.Products p&lt;br /&gt;    JOIN Northwind.dbo.Categories c ON p.CategoryID = c.CategoryID&lt;br /&gt;ORDER BY p.ProductID&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;I run the above query against a Northwind Database that I have lying around on my home computer and I pasted the result set into a Mongo Shell window.&lt;/p&gt;&lt;p&gt;Notice that I added CategoryName to Product. From a relational point of view, this is criminal. However, Mongo is a DOCUMENT database and repeating data isn’t quite sin; I am also leaving this in the CategoryName because repeating data is in the spirit of document databases as I understand them. (Besides the version of MongoDB.DLL I’m using doesn’t appear to support joins very well.)&lt;/p&gt;&lt;h3&gt;The POCO Class&lt;/h3&gt;&lt;p&gt;To run straightforward Linq queries using MongoDB.DLL, I need a POCO class to hydrate the data into. Since MongoDB is a document database, the data can be unstructured, but to work in Linq, structured data makes things easier. &lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public class Product&lt;br /&gt;{&lt;br /&gt;    public int ProductID { get; set; }&lt;br /&gt;    public string ProductName { get; set; }&lt;br /&gt;    public int SupplierID { get; set; }&lt;br /&gt;    public int CategoryID { get; set; }&lt;br /&gt;    public string QuantityPerUnit { get; set; }&lt;br /&gt;    public decimal UnitPrice { get; set; }&lt;br /&gt;    public int UnitsInStock { get; set; }&lt;br /&gt;    public int UnitsOnOrder { get; set; }&lt;br /&gt;    public int ReorderLevel { get; set; }&lt;br /&gt;    public bool Discontinued { get; set; }&lt;br /&gt;    public string CategoryName { get; set; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;h3&gt;The Code&lt;/h3&gt;&lt;p&gt;Now that I have copied the data that I need to “simulate” the Northwind Product and Category data into a MongoDB collection, I can use this code to do the same thing as I did in the last post:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public static IMongoDatabase GetContext()&lt;br /&gt;{&lt;br /&gt;    var mongo = new Mongo();&lt;br /&gt;    mongo.Connect();&lt;br /&gt;    return mongo.GetDatabase("Northwind");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public static void DoDemo()&lt;br /&gt;{&lt;br /&gt;    var mdb = GetContext();&lt;br /&gt;    var list = from p in mdb.GetCollection&lt;Product&gt;().Linq()&lt;br /&gt;               where p.CategoryName == "Seafood"&lt;br /&gt;               orderby p.ProductName&lt;br /&gt;               select new&lt;br /&gt;               {&lt;br /&gt;                   p.ProductID,&lt;br /&gt;                   p.ProductName,&lt;br /&gt;                   p.UnitPrice,&lt;br /&gt;                   p.CategoryName&lt;br /&gt;               };&lt;br /&gt;&lt;br /&gt;    Console.WriteLine("MongoDB Demo");&lt;br /&gt;    foreach (var item in list)&lt;br /&gt;    {&lt;br /&gt;        Console.WriteLine(&lt;br /&gt;            string.Format("{0}\t{1:c}\t{2}\t{3}",&lt;br /&gt;                item.ProductID,&lt;br /&gt;                item.UnitPrice,&lt;br /&gt;                item.ProductName,&lt;br /&gt;                item.CategoryName));&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;GetContext() is straight forward: You new-up a Mongo, connect and get a database.&lt;/p&gt;&lt;p&gt;The most interesting statement is mdb.GetCollection&lt;Product&gt;().Linq(). The GetCollection&lt;T&gt; method links the content with the name of T to an IMongoCollection of Ts. LinqExtensions.Linq() is an extension method that converts the IMongoCollection to IQueryable.&lt;/p&gt;&lt;p&gt;Last month I compared several Linq providers. Lately I’ve been playing with &lt;a href="http://www.mongodb.org"&gt;MongoDB&lt;/a&gt;. MongoDB is a Document (read NoSQL) database that runs on windows and has a .NET provider.&lt;/p&gt;&lt;p&gt;To do this, I am going to set up an environment with the same data as I used in the previous examples (the infamous Northwind database from SQL Server).&lt;/p&gt;&lt;h3&gt;Create the Data&lt;/h3&gt;&lt;p&gt;To recreate the data from Northwind, I wrote the following query to create insert statements.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;SELECT 'db.Product.insert({' &lt;br /&gt;    + 'ProductID: ' + CAST(p.ProductID AS VARCHAR(10)) + ', '&lt;br /&gt;    + 'ProductName: "' + p.ProductName + '", '&lt;br /&gt;    + 'SupplierID: ' + CAST(p.SupplierID AS VARCHAR(10)) + ', '&lt;br /&gt;    + 'CategoryID: ' + CAST(p.CategoryID AS VARCHAR(10)) + ', '&lt;br /&gt;    + 'QuantityPerUnit: "' + p.QuantityPerUnit + '", '&lt;br /&gt;    + 'UnitPrice: ' + CAST(p.UnitPrice AS VARCHAR(10)) + ', '&lt;br /&gt;    + 'UnitsInStock: ' + CAST(p.UnitsInStock AS VARCHAR(10)) + ', '&lt;br /&gt;    + 'UnitsOnOrder: ' + CAST(p.UnitsOnOrder AS VARCHAR(10)) + ', '&lt;br /&gt;    + 'ReorderLevel: ' + CAST(p.ReorderLevel AS VARCHAR(10)) + ', '&lt;br /&gt;    + 'Discontinued: ' + CASE WHEN p.Discontinued = 1 THEN '"true"' ELSE '"false"' END + ', '&lt;br /&gt;    + 'CategoryName: "' + c.CategoryName + '"'&lt;br /&gt;    + '})'&lt;br /&gt;FROM Northwind.dbo.Products p&lt;br /&gt;    JOIN Northwind.dbo.Categories c ON p.CategoryID = c.CategoryID&lt;br /&gt;ORDER BY p.ProductID&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;I run the above query against a Northwind Database that I have lying around on my home computer and I pasted the result set into a Mongo Shell window.&lt;/p&gt;&lt;p&gt;Notice that I added CategoryName to Product. From a relational point of view, this is criminal. However, Mongo is a DOCUMENT database and repeating data isn’t quite sin; I am also leaving this in the CategoryName because repeating data is in the spirit of document databases as I understand them. (Besides the version of MongoDB.DLL I’m using doesn’t appear to support joins very well.)&lt;/p&gt;&lt;h3&gt;The POCO Class&lt;/h3&gt;&lt;p&gt;To run straightforward Linq queries using MongoDB.DLL, I need a POCO class to hydrate the data into. Since MongoDB is a document database, the data can be unstructured, but to work in Linq, structured data makes things easier. &lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public class Product&lt;br /&gt;{&lt;br /&gt;    public int ProductID { get; set; }&lt;br /&gt;    public string ProductName { get; set; }&lt;br /&gt;    public int SupplierID { get; set; }&lt;br /&gt;    public int CategoryID { get; set; }&lt;br /&gt;    public string QuantityPerUnit { get; set; }&lt;br /&gt;    public decimal UnitPrice { get; set; }&lt;br /&gt;    public int UnitsInStock { get; set; }&lt;br /&gt;    public int UnitsOnOrder { get; set; }&lt;br /&gt;    public int ReorderLevel { get; set; }&lt;br /&gt;    public bool Discontinued { get; set; }&lt;br /&gt;    public string CategoryName { get; set; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;h3&gt;The Code&lt;/h3&gt;&lt;p&gt;Now that I have copied the data that I need to “simulate” the Northwind Product and Category data into a MongoDB collection, I can use this code to do the same thing as I did in the last post:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public static IMongoDatabase GetContext()&lt;br /&gt;{&lt;br /&gt;    var mongo = new Mongo();&lt;br /&gt;    mongo.Connect();&lt;br /&gt;    return mongo.GetDatabase("Northwind");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public static void DoDemo()&lt;br /&gt;{&lt;br /&gt;    var mdb = GetContext();&lt;br /&gt;    var list = from p in mdb.GetCollection&lt;Product&gt;().Linq()&lt;br /&gt;               where p.CategoryName == "Seafood"&lt;br /&gt;               orderby p.ProductName&lt;br /&gt;               select new&lt;br /&gt;               {&lt;br /&gt;                   p.ProductID,&lt;br /&gt;                   p.ProductName,&lt;br /&gt;                   p.UnitPrice,&lt;br /&gt;                   p.CategoryName&lt;br /&gt;               };&lt;br /&gt;&lt;br /&gt;    Console.WriteLine("MongoDB Demo");&lt;br /&gt;    foreach (var item in list)&lt;br /&gt;    {&lt;br /&gt;        Console.WriteLine(&lt;br /&gt;            string.Format("{0}\t{1:c}\t{2}\t{3}",&lt;br /&gt;                item.ProductID,&lt;br /&gt;                item.UnitPrice,&lt;br /&gt;                item.ProductName,&lt;br /&gt;                item.CategoryName));&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;GetContext() is straight forward: You new-up a Mongo, connect and get a database.&lt;/p&gt;&lt;p&gt;The most interesting statement is mdb.GetCollection&lt;Product&gt;().Linq(). The GetCollection&lt;T&gt; method links the content with the name of T to an IMongoCollection of Ts. LinqExtensions.Linq() is an extension method that converts the IMongoCollection to IQueryable.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-4770258340320590982?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/4770258340320590982/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=4770258340320590982' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/4770258340320590982'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/4770258340320590982'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2010/10/adding-mongodb-samus-mongodb-csharp-to.html' title='Adding MongoDB samus / mongodb-csharp to the Linq Comparison'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-5310109361177718462</id><published>2010-09-30T19:05:00.000-07:00</published><updated>2011-04-09T06:47:00.857-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linq2Sql'/><category scheme='http://www.blogger.com/atom/ns#' term='Linq'/><category scheme='http://www.blogger.com/atom/ns#' term='Entity Framework'/><category scheme='http://www.blogger.com/atom/ns#' term='Linq2DataSet'/><title type='text'>Comparing different Linq Providers</title><content type='html'>&lt;p&gt;I’ve been playing with Linq and different "back ends" (not using "providers" since Linq to DataSets probably doesn’t qualify).&lt;/p&gt;&lt;p&gt; In all three examples below, I create the automatic default model with Northwind’s Products and Categories tables. The Linq queries require a join and a filter.&lt;/p&gt;&lt;h3&gt;Linq to DataSet&lt;/h3&gt;&lt;p&gt;Over the past year or so, I’ve been working fairly heavily what I call Linq To DataSets, you know, Linq on top of classic ADO.NET. I have written several blog entries and made a couple of Code Camp presentations on this subject.&lt;/p&gt;&lt;p&gt;What makes Linq to DataSets is that it uses a disconnected data model (data is eagerly loaded). &lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public static NorthwindDS CreateContext()&lt;br /&gt;{&lt;br /&gt;    NorthwindDS ds = new NorthwindDS();&lt;br /&gt;    using (var catda = new CategoriesTableAdapter())&lt;br /&gt;    {&lt;br /&gt;        catda.Fill(ds.Categories);&lt;br /&gt;    }&lt;br /&gt;    using (var proda = new ProductsTableAdapter())&lt;br /&gt;    {&lt;br /&gt;        proda.Fill(ds.Products);&lt;br /&gt;    }&lt;br /&gt;    return ds;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public static void DoDemo()&lt;br /&gt;{&lt;br /&gt;    var ds = CreateContext();&lt;br /&gt;    var list = from p in ds.Products&lt;br /&gt;             join c in ds.Categories on p.CategoryID equals c.CategoryID&lt;br /&gt;        where c.CategoryName == "Seafood"&lt;br /&gt;        orderby p.ProductName&lt;br /&gt;        select new&lt;br /&gt;        {&lt;br /&gt;            p.ProductID,&lt;br /&gt;            p.ProductName,&lt;br /&gt;            p.UnitPrice,&lt;br /&gt;            c.CategoryName&lt;br /&gt;        };&lt;br /&gt;&lt;br /&gt;        Console.WriteLine("DataSet Demo");&lt;br /&gt;        foreach (var item in list)&lt;br /&gt;        {&lt;br /&gt;            Console.WriteLine(&lt;br /&gt;                string.Format("{0}\t{1:c}\t{2}\t{3}", &lt;br /&gt;                    item.ProductID, &lt;br /&gt;                    item.UnitPrice,&lt;br /&gt;                    item.ProductName,&lt;br /&gt;                    item.CategoryName));&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;This one requires real code to load. And everything is loaded. If I need to, I can filter at the DataAdapter level, but that requires fancy Designer work.&lt;/p&gt;&lt;h3&gt;Linq to SQL&lt;/h3&gt;&lt;p&gt;On my last project, we used Linq to SQL. It is easy to develop and capable, but limited. You will use SQL Server, You will not use Stored Procedures to read and write data (it does have some stored procedure support, but not even to the level of Classic ADO.NET).&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public static NorthwindL2SDataContext CreateContext()&lt;br /&gt;{&lt;br /&gt;    return new NorthwindL2SDataContext();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public static void DoDemo()&lt;br /&gt;{&lt;br /&gt;    var context = CreateContext();&lt;br /&gt;    var list = from p in context.Products&lt;br /&gt;            join c in context.Categories on p.CategoryID equals c.CategoryID&lt;br /&gt;        where c.CategoryName == "Seafood"&lt;br /&gt;        orderby p.ProductName&lt;br /&gt;        select new&lt;br /&gt;        {&lt;br /&gt;            p.ProductID,&lt;br /&gt;            p.ProductName,&lt;br /&gt;            p.UnitPrice,&lt;br /&gt;            c.CategoryName&lt;br /&gt;        };&lt;br /&gt;&lt;br /&gt;    Console.WriteLine("Linq2Sql Demo");&lt;br /&gt;    foreach (var item in list)&lt;br /&gt;    {&lt;br /&gt;        Console.WriteLine(&lt;br /&gt;            string.Format("{0}\t{1:c}\t{2}\t{3}",&lt;br /&gt;                item.ProductID,&lt;br /&gt;                item.UnitPrice,&lt;br /&gt;                item.ProductName,&lt;br /&gt;                item.CategoryName));&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Creating the context in Linq to Sql is trivial, just new it up. The Linq is really similar to the Linq to DataSets that I’ve been working with for the last year.&lt;/p&gt;&lt;p&gt;The cool thing is that the data isn’t gotten until I ask for it in the Linq query and only the records I ask for. &lt;/p&gt;&lt;p&gt;Linq to Sql’s model is really close to the table structure of the underlining database. It is less capable than the Entity Framework (below), but it is also less complicated.&lt;/p&gt;&lt;h3&gt;Entity Framework&lt;/h3&gt;&lt;p&gt;I have also played with the Entity Framework. It is more powerful than the others but more difficult to use than the others. &lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public static NorthwindEntities CreateContext()&lt;br /&gt;{&lt;br /&gt;    return new NorthwindEntities();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public static void DoDemo()&lt;br /&gt;{&lt;br /&gt;    var ds = CreateContext();&lt;br /&gt;    var list = from p in ds.Products&lt;br /&gt;        where p.Categories.CategoryName == "Seafood"&lt;br /&gt;        orderby p.ProductName&lt;br /&gt;        select new&lt;br /&gt;        {&lt;br /&gt;            p.ProductID,&lt;br /&gt;            p.ProductName,&lt;br /&gt;            p.UnitPrice,&lt;br /&gt;            p.Categories.CategoryName&lt;br /&gt;        };&lt;br /&gt;&lt;br /&gt;    Console.WriteLine("EntityFramework Demo");&lt;br /&gt;    foreach (var item in list)&lt;br /&gt;    {&lt;br /&gt;        Console.WriteLine(&lt;br /&gt;            string.Format("{0}\t{1:c}\t{2}\t{3}",&lt;br /&gt;                item.ProductID,&lt;br /&gt;                item.UnitPrice,&lt;br /&gt;                item.ProductName,&lt;br /&gt;                item.CategoryName));&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Again it is simple to make a new context. &lt;/p&gt;&lt;p&gt;The Entity Framework supports lazy loading and using stored procedures for Insert, Update and Delete operations. &lt;/p&gt;&lt;p&gt;Notice that there is no join in this query, the Category is imbedded in to the Products. The Entity Framework can work with data models that differ from the underlining data store. &lt;/p&gt;&lt;p&gt;The same treatment is applied to &lt;a href="/2010/10/adding-mongodb-samus-mongodb-csharp-to.html"&gt;Mongo DB&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-5310109361177718462?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/5310109361177718462/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=5310109361177718462' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5310109361177718462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5310109361177718462'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2010/09/comparing-different-linq-providers-ive.html' title='Comparing different Linq Providers'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-1662319001781303404</id><published>2010-08-27T06:32:00.000-07:00</published><updated>2011-04-03T08:55:24.764-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VB.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><category scheme='http://www.blogger.com/atom/ns#' term='Macros'/><title type='text'>Quickly change Themes in Visual Studio 2008</title><content type='html'>&lt;p&gt;I like dark backgrounds when I code; my co-workers don’t. I want to be able to change the screen back and forth from Darkness and Light. So I created a couple of toolbar buttons to switch themes (don’t use the tool until I say you can do so).&lt;/p&gt;&lt;ol&gt;&lt;li&gt;I save my current theme (Tools =&gt; Import and Export Settings… =&gt; Export … =&gt; Next =&gt; Next =&gt; "C:\VS_Themes\Darkness.vssettings" =&gt; Finish).&lt;/li&gt;&lt;li&gt;Create a standard theme (Tools =&gt; Import and Export Settings… =&gt; Reset all Settings).&lt;/li&gt;&lt;li&gt;Save the standard theme (same steps as 1 but call it "C:\VS_Themes\Default.vssettings") &lt;/li&gt;&lt;li&gt;Open Macros IDE (((Alt+F11) || (Tools =&gt; Macros =&gt; Macros IDE …)) &lt;/li&gt;&lt;li&gt;Create a module (Right Click on MyMacros =&gt; Add =&gt; Add Module =&gt; Name it "LoadThemes") &lt;/li&gt;&lt;li&gt;Type the following VB.NET code into the module: &lt;/li&gt;&lt;pre class="prettyprint lang-vb"&gt;&lt;br /&gt;Public Module LoadThemes &lt;br /&gt;    Public Sub SetThemeToDarkness()&lt;br /&gt;        LoadThemeByFilename("C:\VS_Themes\Darkness.vssettings")&lt;br /&gt;    End Sub&lt;&lt;br /&gt;    Public Sub SetThemeToDefault()&lt;br /&gt;        LoadThemeByFilename("C:\VS_Themes\Default.vssettings")&lt;br /&gt;    End Sub&lt;&lt;br /&gt;    Private Sub LoadThemeByFilename(ByVal fileName As String)&lt;br /&gt;        DTE.ExecuteCommand("Tools.ImportandExportSettings", "/import:""" &amp;&lt;br /&gt;            fileName &amp; """")&lt;br /&gt;    End Sub&lt;br /&gt;End Module&lt;br /&gt;&lt;/pre&gt;&lt;li&gt;And I hooked them to buttons on my tookbar (Tools =&gt; Customize =&gt; New… "Theme" =&gt; Commands =&gt; Select Macros =&gt; Drag your macros onto the new Toolbar). &lt;/li&gt;&lt;li&gt;Resave the Darkness Theme (The toolbar is part of the theme, otherwise when you use the tool bar to switch themes, you will lose the toolbar) &lt;/li&gt;&lt;li&gt;Do the same thing for the Default Theme. &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Now you are set.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-1662319001781303404?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/1662319001781303404/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=1662319001781303404' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/1662319001781303404'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/1662319001781303404'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2010/08/quickly-change-themes-in-visual-studio.html' title='Quickly change Themes in Visual Studio 2008'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-7502199587037135495</id><published>2010-07-18T19:26:00.001-07:00</published><updated>2011-04-01T22:49:33.712-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Extension Methods'/><category scheme='http://www.blogger.com/atom/ns#' term='MDI'/><category scheme='http://www.blogger.com/atom/ns#' term='Generics'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Avoid Duplicate Detail Forms in MDI programs</title><content type='html'>&lt;p&gt;In a MDI Windows Forms/CRUD application, I don't want to display the same Detail form more than once at the same time. What if the user saves the address on one form and the email on another? Even if you can trust the user to do the right thing, it just feels icky to have more than 1 form for "John Smith" up at the same time.&lt;/p&gt;&lt;p&gt;It is less dangerous to have duplicate list forms, but I still don't like to gunk up the application with extra forms hanging around.&lt;/p&gt;&lt;p&gt;This code is a modernization of some code I used a couple of years ago. I am using Generics and Extension methods to reduce the amount of code I used in the old .NET 2.0 code!&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;using System.Windows.Forms;&lt;br /&gt;namespace AvoidDupeForms&lt;br /&gt;{&lt;br /&gt;    /// &amp;lt;summary&amp;gt;&lt;br /&gt;    /// A Detail Form is a form that can display a single record.&lt;br /&gt;    /// In this example, there can me more than 1 of these loaded&lt;br /&gt;    /// at once, as long as a record is only loaded once.&lt;br /&gt;    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;    public interface IDetailForm&lt;br /&gt;    {&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Get the Id loaded in this form&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        int Id { get; }&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Set the id for the form to load&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="id"&amp;gt;Id # to be loaded&amp;lt;/param&amp;gt;&lt;br /&gt;        void SetId(int id);&lt;br /&gt;    }&lt;br /&gt;    public static class FormsUtil&lt;br /&gt;    {&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Reveal a form, load a new one if one doesn't yet exist &lt;br /&gt;        /// in the context of this MDI &lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        /// &amp;lt;typeparam name="T"&amp;gt;The type of the form to be revealed&amp;lt;/typeparam&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="thisForm"&amp;gt;&lt;br /&gt;        /// The calling form (used to get MdiParent to be searched)&lt;br /&gt;        /// &amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;example&amp;gt;&lt;br /&gt;        /// &amp;lt;![CDATA[&lt;br /&gt;        /// // As an extention method&lt;br /&gt;        /// this.RevealForm&amp;lt;ListForm&amp;gt;();&lt;br /&gt;        /// // The oldfashioned way&lt;br /&gt;        /// FormsUtil.RevealForm&amp;lt;ListForm&amp;gt;(this);&lt;br /&gt;        /// ]]&amp;gt;&lt;br /&gt;        /// &amp;lt;/example&amp;gt;&lt;br /&gt;        public static void RevealForm&amp;lt;T&amp;gt;(this Form thisForm) &lt;br /&gt;            where T : Form, new()&lt;br /&gt;        {&lt;br /&gt;            Form MdiParent = thisForm.GetMdiParent();&lt;br /&gt;            if (MdiParent != null)&lt;br /&gt;            {&lt;br /&gt;                foreach (Form frm in MdiParent.MdiChildren)&lt;br /&gt;                {&lt;br /&gt;                    if (frm.GetType() == typeof(T))&lt;br /&gt;                    {&lt;br /&gt;                        frm.BringToFront();&lt;br /&gt;                        return;&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;                T flf = new T();&lt;br /&gt;                flf.MdiParent = MdiParent;&lt;br /&gt;                flf.Show();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Reveal a form with a given detailId, load a new one if &lt;br /&gt;        /// one doesn't yet exist in the context of this MDI &lt;br /&gt;        /// NOTE: &amp;gt; 1 instance of T can exist, but only&lt;br /&gt;        /// 1 fore each IDetailForm.Id&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        /// &amp;lt;typeparam name="T"&amp;gt;The type of the form to be revealed&amp;lt;/typeparam&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="thisForm"&amp;gt;&lt;br /&gt;        /// The calling form (used to get MdiParent to be searched)&lt;br /&gt;        /// &amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="detailId"&amp;gt;The ID of the Detail record to be displayed&amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;example&amp;gt;&lt;br /&gt;        /// &amp;lt;![CDATA[&lt;br /&gt;        /// // As an extention method&lt;br /&gt;        /// this.RevealDetailForm&amp;lt;DetailForm&amp;gt;(42);&lt;br /&gt;        /// // The oldfashioned way&lt;br /&gt;        /// FormsUtil.RevealDetailForm&amp;lt;DetailForm&amp;gt;(this, 42);&lt;br /&gt;        /// ]]&amp;gt;&lt;br /&gt;        /// &amp;lt;/example&amp;gt;&lt;br /&gt;        public static void RevealDetailForm&amp;lt;T&amp;gt;(this Form thisForm, int detailId) &lt;br /&gt;            where T : Form, IDetailForm, new()&lt;br /&gt;        {&lt;br /&gt;            Form MdiParent = thisForm.GetMdiParent();&lt;br /&gt;            if (MdiParent != null)&lt;br /&gt;            {&lt;br /&gt;                foreach (Form frm in MdiParent.MdiChildren)&lt;br /&gt;                {&lt;br /&gt;                    if (frm.GetType() == typeof(T))&lt;br /&gt;                    {&lt;br /&gt;                        T saFrm = (T)frm;&lt;br /&gt;                        if (saFrm.Id == detailId)&lt;br /&gt;                        {&lt;br /&gt;                            saFrm.BringToFront();&lt;br /&gt;                            return;&lt;br /&gt;                        }&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;                T modify = new T();&lt;br /&gt;                modify.MdiParent = MdiParent;&lt;br /&gt;                modify.SetId(detailId);&lt;br /&gt;                modify.Show();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Gets the MdiParent for a given form&lt;br /&gt;        /// (it could be self)&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="thisForm"&amp;gt;&lt;br /&gt;        /// The calling form (used to get MdiParent to be searched)&lt;br /&gt;        /// &amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;returns&amp;gt;&lt;br /&gt;        /// The MdiParent of thisForm, or null if thisForm has no parent&lt;br /&gt;        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;        /// &amp;lt;example&amp;gt;&lt;br /&gt;        /// &amp;lt;![CDATA[&lt;br /&gt;        /// // As an extention method&lt;br /&gt;        /// Form MdiParent = thisForm.getMdiContainer();&lt;br /&gt;        /// // The oldfashioned way&lt;br /&gt;        /// Form MdiParent = FormsUtil.getMdiContainer(thisForm);&lt;br /&gt;        /// ]]&amp;gt;&lt;br /&gt;        /// &amp;lt;/example&amp;gt;&lt;br /&gt;        public static Form GetMdiParent(this Form thisForm)&lt;br /&gt;        {&lt;br /&gt;            if (thisForm.IsMdiContainer)&lt;br /&gt;                return thisForm;&lt;br /&gt;            if (thisForm.IsMdiChild)&lt;br /&gt;                return thisForm.MdiParent;&lt;br /&gt;            return null;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-7502199587037135495?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/7502199587037135495/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=7502199587037135495' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/7502199587037135495'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/7502199587037135495'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2010/07/avoid-duplicate-detail-forms-in-mdi.html' title='Avoid Duplicate Detail Forms in MDI programs'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-4623217285554420206</id><published>2010-06-26T08:39:00.000-07:00</published><updated>2011-01-04T20:15:30.399-08:00</updated><title type='text'>Back in Time</title><content type='html'>&lt;p&gt;I took this picture this year on Indiana Street in Spokane. &lt;/p&gt;&lt;br /&gt;&lt;a href='http://4.bp.blogspot.com/_VtUEHupKsDM/TCYfSqcFOgI/AAAAAAAAAII/NLyUZBqj3lU/s1600/IMG_0459.JPG'&gt;&lt;img src='http://4.bp.blogspot.com/_VtUEHupKsDM/TCYfSqcFOgI/AAAAAAAAAII/NLyUZBqj3lU/s320/IMG_0459.JPG' border='0' alt=''style='clear:both;float:left; margin:0px 10px 10px 0;' /&gt;&lt;/a&gt;&amp;nbsp;&lt;div style='clear:both; text-align:LEFT'&gt;&lt;a href='http://picasa.google.com/blogger/' target='ext'&gt;&lt;img src='http://photos1.blogger.com/pbp.gif' alt='Posted by Picasa' style='border: 0px none ; padding: 0px; background: transparent none repeat scroll 0% 50%; -moz-background-clip: initial; -moz-background-origin: initial; -moz-background-inline-policy: initial;' align='middle' border='0' /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-4623217285554420206?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/4623217285554420206/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=4623217285554420206' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/4623217285554420206'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/4623217285554420206'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2010/06/back-in-time-i-took-this-picture-this.html' title='Back in Time'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_VtUEHupKsDM/TCYfSqcFOgI/AAAAAAAAAII/NLyUZBqj3lU/s72-c/IMG_0459.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-2298226040162405173</id><published>2010-06-05T19:34:00.000-07:00</published><updated>2011-01-04T20:16:00.267-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Non-Technical'/><category scheme='http://www.blogger.com/atom/ns#' term='Twitter'/><category scheme='http://www.blogger.com/atom/ns#' term='Polls'/><title type='text'>Unscientific polling in the internet</title><content type='html'>&lt;p&gt;I see the following tweet:&lt;br /&gt;&lt;pre&gt;@ChrisLove: Do You Prefer a Stick Shift or Automatic? &lt;br /&gt;[Stick Shift: http://twp.li/6lbj || Automatic: http://twp.li/p8y4 ]&lt;br /&gt;#twittpoll&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;(I really like the way he used “||” instead of “or”.) Being a stick shift enthusiast (ok weirdo), I clicked on http://twp.li/6lbj without thinking about it; when the page loaded I saw that the stick shift was beating automatic 80 to 20. This doesn’t match what I see in the world.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The problem is that people who prefer stick care deeply, but people who prefer automatic don’t feel strongly about their preference (unless they are forced to drive a stick).&lt;br /&gt;&lt;/p&gt;&lt;p&gt;This example is probably harmless. However, both the Republicans and Democrats in the US are using this kind of polling to push their point of view.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-2298226040162405173?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/2298226040162405173/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=2298226040162405173' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2298226040162405173'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2298226040162405173'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2010/06/unscientific-polling-in-internet-i-see.html' title='Unscientific polling in the internet'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-8850776099371038155</id><published>2010-05-17T19:25:00.000-07:00</published><updated>2011-01-07T06:24:32.260-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Code Camp'/><category scheme='http://www.blogger.com/atom/ns#' term='Portland Code Camp'/><category scheme='http://www.blogger.com/atom/ns#' term='Linq2DataSet'/><title type='text'>Portland Code Camp and Me</title><content type='html'>&lt;p&gt;I will be presenting &lt;a href="http://portlandcodecamp.org/2010/Sessions/Details/38"&gt;Introduction to Linq and Linq2DataSets&lt;/A&gt; an the &lt;a href="http://portlandcodecamp.org"&gt;Portland Code Camp&lt;/a&gt; from 9:00 to 10:15 AM on Saturday, May 22, 2010 (Session 0x01) in Room 13.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-8850776099371038155?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/8850776099371038155/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=8850776099371038155' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/8850776099371038155'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/8850776099371038155'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2010/05/portland-code-camp-and-me-i-will-be.html' title='Portland Code Camp and Me'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-8402180765918552678</id><published>2010-04-08T22:03:00.000-07:00</published><updated>2011-01-07T06:25:06.222-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Boise Code Camp'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Camp'/><category scheme='http://www.blogger.com/atom/ns#' term='Linq2DataSet'/><title type='text'>My Boise Code Camp Presentation Notes Are Available</title><content type='html'>&lt;p&gt;The Notes from my March 27, 2010 &lt;a href="http://www.boisecodecamp.org"&gt;Boise Code Camp&lt;/a&gt; presentation are now on line &lt;a href="http://www.boisecodecamp.org/Portals/0/BCC/SpeakerMaterial/2010/linq2datasets-boise-2010.zip"&gt;here&lt;/a&gt;!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-8402180765918552678?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/8402180765918552678/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=8402180765918552678' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/8402180765918552678'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/8402180765918552678'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2010/04/my-boise-code-camp-presentation-notes.html' title='My Boise Code Camp Presentation Notes Are Available'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-6425112978014429070</id><published>2010-03-30T18:00:00.000-07:00</published><updated>2011-01-07T06:25:34.245-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Boise Code Camp'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Camp'/><category scheme='http://www.blogger.com/atom/ns#' term='Linq2DataSet'/><title type='text'>My Boise Code Camp Presentation Notes</title><content type='html'>&lt;p&gt;If you are looking for my Linq2DataSets presentation from Saturday's code camp, I am in the progress of getting them ready and finding a place to post item.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-6425112978014429070?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/6425112978014429070/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=6425112978014429070' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/6425112978014429070'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/6425112978014429070'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2010/03/my-boise-code-camp-presentation-notes.html' title='My Boise Code Camp Presentation Notes'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-2520285392771733260</id><published>2010-03-15T20:05:00.000-07:00</published><updated>2011-04-01T22:52:29.167-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VB.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Nortwind'/><category scheme='http://www.blogger.com/atom/ns#' term='Linq2DataSet'/><title type='text'>Group By doesn’t appear to work in Linq2DataSet</title><content type='html'>&lt;p&gt;As I’m working on my presentation for &lt;a href="http://www.boisecodecamp.org/"&gt;Boise Code Camp&lt;/a&gt;, I’ve come across some issues trying to demonstrate Group By. I haven’t been able to make a Group By query work. When I run the same query using Linq2Sql, it works just fine.&lt;/p&gt;&lt;p&gt;For example, given the following code (in VB 10):&lt;/p&gt;&lt;pre class="prettyprint lang-vb"&gt;&lt;br /&gt;Dim MyList = From o In myData.Orders _&lt;br /&gt;    Join od In myData.Order_Details On o.OrderID Equals od.OrderID _&lt;br /&gt;    Join e In myData.Employees On o.EmployeeID Equals e.EmployeeID _&lt;br /&gt;    Group By FullOrder = New With _&lt;br /&gt;        { _&lt;br /&gt;            .OrderId = od.OrderID, _&lt;br /&gt;            .EmployeeName = (e.FirstName &amp; " " &amp; e.LastName), _&lt;br /&gt;            .ShipCountry = o.ShipCountry, _&lt;br /&gt;            .OrderDate = o.OrderDate _&lt;br /&gt;        } _&lt;br /&gt;    Into Amount = Sum(od.Quantity * od.UnitPrice) _&lt;br /&gt;    Where FullOrder.ShipCountry = "USA" _&lt;br /&gt;    Order By FullOrder.OrderId _&lt;br /&gt;    Select FullOrder.OrderId, _&lt;br /&gt;        FullOrder.OrderDate, _&lt;br /&gt;        FullOrder.EmployeeName, _&lt;br /&gt;        Amount&lt;br /&gt;&lt;br /&gt;For Each x In MyList&lt;br /&gt;    Console.WriteLine( _&lt;br /&gt;        String.Format( _&lt;br /&gt;           "{0}; {1:d}; {2}: {3:c}", _&lt;br /&gt;           x.OrderId, _&lt;br /&gt;           x.OrderDate, _&lt;br /&gt;           x.EmployeeName, _&lt;br /&gt;           x.Amount))&lt;br /&gt;Next&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;When myData is a DataSet: I get:&lt;/p&gt;&lt;pre&gt;10262; 7/22/1996; Laura Callahan: $204.00&lt;br /&gt;10262; 7/22/1996; Laura Callahan: $360.00&lt;br /&gt;10262; 7/22/1996; Laura Callahan: $60.80&lt;br /&gt;10269; 7/31/1996; Steven Buchanan: $120.00&lt;br /&gt;10269; 7/31/1996; Steven Buchanan: $556.00&lt;br /&gt;10271; 8/1/1996; Michael Suyama: $48.00&lt;br /&gt;10272; 8/2/1996; Michael Suyama: $388.80&lt;br /&gt;10272; 8/2/1996; Michael Suyama: $400.00&lt;br /&gt;10272; 8/2/1996; Michael Suyama: $667.20&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;There is more than 1 entry for each OrderId, the query failed to group properly. Order 10262 has 3 lines corresponding to the 3 line items of the order.&lt;/p&gt;&lt;p&gt;If I run the same Linq query with myData as a Linq2Sql DataContext, I get:&lt;/p&gt;&lt;pre&gt;10262; 7/22/1996; Laura Callahan: $624.80&lt;br /&gt;10269; 7/31/1996; Steven Buchanan: $676.00&lt;br /&gt;10271; 8/1/1996; Michael Suyama: $48.00&lt;br /&gt;10272; 8/2/1996; Michael Suyama: $1,456.00&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Here everything is grouped together and Amount is totaled. Order 10262 has 1 entry as I would expect.&lt;/p&gt;&lt;p&gt;There may be a slightly more complex way to make this query work using the DataSet and I haven’t found it, but right now, it doesn’t look good for Linq2DataSets in this area.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-2520285392771733260?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/2520285392771733260/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=2520285392771733260' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2520285392771733260'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2520285392771733260'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2010/03/group-by-doesnt-appear-to-work-in.html' title='Group By doesn’t appear to work in Linq2DataSet'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-5029520433289033565</id><published>2010-02-23T19:48:00.000-08:00</published><updated>2011-04-01T22:58:55.737-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Nortwind'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Object Graphs'/><category scheme='http://www.blogger.com/atom/ns#' term='Linq2DataSet'/><title type='text'>Loading Object Graphs with Linq2DataSets</title><content type='html'>&lt;p&gt;The data base likes to keep data in relational tables and the middle tier likes to present the data in object graphs where the details are stored within the patient object, so everything is close at hand. So how do you transform the data from tables to graphs? I use Linq2DataSets.&lt;/p&gt;&lt;h3&gt;The Stored Procedure&lt;/h3&gt;&lt;p&gt;Suppose you are asked to load an object graph with the following stored procedure (using Northwind, my favorite database of all times):&lt;/p&gt;&lt;pre class="prettyprint"&gt;-- This procedure returns 2 results sets the first includes all of the Orders and &lt;br /&gt;-- the second all of the Order Details (regardless of order).&lt;br /&gt;CREATE PROCEDURE dbo.GetAllOrders&lt;br /&gt;AS&lt;br /&gt;SELECT o.OrderID, o.CustomerID, o.EmployeeID, o.OrderDate, o.RequiredDate, &lt;br /&gt;    o.ShippedDate, o.ShipVia, o.Freight, o.ShipName, o.ShipAddress, o.ShipCity, &lt;br /&gt;    o.ShipRegion, o.ShipPostalCode, o.ShipCountry &lt;br /&gt;  FROM [Orders] o&lt;br /&gt;&lt;br /&gt;SELECT od.OrderID, od.ProductID, od.UnitPrice, od.Quantity, od.Discount&lt;br /&gt;  FROM [Order Details] od&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;In real life, I would probably have parameters to limit the result sets to the data that I really want. For the purpose of demonstration, it is helpful to process a lot of data.&lt;/p&gt;&lt;h3&gt;Getting the data into the Object Graphs&lt;/h3&gt;&lt;p&gt;Now, suppose you want to load this data into Object Graphs. In my example, I have an Order class that includes a list of its Order Details (a real production SP would probably include parameters to filter the data returned; you don’t want to load all the orders for a real company).&lt;/p&gt;&lt;p&gt;The SP returns the two lists that you will have to stitch together yourself in code:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// Loads all the orders into a list of Order objects&lt;br /&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;public static List&lt;Order&gt; GetAllOrders(OrderDS ds)&lt;br /&gt;{&lt;br /&gt;    return new List&lt;Order&gt;(&lt;br /&gt;        from orders in ds.Orders&lt;br /&gt;        select new Order(&lt;br /&gt;            orders.OrderID,&lt;br /&gt;            orders.CustomerID,&lt;br /&gt;            orders.EmployeeID,&lt;br /&gt;            orders.OrderDate,&lt;br /&gt;            orders.RequiredDate,&lt;br /&gt;            !orders.IsShippedDateNull() ? orders.ShippedDate : (DateTime?)null,&lt;br /&gt;            orders.ShipVia,&lt;br /&gt;            orders.Freight,&lt;br /&gt;            orders.ShipName,&lt;br /&gt;            orders.ShipAddress,&lt;br /&gt;            orders.ShipCity,&lt;br /&gt;            !orders.IsShipRegionNull() ? orders.ShipRegion : string.Empty,&lt;br /&gt;            !orders.IsShipPostalCodeNull() ? orders.ShipPostalCode : string.Empty,&lt;br /&gt;            orders.ShipCountry,&lt;br /&gt;            getOrderDetails(orders.OrderID, ds)));&lt;br /&gt;}&lt;br /&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// Loads the order details associated with a given order into a list of &lt;br /&gt;/// OrderDetal objects&lt;br /&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;public static List&lt;OrderDetail&gt; getOrderDetails(int orderId, OrderDS ds)&lt;br /&gt;{&lt;br /&gt;    return new List&lt;OrderDetail&gt;(&lt;br /&gt;        from orderDetails in ds.OrderDetails&lt;br /&gt;        where orderDetails.OrderID == orderId&lt;br /&gt;        select new OrderDetail(&lt;br /&gt;            orderDetails.OrderID,&lt;br /&gt;            orderDetails.ProductID,&lt;br /&gt;            orderDetails.UnitPrice,&lt;br /&gt;            orderDetails.Quantity,&lt;br /&gt;            orderDetails.Discount));&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;From the above code, I would like to point out&lt;ul&gt;&lt;li&gt;GetAllOrders() calls getOrderDetails() from within the linq query. When you call the Orders constructor, you can call any code you would call in any other constructor. &lt;/li&gt;&lt;li&gt;Even though I’m in the middle of a Linq query in GetAllOrders(), I can create a second Linq query in getOrderDetails using the same DataSet.&lt;/li&gt;&lt;li&gt;Since we are using DataSets and other classic ADO.NET objects, we need to call IsFooNullable() to avoid an InvalidCastException. &lt;/li&gt;&lt;li&gt;When I’m passing null to the Order constructor, I need to cast it to the correct type.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Appendix&lt;/h3&gt;&lt;p&gt;Here are the classes that I loaded the in the code above&lt;/p&gt;&lt;pre class="prettyprint"&gt;public class Order&lt;br /&gt;{&lt;br /&gt;    public int OrderID { get; set; }&lt;br /&gt;    public string CustomerID { get; set; }&lt;br /&gt;    public int EmployeeID { get; set; }&lt;br /&gt;    public DateTime OrderDate { get; set; }&lt;br /&gt;    public DateTime RequiredDate { get; set; }&lt;br /&gt;    public DateTime? ShippedDate { get; set; }&lt;br /&gt;    public int ShipVia { get; set; }&lt;br /&gt;    public decimal Freight { get; set; }&lt;br /&gt;    public string ShipName { get; set; }&lt;br /&gt;    public string ShipAddress { get; set; }&lt;br /&gt;    public string ShipCity { get; set; }&lt;br /&gt;    public string ShipRegion { get; set; }&lt;br /&gt;    public string ShipPostalCode { get; set; }&lt;br /&gt;    public string ShipCountry { get; set; }&lt;br /&gt;    public List&lt;OrderDetail&gt; Details { get; set; }&lt;br /&gt;&lt;br /&gt;    public Order(int orderID, string customerID, int employeeID, DateTime orderDate, &lt;br /&gt;        DateTime requiredDate, DateTime? shippedDate, int shipVia, decimal freight, &lt;br /&gt;        string shipName, string shipAddress, string shipCity, string shipRegion, &lt;br /&gt;        string shipPostalCode, string shipCountry, List&lt;OrderDetail&gt; details)&lt;br /&gt;    {&lt;br /&gt;        this.OrderID = orderID;&lt;br /&gt;        this.CustomerID = customerID;&lt;br /&gt;        this.EmployeeID = employeeID;&lt;br /&gt;        this.OrderDate = orderDate;&lt;br /&gt;        this.RequiredDate = requiredDate;&lt;br /&gt;        this.ShippedDate = shippedDate;&lt;br /&gt;        this.ShipVia = shipVia;&lt;br /&gt;        this.Freight = freight;&lt;br /&gt;        this.ShipName = shipName;&lt;br /&gt;        this.ShipAddress = shipAddress;&lt;br /&gt;        this.ShipCity = shipCity;&lt;br /&gt;        this.ShipRegion = shipRegion;&lt;br /&gt;        this.ShipPostalCode = shipPostalCode;&lt;br /&gt;        this.ShipCountry = shipCountry;&lt;br /&gt;        this.Details = details;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;public class OrderDetail&lt;br /&gt;{&lt;br /&gt;    public int OrderID { get; set; }&lt;br /&gt;    public int ProductID { get; set; }&lt;br /&gt;    public decimal UnitPrice { get; set; }&lt;br /&gt;    public int Quantity { get; set; }&lt;br /&gt;    public float Discount { get; set; }&lt;br /&gt;&lt;br /&gt;    public OrderDetail(int orderID, int productID, decimal unitPrice, int quantity, &lt;br /&gt;        float discount)&lt;br /&gt;    {&lt;br /&gt;        this.OrderID = orderID;&lt;br /&gt;        this.ProductID = productID;&lt;br /&gt;        this.UnitPrice = unitPrice;&lt;br /&gt;        this.Quantity = quantity;&lt;br /&gt;        this.Discount = discount;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;And GetDataSet() the function that loads the DataSet&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// Loads OrderDS using the SP GetAllOrders&lt;br /&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;public static OrderDS GetDataSet()&lt;br /&gt;{&lt;br /&gt;    var ds = new OrderDS();&lt;br /&gt;    SqlConnection conn = new SqlConnection(CONNECTION_STRING);&lt;br /&gt;&lt;br /&gt;    using (SqlCommand cmd = new SqlCommand("GetAllOrders", conn))&lt;br /&gt;    {&lt;br /&gt;        cmd.CommandType = System.Data.CommandType.StoredProcedure;&lt;br /&gt;&lt;br /&gt;        SqlDataAdapter DA = new SqlDataAdapter(cmd);&lt;br /&gt;        DA.TableMappings.Add("Table", "Orders");&lt;br /&gt;        DA.TableMappings.Add("Table1", "OrderDetails");&lt;br /&gt;&lt;br /&gt;        DA.Fill(ds);&lt;br /&gt;    }&lt;br /&gt;    return ds;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Since I’m too lazy to do graphics on this blog, I will leave it to the reader to make the actual DataSet.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-5029520433289033565?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/5029520433289033565/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=5029520433289033565' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5029520433289033565'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5029520433289033565'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2010/02/loading-object-graphs-with.html' title='Loading Object Graphs with Linq2DataSets'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-6517340653930904521</id><published>2010-02-21T21:20:00.000-08:00</published><updated>2011-04-01T23:02:01.260-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Code Generation'/><category scheme='http://www.blogger.com/atom/ns#' term='System Tables'/><category scheme='http://www.blogger.com/atom/ns#' term='Nortwind'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Generate Stored Procedures with data from SQL Server System Tables</title><content type='html'>&lt;p&gt;Here’s an experiment I wrote over the weekend to create an Insert SP for a table using &lt;a href="http://msdn.microsoft.com/en-us/library/aa260604(SQL.80).aspx"&gt;SQL Server System Tables&lt;/a&gt;. &lt;/p&gt;&lt;p&gt;This code generates code for a specific code pattern and won’t necessarily work for any table that is thrown at it. Supporting every possible situation can make the code really complex. If I am faced with a table that this can’t handle, I am face with the choice of expanding the program to handle the new situation or write the code by hand. &lt;/p&gt;&lt;p&gt;These SPs are the same except for:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The SP name – Based on Table Name&lt;/li&gt;&lt;li&gt;The Table Name&lt;/li&gt;&lt;li&gt;The Fields&lt;/li&gt;&lt;li&gt;Which Field is the Primary Key&lt;/li&gt;&lt;li&gt;Which Fields are Nullable&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;From the System Tables I use:&lt;/p&gt;&lt;ul&gt;&lt;/li&gt;&lt;li&gt;sysObjects.name: the name of the table&lt;/li&gt;&lt;li&gt;sysColumns.name: the column name&lt;/li&gt;&lt;li&gt;sysTypes.name: the type name&lt;/li&gt;&lt;li&gt;sysColumns.length: the length of the field&lt;/li&gt;&lt;li&gt;sysColumns.isnullable: is the field nullable?&lt;/li&gt;&lt;li&gt;sysColumns.status: used to determine if this is the primary key/auto-number column (look for 0x80)&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;The Code&lt;/h3&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Data.SqlClient;&lt;br /&gt;using System.Text;&lt;br /&gt;&lt;br /&gt;namespace GenerateSP&lt;br /&gt;{&lt;br /&gt;    class Program&lt;br /&gt;    {&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// The Connection String&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        private const string CONNECTION_STRING = @"Data Source=localhost\SQLEXPRESS;" + &lt;br /&gt;             "Initial Catalog=Northwind;Integrated Security=True";&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Number of list items per line in the generated procedure&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        private const int ITEMS_PER_LINE = 5;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Shows the Code Generation in action&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        static void Main(string[] args)&lt;br /&gt;        {&lt;br /&gt;            Console.WriteLine(CreateInsertSp("Employees"));&lt;br /&gt;            Console.ReadKey();&lt;br /&gt;        }&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Creates an INSERT Stored Procedure for a given table as a string&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        public static string CreateInsertSp(string tableName)&lt;br /&gt;        {&lt;br /&gt;            string identityField = string.Empty;&lt;br /&gt;            // There are 3 places in the SP that refer to the field names&lt;br /&gt;            // so I am using 3 string builders to generate those parts&lt;br /&gt;            // of the SP;&lt;br /&gt;            StringBuilder parametersSb = new StringBuilder();&lt;br /&gt;            StringBuilder InsertValueListSb = new StringBuilder();&lt;br /&gt;            StringBuilder InsertFieldListSb = new StringBuilder();&lt;br /&gt;            using (SqlConnection conn = new SqlConnection(CONNECTION_STRING))&lt;br /&gt;            {&lt;br /&gt;                int lineNumber = 0; // Used to &lt;br /&gt;                SqlDataReader reader = GetTableDefReader(tableName, conn);&lt;br /&gt;                while (reader.Read())&lt;br /&gt;                {&lt;br /&gt;                    string colName = reader.GetString(0);&lt;br /&gt;                    string typeName = reader.GetString(1);&lt;br /&gt;                    int length = reader.GetInt32(2);&lt;br /&gt;                    int isNullable = reader.GetInt32(3);&lt;br /&gt;                    int status = reader.GetInt32(4);&lt;br /&gt;&lt;br /&gt;                    AddToParameterSb(parametersSb, colName, typeName, length, &lt;br /&gt;&lt;br /&gt;                        isNullable, status);&lt;br /&gt;                    if (status == 0x80)&lt;br /&gt;                        identityField = colName;&lt;br /&gt;                    else&lt;br /&gt;                    {&lt;br /&gt;                        lineNumber++;&lt;br /&gt;                        AddInsertFieldListToSb(InsertFieldListSb, colName, lineNumber);&lt;br /&gt;                        AddInsertValueListToSb(InsertValueListSb, colName, lineNumber);&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            // Put everything together&lt;br /&gt;            return&lt;br /&gt;                string.Format("\nCREATE PROCEDURE [dbo].[Insert{0}]\n", tableName) +&lt;br /&gt;                parametersSb.ToString() +&lt;br /&gt;                string.Format("\nAS\n\nINSERT INTO [{0}] (", tableName) +&lt;br /&gt;                InsertFieldListSb.ToString() +&lt;br /&gt;                string.Format(")\nVALUES (") +&lt;br /&gt;                InsertValueListSb.ToString() +&lt;br /&gt;                string.Format(")\n\nSET @{0} = @@IDENTITY\n\nGO\n", identityField);&lt;br /&gt;        }&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Gets a DataReader containing selected column information for all of the &lt;br /&gt;        /// columns in the indecated table from SQL Server System Tables &lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;&lt;br /&gt;        private static SqlDataReader GetTableDefReader(string tableName, &lt;br /&gt;&lt;br /&gt;            SqlConnection conn)&lt;br /&gt;        {&lt;br /&gt;            SqlDataReader reader;&lt;br /&gt;            string getDataForTable =&lt;br /&gt;                "SELECT c.name AS col_name, " +&lt;br /&gt;                "   t.name AS type_name, " +&lt;br /&gt;                "   CAST(c.length AS INT) AS length, " +&lt;br /&gt;                "   c.isnullable, " +&lt;br /&gt;                "   CAST(c.status AS INT) AS status " +&lt;br /&gt;                "FROM " +&lt;br /&gt;                "  sysObjects o " +&lt;br /&gt;                "  JOIN sysColumns c ON c.id = o.id " +&lt;br /&gt;                "  JOIN systypes t on c.xtype = t.xtype AND t.status = 0 " +&lt;br /&gt;                "WHERE o.name = @tableName " +&lt;br /&gt;                "ORDER BY c.colid ";&lt;br /&gt;            using (SqlCommand cmd = new SqlCommand(getDataForTable, conn))&lt;br /&gt;            {&lt;br /&gt;                cmd.Parameters.AddWithValue("@tableName", tableName);&lt;br /&gt;                conn.Open();&lt;br /&gt;                reader = cmd.ExecuteReader();&lt;br /&gt;            }&lt;br /&gt;            return reader;&lt;br /&gt;        }&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Adds the current field to the &lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        private static void AddToParameterSb(StringBuilder sb, string colName, &lt;br /&gt;             string typeName, int length, int isNullable, int status)&lt;br /&gt;        {&lt;br /&gt;            if (sb.Length &amp;gt; 0)&lt;br /&gt;                sb.Append(",\n");&lt;br /&gt;            sb.AppendFormat("\t@{0} ", colName);&lt;br /&gt;            switch (typeName.ToLower())&lt;br /&gt;            {&lt;br /&gt;                case "varchar":&lt;br /&gt;                case "nvarchar":&lt;br /&gt;                    string lenString = length.ToString();&lt;br /&gt;                    if (length == -1)&lt;br /&gt;                        lenString = "MAX";&lt;br /&gt;                    sb.AppendFormat("{0}({1})", typeName, lenString);&lt;br /&gt;                    break;&lt;br /&gt;                default:&lt;br /&gt;                    sb.Append(typeName);&lt;br /&gt;                    break;&lt;br /&gt;            }&lt;br /&gt;            if (status == 0x80)&lt;br /&gt;                sb.Append(" OUT");&lt;br /&gt;            else if (isNullable != 0)&lt;br /&gt;                sb.Append(" = NULL");&lt;br /&gt;        }&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Adds the current field to the VALUES list for an INSERT query&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        private static void AddInsertValueListToSb(StringBuilder sb, string colName, &lt;br /&gt;            int lineNumber)&lt;br /&gt;        {&lt;br /&gt;            AddListSeperatorToSb(sb, lineNumber);&lt;br /&gt;            sb.AppendFormat("@{0}", colName);&lt;br /&gt;        }&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Adds the current field to the Field list for an INSERT query&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;&lt;br /&gt;        private static void AddInsertFieldListToSb(StringBuilder sb, string colName, &lt;br /&gt;            int lineNumber)&lt;br /&gt;        {&lt;br /&gt;            AddListSeperatorToSb(sb, lineNumber);&lt;br /&gt;            sb.AppendFormat("[{0}]", colName);&lt;br /&gt;        }&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Adds the comma and or new line to the list StringBuilder&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        /// &amp;lt;remarks&amp;gt;&lt;br /&gt;        /// Shouldn't have a comma before the first item in the list.&amp;lt;br /&amp;gt;&lt;br /&gt;        /// Should only insert new ine after each ITEMS_PER_LINE items&lt;br /&gt;        /// &amp;lt;/remarks&amp;gt;&lt;br /&gt;        private static void AddListSeperatorToSb(StringBuilder sb, int lineNumber)&lt;br /&gt;        {&lt;br /&gt;            if (sb.Length &amp;gt; 0)&lt;br /&gt;                sb.Append(", ");&lt;br /&gt;            if ((lineNumber % ITEMS_PER_LINE) == 0)&lt;br /&gt;                sb.Append("\n\t");&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;I adapted this code for T4 Templates &lt;a href="http://jrcs3.blogspot.com/2011/02/four-styles-of-t4-template-code.html"&gt;here&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-6517340653930904521?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/6517340653930904521/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=6517340653930904521' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/6517340653930904521'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/6517340653930904521'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2010/02/generate-stored-procedures-with-data.html' title='Generate Stored Procedures with data from SQL Server System Tables'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-2821486304683630542</id><published>2010-01-30T17:18:00.001-08:00</published><updated>2011-03-31T20:45:44.659-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Nortwind'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='DataView'/><category scheme='http://www.blogger.com/atom/ns#' term='Linq2DataSet'/><title type='text'>Linq2DataSet replaces the DataView</title><content type='html'>&lt;p&gt;Remember the ADO.NET DataView? It is the old-fashioned way to filter an existing DataSet from the days of ADO.NET 1.0. They are useful for filtering and sorting DataSets that you already have on hand for other reasons. &lt;br /&gt;&lt;/p&gt;&lt;p&gt;Let’s say you want a list of all the Northwind employees who live in the United States sorted by LastName:&lt;br /&gt;&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;// If you use DataSets you can probably write your own EmployeeDS &amp;amp; SetupData():&lt;br /&gt;EmployeeDS db = SetupData();&lt;br /&gt;&lt;br /&gt;// Filter by Country = “USA”: Sort by LastName&lt;br /&gt;DataView dv = new DataView(&lt;br /&gt;    db.Employees,&lt;br /&gt;    "Country = 'USA'",  // The Filter&lt;br /&gt;    "LastName",  // Sort Order&lt;br /&gt;    DataViewRowState.CurrentRows);&lt;br /&gt;&lt;br /&gt;// the DataView consists of a collection of DataRowView, so you have to cast back&lt;br /&gt;// to get to the strongly typed DataRows EmployeeDS.EmployeesRow&lt;br /&gt;foreach (DataRowView dvRow in dv)&lt;br /&gt;{&lt;br /&gt;    EmployeeDS.EmployeesRow item = (EmployeeDS.EmployeesRow)dvRow.Row;&lt;br /&gt;    Console.WriteLine(item.LastName);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;In the code above, the filter and the sort are in strings, so the compiler can’t find errors; if the Employee table doesn’t have a “Country” field, the above code will compile but throw an EvaluateException at runtime.&lt;/p&gt;&lt;p&gt;In the foreach loop you need to cast the DataRowView into the strongly typed DataRow before you can access the properties. If you really don’t want to do the cast, you could use “dvRow["LastName"]” to get the last name, but that would involve another “magic string”.&lt;/p&gt;&lt;p&gt;Now, let’s get the same list in Linq2DataSet:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;// If you use DataSets you can probably write your own EmployeeDS &amp;amp; SetupData():&lt;br /&gt;EmployeeDS db = SetupData();&lt;br /&gt;&lt;br /&gt;OrderedEnumerableRowCollection&amp;lt;EmployeeDS.EmployeesRow&amp;gt; linqRows = &lt;br /&gt;    from e in db.Employees&lt;br /&gt;    where e.Country == "USA"&lt;br /&gt;    orderby e.LastName&lt;br /&gt;    select e;&lt;br /&gt;&lt;br /&gt;// Linq2DataSet gives you a collection of strongly typed DataRows.&lt;br /&gt;// You don’t have to cast to get to the LastName element here:&lt;br /&gt;foreach (EmployeeDS.EmployeesRow item in linqRows)&lt;br /&gt;    Console.WriteLine(item.LastName);&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;In this code, the only thing in a string is “USA”; the compiler will freak out if you don’t have a “Country” field. You don’t have to rely on angry user to find these bugs.&lt;/p&gt;&lt;p&gt;In the foreach loop you don’t have to cast, the output of the Linq query is a collection of strongly typed DataRows (however it isn’t a DataTable, but a DataRow can’t belong to more than one DataTable anyway). &lt;/p&gt;&lt;p&gt;If you really only want LastNames you can get only LastNames:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;// If you use DataSets you can probably write your own EmployeeDS &amp;amp; SetupData():&lt;br /&gt;EmployeeDS db = SetupData();&lt;br /&gt;&lt;br /&gt;// Get me only LastNames as a collection of the field’s data type (in this case, string):&lt;br /&gt;EnumerableRowCollection&amp;lt;string&amp;gt; LastNames = from e in db.Employees&lt;br /&gt;        where e.Country == "USA"&lt;br /&gt;        orderby e.LastName&lt;br /&gt;        select e.LastName;&lt;br /&gt;&lt;br /&gt;// Loop through the strings&lt;br /&gt;foreach (string LastName in LastNames)&lt;br /&gt;    Console.WriteLine(LastName);&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Here Linq2DataSet gives us back a collection of strings because in the DataSet LastName is a string; if you ask for HireDate, you will get a collection of DateTimes.&lt;/p&gt;&lt;p&gt;Suppose you want a both LastName and FirstName you could do this (with Anonymous Types):&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;// If you use DataSets you can probably write your own EmployeeDS &amp;amp; SetupData():&lt;br /&gt;EmployeeDS db = SetupData();&lt;br /&gt;&lt;br /&gt;// Here we need to use “var” because the type doesn’t exist until the&lt;br /&gt;// compiler creates it:&lt;br /&gt;var Names = from e in db.Employees&lt;br /&gt;            where e.Country == "USA"&lt;br /&gt;            orderby e.LastName&lt;br /&gt;            select new { e.LastName, e.FirstName };&lt;br /&gt;&lt;br /&gt;// Here we are using the same type that the compiler created above:&lt;br /&gt;foreach (var Name in Names)&lt;br /&gt;    Console.WriteLine(string.Format("{0}, {1}",Name.LastName, Name.FirstName));&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;To make this work, C# created an anonymous type to put the results of the Linq query. Anonymous Types are strong types that are created at compile time; they just don’t have names and there are no class or struct declaration needed in the code. &lt;/p&gt;&lt;p&gt;(On my machine, according to the debugger, Names is a System.Data.EnumerableRowCollection&amp;lt;&amp;lt;&amp;gt;f__AnonymousType0&amp;lt;string,string&amp;gt;&amp;gt;)&lt;/p&gt;&lt;p&gt;More about using Anonymous Types in later posts. . .&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-2821486304683630542?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/2821486304683630542/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=2821486304683630542' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2821486304683630542'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2821486304683630542'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2010/01/linq2dataset-replaces-dataview.html' title='Linq2DataSet replaces the DataView'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-5580179007509804828</id><published>2010-01-14T20:06:00.001-08:00</published><updated>2011-03-31T20:42:57.748-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Linq2DataSet'/><title type='text'>Linq2DataSet Introduction</title><content type='html'>&lt;p&gt;Lately I’ve been working for a client that recently moved an existing application to VS 2008 / .NET 3.5. The app uses some DataSets, so I’ve been playing to what I call Linq2DataSet (or Linq to DataSet).&lt;/p&gt;&lt;h3&gt;Getting Started&lt;/h3&gt;&lt;p&gt;To use Linq2DataSet will need to use the .NET 3.5 runtime and, in addition to the usual ADO.NET assemblies you will need to add a reference to &lt;strong&gt;System.Data.DataSetExtensions.dll.&lt;/strong&gt;&lt;/p&gt;&lt;h3&gt;Quick comparison to Linq2Sql&lt;/h3&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;// Linq To Sql&lt;br /&gt;int Linq2SqlGetCount()&lt;br /&gt;{&lt;br /&gt;     BigTableSQLDataContext data = new BigTableSQLDataContext();&lt;br /&gt;     return (from x in data.Big_Tables select x).Count();&lt;br /&gt;}&lt;br /&gt;// Linq to DataSet&lt;br /&gt;int Linq2DataSetGetCount()&lt;br /&gt;{&lt;br /&gt;     BigTableDS data = new BigTableDS();&lt;br /&gt;     Big_TableTableAdapter da = new Big_TableTableAdapter();&lt;br /&gt;     da.Fill(data.Big_Table);&lt;br /&gt;&lt;br /&gt;     return (from x in data.Big_Table select x).Count();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The code isn’t that much different. There is a little more code to setup the DataSet than the SQL DataContext. No big deal.&lt;/p&gt;&lt;p&gt;There is a big gotcha. I ran both functions against a table with 20,000 records. The DataSet is fully loaded before anything can happen. In the code above, the Linq2Sql function runs in &amp;lt; 1 second and the Linq2DataSet version takes about a minute and a half.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;In Linq2DataSet, all 20,000 are loaded into the DataSet before the Linq code is executed. In Linq2Sql, the engine executes the Linq and generates the SQL to get the data (probably something like &lt;strong&gt;SELECT COUNT(*) FROM Big_Table&lt;/strong&gt;). &lt;br /&gt;&lt;/p&gt;&lt;p&gt;Yes, this looks bad, however if you already have the DataSet hanging around, Linq2DataSet may be a Mega-Cool way to solve your problems. For the record, I would not recommend Linq2DataSet for new “Green Field” projects, however, if you already have the DataSet lying around, Linq can make it easy to get that little bit of extra info you need. Linq2DataSets is also a way to get into Linq quickly then you can learn about Linq2Sql or the Entity Framework.  &lt;br /&gt;&lt;/p&gt;&lt;p&gt;More to come…&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-5580179007509804828?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/5580179007509804828/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=5580179007509804828' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5580179007509804828'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5580179007509804828'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2010/01/linq2dataset-introduction.html' title='Linq2DataSet Introduction'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-3302858043633501585</id><published>2009-12-13T17:54:00.001-08:00</published><updated>2011-04-03T08:15:27.949-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='nullabletypes'/><category scheme='http://www.blogger.com/atom/ns#' term='Generics'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Nullable Data Types Demo</title><content type='html'>&lt;h3&gt;The Problem&lt;/h3&gt;&lt;p&gt;In several of the projects I’ve worked on, we used some token value to represent null for non-nullable types. These values would be extreme values (for int, we would use int.MinValue or int.MaxValue), or null token. Recently I’ve come across some controls that don’t like this scheme and prefer using nullable types (like int?). &lt;/p&gt;&lt;p&gt;The original code was written in C# 1.X, so nullable types didn’t exist; the code works, so I don’t want to convert the non-nullables to nullable and risk breaking the rest of the application.&lt;/p&gt;&lt;p&gt;In production, I’ve solved the problem by creating “shadow” nullable properties. The code in these properties would translate the null tokens to null. For the most part the translation code is inline.&lt;/p&gt;&lt;h3&gt;Taking it to 11 with Generics&lt;/h3&gt;&lt;p&gt;This weekend, I played with implementing this stuff with a generic helper class. So the code for a nullable property would look something like this:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public DateTime? DobNullable&lt;br /&gt;{&lt;br /&gt;     get { return NullableHelper.GetNullable&amp;lt;DateTime&amp;gt;(this.Dob); }&lt;br /&gt;     set { this.Dob = NullableHelper.SetNullable&amp;lt;DateTime&amp;gt;(value); }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;To do this I created a class called NullableHelper that contained translation functions: The to set you use this:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public static T SetNullable&amp;lt;T&amp;gt;(T? futureValue)&lt;br /&gt;     where T : struct&lt;br /&gt;{&lt;br /&gt;     T rVal;&lt;br /&gt;     if (futureValue != null)&lt;br /&gt;          rVal = (T)futureValue;&lt;br /&gt;     else&lt;br /&gt;          rVal = NullForT&amp;lt;T&amp;gt;();&lt;br /&gt;     return rVal;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;This function echo back the value passed in UNLESS it is null; if it is null, it returns the null token. And to get, you use this:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public static T? GetNullable&amp;lt;T&amp;gt;(T presentValue)&lt;br /&gt;     where T : struct, IComparable&lt;br /&gt;{&lt;br /&gt;     T? rVal = null;&lt;br /&gt;&lt;br /&gt;     // I can't get the generic do == &amp;amp; !=, this works, so I'm &lt;br /&gt;     // going with it for now.&lt;br /&gt;     IComparable ic = presentValue as IComparable;&lt;br /&gt;     if (ic != null)&lt;br /&gt;     {&lt;br /&gt;          T CompareValue = NullForT&amp;lt;T&amp;gt;();&lt;br /&gt;          if (ic.CompareTo(CompareValue) != 0)&lt;br /&gt;               rVal = presentValue;&lt;br /&gt;          // I already set rVal to null above.&lt;br /&gt;          return rVal;&lt;br /&gt;     }&lt;br /&gt;     else&lt;br /&gt;     {&lt;br /&gt;         throw new ApplicationException(&lt;br /&gt;             string.Format("NullableDataTypesDemo.NullableHelper.GetNullable&amp;lt;T&amp;gt;()" +&lt;br /&gt;                  "\r\n'{0}' is can't be cast to IComparable",&lt;br /&gt;                  typeof(T).ToString())&lt;br /&gt;          );&lt;br /&gt;     }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;In this function I needed to cast T as IComparable to compare the value with the null token.&lt;/p&gt;&lt;p&gt;Both functions use a null token from the following function:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public static T NullForT&amp;lt;T&amp;gt;() &lt;br /&gt;     where T : struct&lt;br /&gt;{&lt;br /&gt;     T rVal;&lt;br /&gt;     // Here you will need to have an if for each of the &lt;br /&gt;     // supported types, this function could be really big in production:&lt;br /&gt;     if (typeof(T) == typeof(DateTime))&lt;br /&gt;     {&lt;br /&gt;          DateTime x = DateTime.MaxValue;&lt;br /&gt;          object o = x;&lt;br /&gt;          rVal = (T)o;&lt;br /&gt;     }&lt;br /&gt;     // Set other null tokens here&lt;br /&gt;     else&lt;br /&gt;     {&lt;br /&gt;          throw new ApplicationException(&lt;br /&gt;                 string.Format("NullableDataTypesDemo.NullableHelper.NullForT&amp;lt;T&amp;gt;()" +&lt;br /&gt;                 "\r\n'{0}' is an unsupported Type", &lt;br /&gt;                 typeof(T).ToString())&lt;br /&gt;          );&lt;br /&gt;     }&lt;br /&gt;     return rVal;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;This function is probably the Achilles’ heel of this design. You will need an if (typeof(T) block for each type you want to support in this function. Most of the complexity points of this solution are borne by this function.&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;Over the weekend I came up with a cool way of translating from a non-nullable with null tokens to nullables. Will I implement this in production? Probably not, the code works and I don’t want to risk breaking it. If I need to do similar things in a future project, I may come back to this post.&lt;/p&gt;&lt;h3&gt;The Whole Experiment&lt;/h3&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;using System;&lt;br /&gt;&lt;br /&gt;namespace NullableDataTypesDemo&lt;br /&gt;{&lt;br /&gt;    class Program&lt;br /&gt;    {&lt;br /&gt;        static void Main(string[] args)&lt;br /&gt;        {&lt;br /&gt;            // Create an instance of the demo entity&lt;br /&gt;            DemoEntityClass x1 = new DemoEntityClass(&lt;br /&gt;                1, &lt;br /&gt;                100m,&lt;br /&gt;                "Jill Stephens", &lt;br /&gt;                NullableHelper.NullForT&amp;lt;DateTime&amp;gt;(), &lt;br /&gt;                NullableHelper.NullForT&amp;lt;int&amp;gt;());&lt;br /&gt;&lt;br /&gt;            // Do some querying&lt;br /&gt;            if (x1.IdNullable != null)&lt;br /&gt;            {&lt;br /&gt;                Console.WriteLine(string.Format("ID = {0}", x1.IdNullable));&lt;br /&gt;            }&lt;br /&gt;            if (x1.NumOfChildren == NullableHelper.NullForT&amp;lt;int&amp;gt;())&lt;br /&gt;            {&lt;br /&gt;                Console.WriteLine("Children Unknown (classic)");&lt;br /&gt;            }&lt;br /&gt;            // Set a DOB&lt;br /&gt;            x1.DobNullable = new DateTime(1776, 7, 4);&lt;br /&gt;            Console.WriteLine(string.Format("{0:d}", x1.DobNullable));&lt;br /&gt;            // Set # of children and display&lt;br /&gt;            x1.NumOfChildrenNullable = 2;&lt;br /&gt;            Console.WriteLine("value of Number of Children: {0}", x1.NumOfChildren);&lt;br /&gt;            // Unset # of children&lt;br /&gt;            x1.NumOfChildren = NullableHelper.NullForT&amp;lt;int&amp;gt;();&lt;br /&gt;            if (x1.NumOfChildrenNullable == null)&lt;br /&gt;            {&lt;br /&gt;                Console.WriteLine("Children Unknown (new)");&lt;br /&gt;            }&lt;br /&gt;            // Won't comile, &lt;br /&gt;            // NullableHelper.NullForT&amp;lt;DemoEntityClass&amp;gt;();&lt;br /&gt;            // Some NullForT that won't compile&lt;br /&gt;            // (you can fix these by adding code to NullForT())&lt;br /&gt;            try&lt;br /&gt;            {&lt;br /&gt;                NullableHelper.NullForT&amp;lt;DemoStruct&amp;gt;();&lt;br /&gt;            }&lt;br /&gt;            catch (Exception ex)&lt;br /&gt;            {&lt;br /&gt;                Console.WriteLine(ex.Message);&lt;br /&gt;            }&lt;br /&gt;            try&lt;br /&gt;            {&lt;br /&gt;                NullableHelper.NullForT&amp;lt;double&amp;gt;();&lt;br /&gt;            }&lt;br /&gt;            catch (Exception ex)&lt;br /&gt;            {&lt;br /&gt;                Console.WriteLine(ex.Message);&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            // Force read line, so this won't go away in VS&lt;br /&gt;            Console.ReadLine();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;    /// &amp;lt;summary&amp;gt;&lt;br /&gt;    /// My Demo Entity Class&lt;br /&gt;    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;    class DemoEntityClass&lt;br /&gt;    {&lt;br /&gt;        public DemoEntityClass(int id, decimal amount, string name, DateTime dob, &lt;br /&gt;            int numOfChildren)&lt;br /&gt;        {&lt;br /&gt;            this.Id = id;&lt;br /&gt;            this.Amount = amount;&lt;br /&gt;            this.Name = name;&lt;br /&gt;            this.Dob = dob;&lt;br /&gt;            this.NumOfChildren = numOfChildren;&lt;br /&gt;        }&lt;br /&gt;        public int Id { get; set; }&lt;br /&gt;        public decimal Amount { get; set; }&lt;br /&gt;        public string Name { get; set; }&lt;br /&gt;        public DateTime Dob { get; set; }&lt;br /&gt;        public int NumOfChildren { get; set; }&lt;br /&gt;&lt;br /&gt;        public int? IdNullable&lt;br /&gt;        {&lt;br /&gt;            get { return NullableHelper.GetNullable&amp;lt;int&amp;gt;(this.Id); }&lt;br /&gt;            set { this.Id = NullableHelper.SetNullable&amp;lt;int&amp;gt;(value); }&lt;br /&gt;        }&lt;br /&gt;        public decimal? AmountNullable&lt;br /&gt;        {&lt;br /&gt;            get { return NullableHelper.GetNullable&amp;lt;decimal&amp;gt;(this.Amount); }&lt;br /&gt;            set { this.Amount = NullableHelper.SetNullable&amp;lt;decimal&amp;gt;(value); }&lt;br /&gt;        }&lt;br /&gt;        // string is nullable, so I am including this for completeness&lt;br /&gt;        public string NameNullable&lt;br /&gt;        {&lt;br /&gt;            get { return this.Name; }&lt;br /&gt;            set { this.Name = (string)value; }&lt;br /&gt;        }&lt;br /&gt;        public DateTime? DobNullable&lt;br /&gt;        {&lt;br /&gt;            get { return NullableHelper.GetNullable&amp;lt;DateTime&amp;gt;(this.Dob); }&lt;br /&gt;            set { this.Dob = NullableHelper.SetNullable&amp;lt;DateTime&amp;gt;(value); }&lt;br /&gt;        }&lt;br /&gt;        public int? NumOfChildrenNullable&lt;br /&gt;        {&lt;br /&gt;            get { return NullableHelper.GetNullable&amp;lt;int&amp;gt;(this.NumOfChildren); }&lt;br /&gt;            set { this.NumOfChildren = NullableHelper.SetNullable&amp;lt;int&amp;gt;(value); }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    /// &amp;lt;summary&amp;gt;&lt;br /&gt;    /// My Demo struct&lt;br /&gt;    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;    struct DemoStruct&lt;br /&gt;    {&lt;br /&gt;        public int x;&lt;br /&gt;        public int y;&lt;br /&gt;        public int xy { get { return x * y; } }&lt;br /&gt;    }&lt;br /&gt;    static class NullableHelper&lt;br /&gt;    {&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Gets the Null marker value for value types&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        /// &amp;lt;remarks&amp;gt;&lt;br /&gt;        /// In some old applications that date back to before nullable types&lt;br /&gt;        /// maked fields as being null with extreme values (int.MaxValue for&lt;br /&gt;        /// example).&lt;br /&gt;        /// &amp;lt;/remarks&amp;gt;&lt;br /&gt;        /// &amp;lt;typeparam name="T"&amp;gt;Tye value type being tested&amp;lt;/typeparam&amp;gt;&lt;br /&gt;        /// &amp;lt;returns&amp;gt;The Null marker value&amp;lt;/returns&amp;gt;&lt;br /&gt;        public static T NullForT&amp;lt;T&amp;gt;() &lt;br /&gt;            where T : struct&lt;br /&gt;        {&lt;br /&gt;            T rVal;&lt;br /&gt;            // Here you will need to have an if for each of the &lt;br /&gt;            // supported types, this function could be really big in production:&lt;br /&gt;            if (typeof(T) == typeof(int))&lt;br /&gt;            {&lt;br /&gt;                int x = int.MaxValue;&lt;br /&gt;                object o = x;&lt;br /&gt;                rVal = (T)o;&lt;br /&gt;            }&lt;br /&gt;            else if (typeof(T) == typeof(decimal))&lt;br /&gt;            {&lt;br /&gt;                decimal x = decimal.MaxValue;&lt;br /&gt;                object o = x;&lt;br /&gt;                rVal = (T)o;&lt;br /&gt;            }&lt;br /&gt;            else if (typeof(T) == typeof(string))&lt;br /&gt;            {&lt;br /&gt;                string x = string.Empty;&lt;br /&gt;                object o = x;&lt;br /&gt;                rVal = (T)o;&lt;br /&gt;            }&lt;br /&gt;            else if (typeof(T) == typeof(DateTime))&lt;br /&gt;            {&lt;br /&gt;                DateTime x = DateTime.MaxValue;&lt;br /&gt;                object o = x;&lt;br /&gt;                rVal = (T)o;&lt;br /&gt;            }&lt;br /&gt;            else&lt;br /&gt;            {&lt;br /&gt;                throw new ApplicationException(&lt;br /&gt;                    string.Format("NullableDataTypesDemo.NullableHelper.NullForT&amp;lt;T&amp;gt;()" +&lt;br /&gt;                      "\r\n'{0}' is an unsupported Type", &lt;br /&gt;                    typeof(T).ToString())&lt;br /&gt;                );&lt;br /&gt;            }&lt;br /&gt;            return rVal;&lt;br /&gt;        }&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Used in a set block to set a non-nullable&lt;br /&gt;        /// field from a nullable value&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        /// &amp;lt;remarks&amp;gt;&lt;br /&gt;        /// Since the null values are gotten from NullForT, this function can be short&lt;br /&gt;        /// &amp;lt;/remarks&amp;gt;&lt;br /&gt;        /// &amp;lt;see cref="NullForT"/&amp;gt;&lt;br /&gt;        /// &amp;lt;typeparam name="T"&amp;gt;Tye value type being set&amp;lt;/typeparam&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="futureValue"&amp;gt;nullable new value&amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;returns&amp;gt;non nullable value  with Null marker value to denote null&amp;lt;/returns&amp;gt;&lt;br /&gt;        public static T SetNullable&amp;lt;T&amp;gt;(T? futureValue)&lt;br /&gt;            where T : struct&lt;br /&gt;        {&lt;br /&gt;            T rVal;&lt;br /&gt;            if (futureValue != null)&lt;br /&gt;                rVal = (T)futureValue;&lt;br /&gt;            else&lt;br /&gt;                rVal = NullForT&amp;lt;T&amp;gt;();&lt;br /&gt;            return rVal;&lt;br /&gt;        }&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Used in a get block to get a nullable field&lt;br /&gt;        /// from the non-nullable value&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        /// &amp;lt;remarks&amp;gt;&lt;br /&gt;        /// This function is a little more complex because we need to cast&lt;br /&gt;        /// presentValue to IComparable to compare it to the null token &lt;br /&gt;        /// &amp;lt;/remarks&amp;gt;&lt;br /&gt;        /// &amp;lt;see cref="NullForT"/&amp;gt;&lt;br /&gt;        /// &amp;lt;typeparam name="T"&amp;gt;Tye value type being set&amp;lt;/typeparam&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="presentValue"&amp;gt;&lt;br /&gt;        /// non-nullable value with Null marker value to denote null&lt;br /&gt;        /// &amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;returns&amp;gt;nullable value returned&amp;lt;/returns&amp;gt;&lt;br /&gt;        public static T? GetNullable&amp;lt;T&amp;gt;(T presentValue)&lt;br /&gt;            where T : struct, IComparable&lt;br /&gt;        {&lt;br /&gt;            T? rVal = null;&lt;br /&gt;&lt;br /&gt;            // I can't get the generic do == &amp;amp; !=, this works, so I'm &lt;br /&gt;            // going with it for now.&lt;br /&gt;            IComparable ic = presentValue as IComparable;&lt;br /&gt;            if (ic != null)&lt;br /&gt;            {&lt;br /&gt;                T CompareValue = NullForT&amp;lt;T&amp;gt;();&lt;br /&gt;                if (ic.CompareTo(CompareValue) != 0)&lt;br /&gt;                    rVal = presentValue;&lt;br /&gt;                // I already set rVal to null above.&lt;br /&gt;            }&lt;br /&gt;            else&lt;br /&gt;            {&lt;br /&gt;               throw new ApplicationException(&lt;br /&gt;                 string.Format("NullableDataTypesDemo.NullableHelper.GetNullable&amp;lt;T&amp;gt;()" +&lt;br /&gt;                      "\r\n'{0}' is can't be cast to IComparable",&lt;br /&gt;                 typeof(T).ToString())&lt;br /&gt;               );&lt;br /&gt;            }&lt;br /&gt;            return rVal;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-3302858043633501585?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/3302858043633501585/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=3302858043633501585' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/3302858043633501585'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/3302858043633501585'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2009/12/nullable-data-types-demo.html' title='Nullable Data Types Demo'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-7453865722492843568</id><published>2009-11-26T10:44:00.001-08:00</published><updated>2011-01-04T20:19:59.007-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='RickRoll'/><category scheme='http://www.blogger.com/atom/ns#' term='The Gu'/><category scheme='http://www.blogger.com/atom/ns#' term='Rick Astley'/><title type='text'>The Gu Rickrolled no one</title><content type='html'>&lt;p&gt;You may have heard about &lt;a href="http://weblogs.asp.net/scottgu/"&gt;Scott Guthrie&lt;/a&gt;’s Rick Astley related stunt at the &lt;a href="http://microsoftpdc.com"&gt;PDC&lt;/a&gt; in &lt;a href="http://www.lacity.org/index.htm"&gt;Los Angeles&lt;/a&gt; last week. I don’t think it qualifies as a &lt;a href="http://en.wikipedia.org/wiki/Rickrolling"&gt;rickroll&lt;/a&gt;. As a developer who uses &lt;a href="http://www.microsoft.com"&gt;Microsoft&lt;/a&gt; technologies, I have sworn to The Gu’s super-duper deluxe uber-geekiness.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;IMO, to qualify as a rickroll, you must willfully click on a link expecting something juicy and end up on suffering through “Never Gonna Give You Up”. You make a bad decision that makes you worthy of such punishment. &lt;br /&gt;&lt;/p&gt;&lt;p&gt;If you clicked on a link for &lt;a href="http://www.yougotrickrolled.com/"&gt;Paris Hilton’s latest video (wink, wink)&lt;/a&gt; and instead got Rick, you have been rickrolled! If you clicked on a link marked &lt;a href="http://www.yougotrickrolled.com/"&gt;Rick Astley’s famous video&lt;/a&gt;, you haven’t been rickrolled, you are getting what you expected.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;At the PDC, The Gu’s victims didn’t have the &lt;a href="http://en.wikipedia.org/wiki/Free_will"&gt;free will&lt;/a&gt; not to click the link or take the &lt;a href="http://en.wikipedia.org/wiki/Redpill"&gt;red pill&lt;/a&gt;. In this situation, The Gu launched the video.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;If one of The Gu’s minions changed out the “real” video with Rick Astley without his knowledge, then he is the only rickrollee. &lt;br /&gt;&lt;/p&gt;&lt;p&gt;It could be argued that the attending a Scott Guthrie presentation is bad decision that qualifies one to be worthy of being rickrolled.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-7453865722492843568?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/7453865722492843568/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=7453865722492843568' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/7453865722492843568'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/7453865722492843568'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2009/11/gu-rickrolled-no-one.html' title='The Gu Rickrolled no one'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-1697425262922775472</id><published>2009-11-12T20:25:00.001-08:00</published><updated>2011-04-03T08:18:21.562-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XML Comments'/><category scheme='http://www.blogger.com/atom/ns#' term='Documentation'/><title type='text'>Rant on XML Comments</title><content type='html'>&lt;p&gt;The purpose of .NET XML comment is to help you generate outside documentation.  When you tell Visual Studio to generate the XML file, you get tool tips when you hover over your method and you can use a tool like SandCastle to generate MSDN style help files based on your XML Comments. XML comments are really designed for Black Box documentation of Frameworks and API.&lt;/p&gt;&lt;p&gt;An XML comment is not the same as a development comment. When I am looking at a SandCastle generated help file, I care about how to use your class or method; I don’t care about why you chose to use a bubble sort over a quick sort.&lt;/p&gt;&lt;p&gt;I’ve seen comments like this:&lt;/p&gt;&lt;pre class="prettyprint"&gt;///&amp;lt;summary&amp;gt;&lt;br /&gt;/// DV&lt;br /&gt;///&amp;lt;/summary&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;where DV is the initials of one of the developers. If you were actually use the XML comment feature, this comment would show up when you mouse over the class in Visual Studio or in the help file you created with SandCastle, same with this comment: &lt;/p&gt;&lt;pre class="prettyprint"&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// This is the FooBar class!&lt;br /&gt;/// I originally designed on a napkin after midnight after drinking &lt;br /&gt;/// a fifth of JD &amp;amp; eating 3 orders of hot wings.&lt;br /&gt;/// I was inspired to write this class after Ellen, the goddess of &lt;br /&gt;/// the 327th Ave NE Pub down the street from my studio apartment,&lt;br /&gt;/// who rejected me after I drank myself silly summoning up the &lt;br /&gt;/// courage  to ask her out.&lt;br /&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;With the VS tooltip feature you lose all formatting, so if you have a comment like&lt;/p&gt;&lt;pre class="prettyprint"&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// Foobar Class&lt;br /&gt;///&lt;br /&gt;/// Combines Bars with Foos and converts them from Metric to Imperial&lt;br /&gt;///&lt;br /&gt;/// 2005-04-13 – RN – Original implication &lt;br /&gt;/// 2005-05-03 – RF – Bug #12239 – g to # conversion issue&lt;br /&gt;/// 2008-03-27 – VW – re-Implement Linq to Foo framework&lt;br /&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;will appear on 1 or 2 lines without the linefeeds. The tags are ignored when VS creates tooltips.&lt;/p&gt;&lt;p&gt;I know that most of the projects I work on are not frameworks or API, but it still feel the need to avoid using XML comments for things other what I think they are designed for.&lt;/p&gt;&lt;p&gt;I am uptight about XML comments because I have used them, once. We created a help file for a client using SandCastle; the customer was impressed, though I bet they never used it.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-1697425262922775472?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/1697425262922775472/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=1697425262922775472' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/1697425262922775472'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/1697425262922775472'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2009/11/rant-on-xml-comments.html' title='Rant on XML Comments'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-1702205970202530613</id><published>2009-10-11T19:10:00.001-07:00</published><updated>2011-01-04T20:20:38.765-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Software Quality'/><title type='text'>How bad is too bad?</title><content type='html'>&lt;p&gt;I have been assigned the task of updating a program that isn’t terribly well designed.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;How deep do I dive in trying to fix this program? Do I take all of the inappropriate code from the Form Classes and move them into Business Classes? Do I get rid of all the SQL queries in code? Do I tear the whole thing to shreds and start over with my brilliantly planned super object oriented design applying all 23 GoF design patterns?  My inner geek screams yes, Yes, YES! But according to Joel Spolsky, rewriting software just to do it can be the biggest mistake “you” can make. (http://www.joelonsoftware.com/articles/fog0000000069.html).&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I mean, the program basically works. If the world around the program wasn’t changing, it could probably go unchanged. But we’re replacing one system that this program talks to and replacing it with another one.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Looking at the code, I would date the program to around the 2003 timeframe with stuff added later as the program evolved. I see: &lt;/p&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;Int32&lt;/strong&gt; in place of &lt;strong&gt;int&lt;/strong&gt;, &lt;strong&gt;String&lt;/strong&gt; in place of &lt;strong&gt;string&lt;/strong&gt;, etc. (I remember reading and hearing experts recommending that practice in the early days of .NET)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Long unstructured functions in the form class. Sort of like VB6 in C#, we know that a lot of that went on in the early 0's.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;There is some object orientation grafted on to the edges of the program but the core is pretty old fashioned pre-OO .NET 1.0 code.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Uses &lt;strong&gt;finally&lt;/strong&gt; in places where rational modern C# coders would use &lt;strong&gt;using&lt;/strong&gt;.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;p&gt;So it isn’t wonderful code, but, for the most part, it works. But like any spoiled brat, I just wanna do it. Why: just because.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The program was written in the ancient times of yore (5 years ago). When .NET first came out, OO was just starting to catch on in the mainstream. Right now I am hearing rumors that the next big thing is going to be Functional programming; the justification is that it is easier to parallelize so elements of the Functional Fad will probably stick around for the long term. What will my elegant OO code look like to the Functional masters of the future?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-1702205970202530613?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/1702205970202530613/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=1702205970202530613' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/1702205970202530613'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/1702205970202530613'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2009/10/how-bad-is-too-bad.html' title='How bad is too bad?'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-7223826733291911021</id><published>2009-09-22T21:04:00.001-07:00</published><updated>2011-04-03T08:20:19.086-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='Obscurity'/><title type='text'>SQL Funny Business</title><content type='html'>&lt;p&gt;Today at work we were talking about mixing old (table, table where join criteria) and new (table join table on join criteria) style joins in the same query. So that got me to thinking about what ON really does. I ran the following queries against the infamous Northwind Database:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;-- The modern style join:&lt;br /&gt;SELECT *&lt;br /&gt;FROM dbo.Orders o&lt;br /&gt; JOIN [Order Details] od ON od.OrderID = o.OrderID &lt;br /&gt;WHERE o.CustomerID = 'SUPRD'&lt;br /&gt;&lt;br /&gt;-- The classic style join:&lt;br /&gt;SELECT *&lt;br /&gt;FROM dbo.Orders o, [Order Details] od&lt;br /&gt;WHERE od.OrderID = o.OrderID&lt;br /&gt; AND o.CustomerID = 'SUPRD'&lt;br /&gt;&lt;br /&gt;-- Inverted modern join (join criteria in WHERE, selection criteria in ON):&lt;br /&gt;SELECT *&lt;br /&gt;FROM dbo.Orders o&lt;br /&gt; JOIN [Order Details] od ON o.CustomerID = 'SUPRD'&lt;br /&gt;WHERE od.OrderID = o.OrderID&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;All three queries gave me the same results set.&lt;/p&gt;&lt;p&gt;Is the ON clause just a different place to shove selection criteria (a phantom where). I like the modern style. You can put all the join information together. You could mix things up when you practice Job Security Based Programming.&lt;/p&gt;&lt;p&gt;I think it would be fun to have a obscure SQL programming competition, like the obscure C programming competitions in the days of yore.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-7223826733291911021?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/7223826733291911021/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=7223826733291911021' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/7223826733291911021'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/7223826733291911021'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2009/09/sql-funny-business.html' title='SQL Funny Business'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-8885282030848663154</id><published>2009-08-31T21:56:00.001-07:00</published><updated>2011-01-07T06:38:26.798-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Refactoring'/><category scheme='http://www.blogger.com/atom/ns#' term='Cut and Paste'/><title type='text'>Is it too late to wrap it into a function?</title><content type='html'>&lt;p&gt;Today I was refactoring several properties in a Business Class from int to int?. I was in a hurry, so I was implementing the 10 properties using cut and paste inheritance (as if that is ever really faster).&lt;br /&gt;&lt;/p&gt;&lt;p&gt;After the 8th or 9th properties, the light went off in my mind: I should write a couple of functions to do the hard work and call the functions from the property get and set functions. Was it too late to to do it right?&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I said NO.It did take me longer to write the functions than it would have taken to cut and past the 2 remaining properties. However, the code is easier to read, validate and change.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I guess I justify my earlier sloppy coding time as an opportunity to think of the right way. During the first go round I was planning to do the second one; I needed to do it wrong to see how to do it right.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-8885282030848663154?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/8885282030848663154/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=8885282030848663154' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/8885282030848663154'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/8885282030848663154'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2009/08/is-it-too-late-to-wrap-it-into-function.html' title='Is it too late to wrap it into a function?'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-1240739227977359850</id><published>2009-07-31T09:43:00.001-07:00</published><updated>2011-01-07T06:31:55.508-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='teams'/><category scheme='http://www.blogger.com/atom/ns#' term='career'/><title type='text'>New Team, New Ways of Thinking</title><content type='html'>&lt;p&gt;I have recently started working on a new team.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The new team uses a different architecture, different naming conventions, file organization, source control, etc. The new team is uptight about different things than the old team.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I am learning to think differently, reevaluate my old ways and adapt the new things from the new team.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;In the long run, I think it is a good thing; I need change to avoid ruts and learn new ways of approaching problems&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-1240739227977359850?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/1240739227977359850/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=1240739227977359850' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/1240739227977359850'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/1240739227977359850'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2009/07/new-team-new-ways-of-thinking_31.html' title='New Team, New Ways of Thinking'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-3006851531710523838</id><published>2009-06-15T21:36:00.001-07:00</published><updated>2011-04-03T08:22:04.223-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Access'/><category scheme='http://www.blogger.com/atom/ns#' term='VBA'/><title type='text'>Access 2007 Trap: Life without @@identity()</title><content type='html'>&lt;p&gt;I came across some interesting behavior in Access 2007 that tripped me up for a little while.I needed to add a record to a table and then get the primary key value of the newly added record.&lt;/p&gt;&lt;p&gt;I wrote the code that I expected to work and I always got back the same number for the primary key every time I ran the code; the value of the primary key value of the &lt;em&gt;first&lt;/em&gt; record.But I wanted the primary key value of the &lt;em&gt;last&lt;/em&gt; record, the record that I just created. So, I added &lt;strong&gt;.MoveLast&lt;/strong&gt; to get the last record.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;   Dim rs As Recordset2&lt;br /&gt;   Dim recordId As Integer&lt;br /&gt;   Set rs = Application.CurrentDb.OpenRecordset("Table_1")&lt;br /&gt;   With rs&lt;br /&gt;       .AddNew&lt;br /&gt;       !field_1 = "Field_1"&lt;br /&gt;       !field_2 = "Field_2"&lt;br /&gt;       ' I expected the the primary key value to be loaded here:&lt;br /&gt;       .Update&lt;br /&gt;       ' When you open a recordset, there is an implied "MoveFirst" call&lt;br /&gt;       ' For whatever reason, Access doesn't refresh values after writing&lt;br /&gt;       ' the record:&lt;br /&gt;       .MoveLast&lt;br /&gt;       ' Without the MoveLast, you get the record_id of the first record:&lt;br /&gt;       recordId = !record_id&lt;br /&gt;       .Close&lt;br /&gt;   End With&lt;br /&gt;   Set rs = Nothing&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;I guess the thing that screwed me up is that I expected all of the fields in the current record of a RecordSet2 point to the same record. In my mind, when I call &lt;strong&gt;Update&lt;/strong&gt;, the value of the primary key should be retrieved and ready for me to reference.&lt;/p&gt;&lt;p&gt;In ADO.NET, the DataSet has the &lt;strong&gt;AcceptChanges()&lt;/strong&gt; method. This is logical to me because a DataSet is disconnected. I guess a Recordset2 is "loosly" connected.&lt;/p&gt;&lt;p&gt;Access continues to weird me out.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-3006851531710523838?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/3006851531710523838/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=3006851531710523838' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/3006851531710523838'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/3006851531710523838'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2009/06/access-2007-trap-life-without-identity.html' title='Access 2007 Trap: Life without @@identity()'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-2722711615970174988</id><published>2009-05-22T18:29:00.001-07:00</published><updated>2011-04-03T08:23:23.745-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Flair'/><category scheme='http://www.blogger.com/atom/ns#' term='CSS'/><category scheme='http://www.blogger.com/atom/ns#' term='StackOverflow'/><title type='text'>Stackoverflow Flair without the image</title><content type='html'>&lt;p&gt;Scott Hanselman tweeted about how cool it would be to have a &lt;a href="http://stackoverflow.com/"&gt;Stackoverflow&lt;/a&gt; flair without a tje gravatar.  This is my solution using CSS&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;Stack Overflow Flair Demo&amp;lt;/title&amp;gt;&lt;br /&gt;    &amp;lt;style type="text/css"&amp;gt;&lt;br /&gt;.valuable-flair&lt;br /&gt;{&lt;br /&gt;    background-color: #ffffff;&lt;br /&gt;    font-family: Arial, Helvetica, sans-serif;&lt;br /&gt;    font-size: 12px;&lt;br /&gt;    height: 50px;&lt;br /&gt;    padding: 3px;&lt;br /&gt;    width: 50px;&lt;br /&gt;}&lt;br /&gt;.gravatar&lt;br /&gt;{&lt;br /&gt; display: none;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.valuable-flair .badge1&lt;br /&gt;{&lt;br /&gt;    color: #ffcc00;&lt;br /&gt;}&lt;br /&gt;.valuable-flair .badge2&lt;br /&gt;{&lt;br /&gt;    color: #c0c0c0;&lt;br /&gt;}&lt;br /&gt;.valuable-flair .badge3&lt;br /&gt;{&lt;br /&gt;    color: #CC9966;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&amp;lt;/style&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&amp;lt;script src="http://stackoverflow.com/users/flair/3819.js?theme=none" type="text/javascript"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-2722711615970174988?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/2722711615970174988/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=2722711615970174988' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2722711615970174988'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2722711615970174988'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2009/05/stackoverflow-flair-without-image.html' title='Stackoverflow Flair without the image'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-7265151169319237193</id><published>2009-05-14T21:05:00.001-07:00</published><updated>2011-06-28T05:54:25.837-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Cookieless session'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='JQuery AJAX'/><title type='text'>ASP.NET Cookieless sessions and JQuery AJAX</title><content type='html'>&lt;p&gt;I was trying to get some jquery ajax calls to work after converting a site to cookie-less sessions (don't ask).  I noticed the following code wouldn't work:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;$.post("/bin/getsomedata.dll", {'id': id},&lt;br /&gt;   function(data)&lt;br /&gt;   {&lt;br /&gt;       doSomething(data);&lt;br /&gt;   }&lt;br /&gt;);&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;I changed it to:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;$.post("&amp;lt;%=Response.ApplyAppPathModifier("/bin/getsomedata.dll")%&amp;gt;", {'id': id},&lt;br /&gt;   function(data)&lt;br /&gt;   {&lt;br /&gt;       doSomething(data);&lt;br /&gt;   }&lt;br /&gt;);&lt;br /&gt;&lt;/pre&gt;&lt;p&gt; and all was groovy&lt;/p&gt;&lt;p&gt;I also noticed that when I turn off cookieless sessions, everything still works. It appears that &lt;strong&gt;Response.ApplyAppPathModifier()&lt;/strong&gt; only alters the URL when I am in cookieless sessions&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-7265151169319237193?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/7265151169319237193/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=7265151169319237193' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/7265151169319237193'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/7265151169319237193'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2009/05/aspnet-cookieless-sessions-and-jquery.html' title='ASP.NET Cookieless sessions and JQuery AJAX'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-1608156417573703820</id><published>2009-05-07T21:29:00.001-07:00</published><updated>2011-04-03T08:33:16.801-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Web'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Code'/><category scheme='http://www.blogger.com/atom/ns#' term='Popup'/><title type='text'>Photoviewer</title><content type='html'>&lt;p&gt;Today I needed to write a pop up form that would show any image without any extra IE (or Firefox, Chrome, Safari, etc.) toolbars, etc.To get a web form to display an arbitrary image, I have a simple page that takes the URL of the image in the query string.  The web form takes that string and uses it to set ImageUrl of an asp.image control.&lt;/p&gt;&lt;h5&gt;photoviewer.aspx:&lt;/h5&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;%@ Page Language="C#" EnableViewState="false" %&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;&lt;br /&gt;&amp;lt;script runat="server"&amp;gt;    private void Page_Load()&lt;br /&gt;    {        string file = Request.QueryString["file"];&lt;br /&gt;        if (file != null)&lt;br /&gt;            myImage.ImageUrl = Server.UrlDecode(file);&lt;br /&gt;    }&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;My Image Viewer&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&lt;br /&gt;    &amp;lt;form id="Form1" method="post" runat="server"&amp;gt;&lt;br /&gt;    &amp;lt;table style="border:0;"&amp;gt;&lt;br /&gt;        &amp;lt;tr&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;&lt;br /&gt;                &amp;lt;asp:Image runat="server" ID="myImage" EnableViewState="false" /&amp;gt;&lt;br /&gt;            &amp;lt;/td&amp;gt;    &lt;br /&gt;        &amp;lt;/tr&amp;gt;&lt;br /&gt;        &amp;lt;tr&amp;gt;&lt;br /&gt;            &amp;lt;td&amp;gt;&lt;br /&gt;                &amp;lt;input type="button" onclick="javascript: window.close();" &lt;br /&gt;                    value="close" /&amp;gt;&lt;br /&gt;            &amp;lt;/td&amp;gt;&lt;br /&gt;        &amp;lt;/tr&amp;gt;&lt;br /&gt;    &amp;lt;/table&amp;gt;&lt;br /&gt;    &amp;lt;/form&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;To get rid of extra browser features and to  size the popup, I call window.open()  I set the height and width to values that will ensure that I have enough room for the image (I can use to get the dimensions of an image and add some buffer around the image so the popup isn’t all picture). I suppress  status, toolbar, menubar. Location and scrollbars by setting them all to “0”.&lt;/p&gt;&lt;h5&gt;feature_win.js&lt;/h5&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;// declared outside of the scope of the function so it will persist on the page:&lt;br /&gt;var newWindow;&lt;br /&gt;function featureWin(height, width, url)&lt;br /&gt;{&lt;br /&gt;    var lHeight = height;&lt;br /&gt;    var lWidth = width;&lt;br /&gt;    &lt;br /&gt;    if (newWindow &amp;amp;&amp;amp; !newWindow.closed) &lt;br /&gt;    {&lt;br /&gt;      newWindow.close()&lt;br /&gt;    }&lt;br /&gt;    newWindow = window.open(url, null, 'height=' + height +  &lt;br /&gt;       ',width=' + width + ',status=0,toolbar=0,menubar=0,location=0,scrollbars=0');&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Here we put it all together.&lt;/p&gt;&lt;h5&gt;default.html&lt;/h5&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;Test My Image Viewer&amp;lt;/title&amp;gt;&lt;br /&gt;    &amp;lt;script type="text/javascript" src="feature_win.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&amp;lt;a href="javascript: featureWin(825, 1050, 'photoviewer.aspx?file=Garden.jpg');"&amp;gt;&lt;br /&gt;    Garden&amp;lt;/a&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-1608156417573703820?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/1608156417573703820/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=1608156417573703820' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/1608156417573703820'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/1608156417573703820'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2009/05/photoviewer.html' title='Photoviewer'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-5947121633532865267</id><published>2009-04-26T20:04:00.001-07:00</published><updated>2011-04-03T08:36:09.447-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Web'/><category scheme='http://www.blogger.com/atom/ns#' term='URL'/><category scheme='http://www.blogger.com/atom/ns#' term='Code'/><category scheme='http://www.blogger.com/atom/ns#' term='Query String'/><title type='text'>URL Builder Functions</title><content type='html'>&lt;p&gt;I am working on an internal web application that does some state management through the query string. That being the case, I have to add, remove and change paramters in the query string.  Here are the functions that I use to edit the URL to change these varables&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;// Takes a URL with parameters and replaces the current value of a given parameter &lt;br /&gt;// with the new value provided&lt;br /&gt;public static string replaceParameterInUrl(string theUrl, string param, string newValue)&lt;br /&gt;{&lt;br /&gt;    StringBuilder sb = new StringBuilder();&lt;br /&gt;    string[] parts = theUrl.Split(new char[] { '?', '&amp;amp;' });&lt;br /&gt;    sb.Append(parts[0]).Append("?");&lt;br /&gt;    for (int i = 1; i &amp;lt; parts.Length; ++i)&lt;br /&gt;    {&lt;br /&gt;         string thisParam = parts[i];&lt;br /&gt;         string[] paramParts = thisParam.Split(new char[] { '=' });&lt;br /&gt;         if (paramParts[0] != param)&lt;br /&gt;             sb.Append(thisParam).Append("&amp;amp;");&lt;br /&gt;    }&lt;br /&gt;    sb.Append(param).Append("=").Append(newValue);&lt;br /&gt;    return sb.ToString();&lt;br /&gt;}&lt;br /&gt;/// Takes a URL with parameters and replaces the current value of a given parameter &lt;br /&gt;/// with the new value provided&lt;br /&gt;public static string removeParameterFromUrl(string theUrl, string param)&lt;br /&gt;{&lt;br /&gt;    StringBuilder sb = new StringBuilder();&lt;br /&gt;    bool isFirstItem = true;&lt;br /&gt;    string[] parts = theUrl.Split(new char[] { '?', '&amp;amp;' });&lt;br /&gt;    sb.Append(parts[0]).Append("?");&lt;br /&gt;    for (int i = 1; i &amp;lt; parts.Length; ++i)&lt;br /&gt;    {&lt;br /&gt;        string thisParam = parts[i];&lt;br /&gt;        string[] paramParts = thisParam.Split(new char[] { '=' });&lt;br /&gt;        if (paramParts[0] != param)&lt;br /&gt;        {&lt;br /&gt;            if (!isFirstItem)&lt;br /&gt;                sb.Append("&amp;amp;");&lt;br /&gt;            sb.Append(thisParam);&lt;br /&gt;            isFirstItem = false;&lt;br /&gt;        }&lt;br /&gt;   }&lt;br /&gt;   return sb.ToString();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;If I was going to use these functions in a public facing site,I'd probably sort the parameters alphabetically, so there would be less flux in the URLs that Google would see&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-5947121633532865267?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/5947121633532865267/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=5947121633532865267' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5947121633532865267'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5947121633532865267'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2009/04/url-builder-functions.html' title='URL Builder Functions'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-8887343056480950748</id><published>2009-04-19T21:19:00.001-07:00</published><updated>2011-01-04T20:24:58.605-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Building Software'/><category scheme='http://www.blogger.com/atom/ns#' term='Semi-Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Framework'/><category scheme='http://www.blogger.com/atom/ns#' term='Small Business'/><title type='text'>On Small, Low Margin Projects</title><content type='html'>&lt;h2&gt;Part 3: Framework and Starter Application&lt;/h2&gt;&lt;p&gt;To get off to a quick start, I would imagine finding or building (or a combination of the two) an application framework before I start selling my services to the small business-person. Most small business applications need CRUD and List forms; user accounts and various levels of access; logging;; an about window; error and audit logging; etc.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The platform doesn’t really matter as long it is robust enough to solve the business problem. You need something that is robust enough to solve the current business problem and accept the changes that will take place (sooner: you misread a requirement, later: new work and more revenue). The toolset should support modern scalable designs; the software may be the seed of an enterprise system.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I know that this is like having a hammer and making everything into a nail. At this kind of margin, you can’t afford to handle any technology that the customer may want to use. If it isn’t a nail and can’t be made into a nail, have someone else do it; margins are too tight to take anything.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The first few projects will probably be losers as you work out the kinks in the framework and your process. &lt;br /&gt;&lt;/p&gt;&lt;p&gt;With a starting point, we can get our customer something to show them after the first sprint. We can show the customer something quickly and have something to talk about when we plan the second sprint. If we come back to them quickly with something to show, they will feel involved in the process. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-8887343056480950748?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/8887343056480950748/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=8887343056480950748' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/8887343056480950748'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/8887343056480950748'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2009/04/on-small-low-margin-projects-part-3.html' title='On Small, Low Margin Projects'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-2890158249366438290</id><published>2009-04-13T19:42:00.001-07:00</published><updated>2011-01-04T20:25:29.260-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Building Software'/><category scheme='http://www.blogger.com/atom/ns#' term='Semi-Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Feedback'/><category scheme='http://www.blogger.com/atom/ns#' term='Small Business'/><title type='text'>On Small, Low Margin Projects</title><content type='html'>&lt;h2&gt;Part 2: Short Interactions and Feedback&lt;/h2&gt;&lt;p&gt;In a &lt;a href="http://jrcs3.blogspot.com/2009/04/on-small-low-margin-projects-part-1_7026.html"&gt;previous post&lt;/a&gt;, I wrote about some of the issues I have experienced with small projects and suggested that Waterfall, Cave of Solitude solutions tend to blow up in your face.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;If we come back to the customer every 2 to 4 weeks, we can both learn about the other side of the transaction:&lt;/p&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;I can teach the customer how the process works, what is possible, what is easy and isn’t going to happen. If you are going to buy custom software you need to learn the process.  It is like buying a new building; you aren’t going to use the gold plated faucets in the penthouse when we are still pouring concrete (I will restrain myself from going on for hundreds of words of half baked analogies).&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The customer can teach me more about his business, what he expected the software to do and I missed on the first time around. What is important? What is a nice to have? I may have the opportunity to see the processes that are too complex to explain.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Customers like to feel that they are part of the process. If you are going to spend a few grand on something, you want a sense of what is going on. Buying custom software is a big part of the company’s activities and the owner may want to boast about it on his blog on in the local watering hole.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;p&gt;If we started at ground zero and only used Scrum like sprints but no initial framework, the first couple of sprints would give the customer little sense of satisfaction.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-2890158249366438290?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/2890158249366438290/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=2890158249366438290' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2890158249366438290'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/2890158249366438290'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2009/04/on-small-low-margin-projects-part-2.html' title='On Small, Low Margin Projects'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-5565091248372353735</id><published>2009-04-12T01:42:00.001-07:00</published><updated>2011-01-04T20:25:59.189-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='High Level'/><category scheme='http://www.blogger.com/atom/ns#' term='Building Software'/><category scheme='http://www.blogger.com/atom/ns#' term='Small Projects'/><category scheme='http://www.blogger.com/atom/ns#' term='Small Business'/><title type='text'>On Small, Low Margin Projects</title><content type='html'>&lt;h2&gt;Part 1: The Problem&lt;/h2&gt;&lt;p&gt;I have been involved in some small (low margin) projects for small business customers using a classic Waterfall type process where we get all of requirements from the customer and go into our digital cave for a few months to write our masterpiece. When we came back to the customer (usually late) to show them their shinny new program, we find that we got it wrong. On one program, we get calls from the customer as he discovers features.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The customer can’t tell us what they want in language we understand; they may know what they want, but not in our language. The customer may not have any experience buying custom software. We don’t know the business and its problems well enough. I think the effects of these problems can be mitigated by delivering more often (a la Agile).&lt;br /&gt;&lt;/p&gt;&lt;p&gt;If we were to go more agile, we would need a way to get something to the customer quickly.  I don’t think a customer in this market would be impressed if, after the first sprint, I showed him a base list window, a base edit window and basic security.  We need a base framework and possibly some modules that exist before the first sprint for the customer.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-5565091248372353735?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/5565091248372353735/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=5565091248372353735' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5565091248372353735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5565091248372353735'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2009/04/on-small-low-margin-projects-part-1_7026.html' title='On Small, Low Margin Projects'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-6159184083710109559</id><published>2009-03-25T20:53:00.001-07:00</published><updated>2011-01-07T06:38:54.947-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Economy'/><category scheme='http://www.blogger.com/atom/ns#' term='CEO Pay'/><category scheme='http://www.blogger.com/atom/ns#' term='Non-Technical'/><title type='text'>Earn CEO Pay Level from Home</title><content type='html'>&lt;p&gt;As I was riding the bus to work I saw the sign above. I didn't make the call because I know that it some sort of a scam; I am still curious as how you would do this. Since some CEOs are now earning the princely sum of $1, I thought I would share some of my ideas:&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Go to several convience stores and look for the little cup that says "Give a Penny, Take a Penny" and take all of the pennies.  After 10 or 20 stores, you may earn your CEO's pay&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Rummage through your couch for change.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Rummage through your car for change.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Rummage through your friend's and family's couchs and cars.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Use your God given talents, for example: &lt;ol&gt;&lt;li&gt;Get your trusty old Marine Band Harmonica, a hat, cardboard and a Sharpie.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;With the Sharpie, write "Give me a CEO's Pay Level and I will stop playing" on the cardboard.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Get on a bus, subway or some other place where it diffcult to leave, display the sign, put out the hat and start playing.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt; If you play like me, there is a high risk of incarceration; with Correctional Industries pay rates, you can earn your CEO's pay in 5 or 6 hours of work&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-6159184083710109559?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/6159184083710109559/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=6159184083710109559' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/6159184083710109559'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/6159184083710109559'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2009/03/earn-ceo-pay-level-from-home.html' title='Earn CEO Pay Level from Home'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-8657905325960875718</id><published>2009-03-14T16:45:00.001-07:00</published><updated>2011-01-07T06:30:30.484-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Social Media'/><category scheme='http://www.blogger.com/atom/ns#' term='Non-Technical'/><title type='text'>Trying to get socially modern</title><content type='html'>&lt;h2&gt;What I'm doing, part 1.5&lt;/h2&gt;&lt;p&gt;Besides Stack Overflow, I've been trying to actually write the blog and use twitter.&amp;nbsp; I'm actually writing to this blog (sort of) and I have created over 15 updates in twitter as jrcs3.&amp;nbsp; I'm following almost 10 people and have more than 2 people following me. So far I've taken a lot more than I've given. &lt;br /&gt;&lt;/p&gt;&lt;p&gt;I developed tunnel vision over the past few years.  Get the code out and get on with my life.  I work mainly in C# 2.0 in both ASP.NET and WinForms (no WPF yet).  I also have a client that needs me to work in Access 97 and a SQL 200 ..... enough all ready&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Anyway, with the ecomomy really freaking out, I need to look outside of my formally safe world of oldtime geekdom and look out to the wider world.   I can go on about the scary stoff, but I am also intereted in the new opportunities that the ecomonic stress can create.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-8657905325960875718?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/8657905325960875718/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=8657905325960875718' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/8657905325960875718'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/8657905325960875718'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2009/03/trying-to-get-socially-modern-what-i.html' title='Trying to get socially modern'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-4110206466575986049</id><published>2009-03-01T20:17:00.001-08:00</published><updated>2011-01-04T20:27:33.022-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='What I&apos;m Doing'/><category scheme='http://www.blogger.com/atom/ns#' term='StackOverflow'/><title type='text'>StackOverflow</title><content type='html'>&lt;h2&gt;What I'm doing. Part 1&lt;/h2&gt;&lt;p&gt;For the past 6 months or so, I have been playing with &lt;a href="http://stackoverflow.com"&gt;StackOverflow&lt;/a&gt;. I don't know that I've really gotten into it, but I still find it interesting.&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;Structured Discussion&lt;/h2&gt;&lt;p&gt;It's like a discussion board but there are more rules and other forms of structure.  Some of it is built into the application but most of it is enforced by the powerful menders of the community (see Badges and Reputation).  Duplicate questions can also be closed as duplicate, so the answer is gathered in 1 place (though I would like to see them tighten up the support for this so it is easier to get to the parent question).&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The discussion is pretty tightly focused on programming; whenever a non-programming question is asked it will either be voted down or closed by the powerful.  It is good thing that the site stays on task, but there are times when "fun" questions are closed and I would have liked to see them live on.  But, what is fun for one is noise for someone else; I can find "fun" someplace else.&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;Voting&lt;/h2&gt;&lt;p&gt;Users of the system have to power to vote for or against any question or answer on the system.  Questions with a lot of votes are considered "hot" and the questions with a lot of down votes end up in some sort of puritory. The users of the site decide what gains capital on SO.  Voting also generated (and destroys) reputation.&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;Badges and Reputation&lt;/h2&gt;&lt;p&gt;This is one of the official ways of controlling our behavior are Badges and Reputation.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;For the most part, you get (and loose) repuptation through voting.  Your reputation is dispalyed next to your profile. You are given more power as you gain repretation. The early powers are basic things like voting, leaving comments, the later powers are the godlike power of an administrator. As you do things to earn reputation, you are invested in site and are more likely to use your powers good.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;You can earn badges by doing certain things that the sight owners want you to do.  Your badge info is next to your reputation on your profile.  Like the Olympics, you they come in bronze, silver and gold.  The bronze metals are for firsts (getting through basic training, solder's first parashoot jump, etc.), moderate metrics of your questions and answers.  Silver is for bigger first and bigger metrics.  Gold for the big stuff.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-4110206466575986049?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/4110206466575986049/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=4110206466575986049' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/4110206466575986049'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/4110206466575986049'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2009/03/stackoverflow-what-i-doing-part-1.html' title='StackOverflow'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-62997182269764042</id><published>2009-02-18T22:08:00.001-08:00</published><updated>2011-01-07T06:29:29.776-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Writing'/><category scheme='http://www.blogger.com/atom/ns#' term='What I&apos;m Doing'/><category scheme='http://www.blogger.com/atom/ns#' term='Non-Technical'/><title type='text'>What I'm Doing</title><content type='html'>&lt;p&gt;The problem: I need to write to learn, but when I write, try to hard to make it perfect and eventually give up. The words get in the way of the idea. In fact, I spent several cycles trying to get this paragraph right and I am not satisfied with it even now.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I need to write to get over the hump of the perfect. I need to write %$#! so I can eventally write well. One way to learn is to explain it. Yada Yada Yada.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;So I'm going to write a series of blog posts about what I'm doing.  Mabie something will stick . .  .&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-62997182269764042?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/62997182269764042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=62997182269764042' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/62997182269764042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/62997182269764042'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2009/02/what-i-doing.html' title='What I&apos;m Doing'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-5808718809310875910</id><published>2008-12-03T22:23:00.001-08:00</published><updated>2011-01-07T06:34:16.531-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Psycho Analysis'/><title type='text'>Test Data and Tea Leaves</title><content type='html'>When I am testing my own software (or someone else's for that matter), I tend to use name like&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Darth Smith&lt;/li&gt;&lt;li&gt;Lisa Simpson&lt;/li&gt;&lt;li&gt;OJ Simpson&lt;/li&gt;&lt;li&gt;Jill Hill&lt;/li&gt;&lt;li&gt;Garth Vader&lt;/li&gt;&lt;li&gt;Darth Brooks&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Maryann *&lt;/li&gt;&lt;li&gt;Shawn Carter&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;And street addresses like:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Box 1&lt;/li&gt;&lt;li&gt;PO Box 1111&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Box 1234&lt;br /&gt;&lt;/li&gt;&lt;li&gt;742 Evergreen Terrace&lt;/li&gt;&lt;li&gt;1313 Mockingbird Lane&lt;/li&gt;&lt;li&gt;1313 North 13th Street&lt;/li&gt;&lt;li&gt;234118 NE 12145th Avenue Court Suite 31712&lt;/li&gt;&lt;/ul&gt;And cities like&lt;br /&gt;&lt;ul&gt;&lt;li&gt;LA&lt;/li&gt;&lt;li&gt;Mockingbird Heights&lt;/li&gt;&lt;li&gt;Springfield&lt;/li&gt;&lt;li&gt;NYC&lt;/li&gt;&lt;li&gt;Uppersex&lt;/li&gt;&lt;li&gt;North South Bend&lt;/li&gt;&lt;li&gt;Old Young America&lt;/li&gt;&lt;li&gt;Terror Lake&lt;/li&gt;&lt;li&gt;Darth's Church&lt;/li&gt;&lt;/ul&gt;There are only 50 US states and a dozen Canadian provinces and the State of Confusion, so I have less chance to improvise here.&lt;br /&gt;Internet Data:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;dvader@deathstar.gov (some argue it should be dvader@deathstar.mil)&lt;/li&gt;&lt;li&gt;a@b.c&lt;/li&gt;&lt;li&gt;http://www.starfleet.edu&lt;/li&gt;&lt;li&gt;jill@enemyster.bus&lt;/li&gt;&lt;li&gt;helen@heckhole.co.uk&lt;/li&gt;&lt;li&gt;http://www.nile.com&lt;/li&gt;&lt;li&gt;null://foo.az&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;What can you tell about a developer or tester based on common test data.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;I use "LA" because it is easy, often grouped with "Box 1"&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The name "Jill" shows up often, my name is "Jack", do I need to say more.&lt;/li&gt;&lt;li&gt;I'm old enough to think of "Darth" as a name and not a title.&amp;nbsp; I am more of a Star Wars geek than an Star Trek geek; there are times when "Kirk" shows up, so I am not a purist.&amp;nbsp; (I think I've even used Darth Spock at one point.)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;When I'm not in a hurry, I like to come up with the long complex addresses that are found in sprawling cities&lt;/li&gt;&lt;li&gt;Sometimes I will play off existing existing domains like nile or enemyster and I tend to use upper level domains other than .com&lt;/li&gt;&lt;li&gt;I watched too much TV as a kid.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-5808718809310875910?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/5808718809310875910/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=5808718809310875910' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5808718809310875910'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/5808718809310875910'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2008/12/test-data-and-tea-leaves.html' title='Test Data and Tea Leaves'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-113340892049327270</id><published>2005-11-30T19:48:00.000-08:00</published><updated>2011-01-04T20:39:42.864-08:00</updated><title type='text'>Waiting ...</title><content type='html'>&lt;p&gt;I hate to wait!&amp;nbsp;&amp;nbsp;I hate uncertainty!&amp;nbsp;&amp;nbsp;I hate being chained to the phone.&lt;/p&gt;&lt;p&gt;Yesterday I got a phone call from one of the headhunters that I have been working with telling me that I was on a list of three coders for a job in Des Moines.&amp;nbsp;&amp;nbsp;The department wanted all three but Management had only approved two.&amp;nbsp;&amp;nbsp;I was not told my position on the list.&lt;/p&gt;&lt;p&gt;This morning I received a couple of phone calls from a couple of headhunters on this same requirement.&amp;nbsp;&amp;nbsp;I was asked about my commitment to going to Iowa to do the work and ability to get there quickly.&amp;nbsp;&amp;nbsp;I was also told to be available for the whole day.&amp;nbsp;&amp;nbsp;I feel like a caged animal pacing around in my apartment all day.&amp;nbsp;&amp;nbsp;And I didn’t get the bloody phone call.&lt;/p&gt;&lt;p&gt;Right now I still don’t know how the whole thing played out.&amp;nbsp;&amp;nbsp;Was I #3 and they would only take 2?&amp;nbsp;&amp;nbsp;Are they going to wait until both 1 and 2 accepted to tell me I am the odd man out?&amp;nbsp;&amp;nbsp;Did the client resent being pressured by the headhunters?&amp;nbsp;&amp;nbsp;Will I find out tomorrow that everything’s groovy?&lt;/p&gt;&lt;p&gt;Normally I hate cell phones: I like the idea of being out of touch.&amp;nbsp;&amp;nbsp;This is a time where it would come in handy.&amp;nbsp;&amp;nbsp;The problem with cell phones is that you have to buy in to the whole thing.&amp;nbsp;&amp;nbsp;I can’t just get a cell phone for a day or two and not drink the cell phone cool-aid.&amp;nbsp;&amp;nbsp;If I give someone my cell phone number, they would expect to be able to use it any time.&lt;/p&gt;&lt;p&gt;I guess I could get a cell phone and have my land line forward it when I want to play that game, but I really can’t justify the expense being a free agent programmer who hasn’t paid off the dot com bust yet.&amp;nbsp;&amp;nbsp;I will put up with the dark side of not having a cell phone to avoid the dark side of having one.&lt;/p&gt;&lt;p&gt;Now I have to get ready for an early phone interview with a company in Cleveland.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-113340892049327270?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/113340892049327270/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=113340892049327270' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/113340892049327270'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/113340892049327270'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2005/11/waiting.html' title='Waiting ...'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-113331396900047356</id><published>2005-11-29T17:26:00.000-08:00</published><updated>2011-01-04T20:34:25.688-08:00</updated><title type='text'>Christmas time is here!</title><content type='html'>&lt;p&gt;Christmas time is here, and it’s time to for us to go out and max out our credit cards.&amp;nbsp;&amp;nbsp;As a free agent programmer, I’m really concerned about my budget.&amp;nbsp;&amp;nbsp;Every time I see an ad suggesting that a 72” high-def plasma TV would be the “perfect gift” for the caretaker of my building, I am reminded of the fact that I don’t have much $$$, and I won’t have much $$$ until I can find my next gig.&lt;/p&gt;&lt;p&gt;It seams to me that Christmas was all about guilting me into buying stuff that no one needs for all my casual relations.&amp;nbsp;&amp;nbsp;The whole retail economy is based on our buying ridiculous gift for our family, friends, co-workers, enemies, etc.&lt;/p&gt;&lt;p&gt;I see ads on the tube that suggest things like big ass TV’s, monster computers, luxury cars, etc.&amp;nbsp;&amp;nbsp;I’m surprised that I haven’t seen ads for real estate (wouldn’t you love to get a Des Moines bungalow this year).&lt;/p&gt;&lt;p&gt;I know some people who give as a competitive sport (and I can’t figure out how to become the target of their giving).&amp;nbsp;&amp;nbsp;I knew two guys who were life long friends and they would try to give the other person the better gift; that is a contest I could enjoy loosing.&lt;/p&gt;&lt;p&gt;I refuse to take Christmas gifting seriously.&amp;nbsp;&amp;nbsp;I do give everyone in my family something for Christmas (I even wrap up junk for my ma, she likes to open presents); I just don’t go overboard.&amp;nbsp;&amp;nbsp;If I were ever in a position to be generous, I would give for other occasions.&amp;nbsp;&amp;nbsp;I think this holiday overload corrupts the whole idea of the holiday.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-113331396900047356?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/113331396900047356/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=113331396900047356' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/113331396900047356'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/113331396900047356'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2005/11/christmas-time-is-here.html' title='Christmas time is here!'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-113285657461168051</id><published>2005-11-24T10:22:00.000-08:00</published><updated>2011-01-04T20:32:15.702-08:00</updated><title type='text'>Thanksgiving Heresy</title><content type='html'>&lt;p&gt;It’s Thanksgiving and I’m not having turkey.&lt;/p&gt;&lt;p&gt;I know that it is un-American.&amp;nbsp;&amp;nbsp;With this confession, I am risking W’s black helicopters coming to my apartment and taking me to Guantanamo Bay.&lt;/p&gt;&lt;p&gt;How did I loose faith in such an important American Institution?&amp;nbsp;&amp;nbsp;Well, my mother didn’t like to cook.&amp;nbsp;&amp;nbsp;The only thing she cooked well was Lasagna, so that is what we had for Thanksgiving.&amp;nbsp;&amp;nbsp;We were thankful to have food that tasted good instead of carbonized turkey, dressing stew, etc.&lt;/p&gt;&lt;p&gt;(I don’t have Lasagna every year; I’ve also had pizza, lamb, salmon, steak, more pizza, etc.)&lt;/p&gt;&lt;p&gt;My other un-American confession: I will not do any shopping on Friday.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-113285657461168051?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/113285657461168051/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=113285657461168051' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/113285657461168051'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/113285657461168051'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2005/11/thanksgiving-heresy.html' title='Thanksgiving Heresy'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-113220883791356651</id><published>2005-11-16T22:27:00.000-08:00</published><updated>2011-04-03T08:45:40.864-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='The TC'/><category scheme='http://www.blogger.com/atom/ns#' term='Frontpage'/><title type='text'>The TC</title><content type='html'>&lt;p&gt;Today I got an email from a Monster with a job description from an organization called The Technical Committee or “The TC”.&amp;nbsp;&amp;nbsp;If you don’t know what the TC is, it’s an organization that ensures that Microsoft follows the 2002 settlement on behalf of the various plaintiffs.&amp;nbsp;&amp;nbsp;You can read all about it on their site &lt;a href="http://www.thetc.org/"&gt;http://www.thetc.org&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;If you want to have some fun with their site:&lt;/p&gt;&lt;p&gt;Browse to their site using FireFox (or most other W3C compliant browser, I also tried it with Amaya, I don’t have Opera) and click on the link “What is The TC?”,&amp;nbsp;&amp;nbsp;Where do you go? Nowhere (the link is to &lt;a href="Y:\Web\Thetc.htm"&gt;file:///Y:/Web/Thetc.htm#What is the TC&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;Do a View Page Source.&amp;nbsp;&amp;nbsp;In the code you will see:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;META content=FrontPage.Editor.Document name=ProgId&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;That means they used Microsoft FrontPage. If you view the page in IE (which will render the page correctly) you will see:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;meta name="GENERATOR" content="Microsoft FrontPage 5.0"&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;FrontPage is this truly evil software that implements themes with out the help of CSS (or XLST) and only works properly in IE.&amp;nbsp;&amp;nbsp;So, if you are a citric of Microsoft and want to follow the adventures of this important committee you need to use a Microsoft browser!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-113220883791356651?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/113220883791356651/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=113220883791356651' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/113220883791356651'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/113220883791356651'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2005/11/tc.html' title='The TC'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18907707.post-113182981383612492</id><published>2005-11-12T13:04:00.000-08:00</published><updated>2011-01-04T20:36:50.964-08:00</updated><title type='text'>So I decided to Blog</title><content type='html'>&lt;p&gt;Allow me to introduce myself ...&lt;/p&gt;&lt;p&gt;I'm Jack Stephens, an unemployed ASP.NET / C# programmer currently located in Spokane.&lt;/p&gt;&lt;p&gt;So I decided to cave in and start a blog.&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;I gave into the overwhelming pressure of Internet fashion and this is the unfortunate result.&lt;/p&gt;&lt;p&gt;Starting a blog begs questions, like:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Do I have anything to say? No.&lt;/li&gt;&lt;li&gt;What will I blog about?&amp;nbsp;&amp;nbsp;I don’t know.&amp;nbsp;&amp;nbsp;Probably what I know:&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Being unemployed and my quest to find a job.&lt;/p&gt;&lt;p&gt;Programming and the technologies that I use: The Evil Empire’s .NET.&amp;nbsp;&amp;nbsp;Including: the .NET Framework ASP.NET, ADO.NET, C#, VB.NET, etc.&lt;/p&gt;&lt;p&gt;Geekdom in Spokane (and wherever I end up after the job search)&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Will anyone outside of my family ever read this?&amp;nbsp;&amp;nbsp;Probably not.&lt;/li&gt;&lt;li&gt;Will anyone &lt;u&gt;in &lt;/u&gt;my family ever read this? Again, probably not.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;So here’s my blog.&amp;nbsp;&amp;nbsp;I know that I’m late into the game, but I need to get into it someone if I don’t want to be totally lame.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18907707-113182981383612492?l=brochure.jrcs3.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://brochure.jrcs3.com/feeds/113182981383612492/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18907707&amp;postID=113182981383612492' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/113182981383612492'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18907707/posts/default/113182981383612492'/><link rel='alternate' type='text/html' href='http://brochure.jrcs3.com/2005/11/so-i-decided-to-blog.html' title='So I decided to Blog'/><author><name>Jack Stephens</name><uri>http://www.blogger.com/profile/04996728441112030246</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
