<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-7881153019980313926</atom:id><lastBuildDate>Tue, 10 Nov 2009 14:00:50 +0000</lastBuildDate><title>Random Acts of Coding</title><description>Random ramblings about technology with a sprinkle of coding.</description><link>http://randomactsofcoding.blogspot.com/</link><managingEditor>James.R.Eggers@gmail.com (J. Eggers)</managingEditor><generator>Blogger</generator><openSearch:totalResults>47</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/RandomActsOfCoding" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-7454883242110036582</guid><pubDate>Tue, 10 Nov 2009 14:00:00 +0000</pubDate><atom:updated>2009-11-10T08:00:50.657-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Reviews</category><category domain="http://www.blogger.com/atom/ns#">Commentary</category><title>Iowa Code Camp: Session Overview</title><description>&lt;p&gt;The &lt;a href="http://iowacodecamp.com" target="_blank"&gt;Iowa Code Camp&lt;/a&gt; was held on&amp;#160; November 7th, 2009 in Des Moines, IA.&amp;#160; With a capacity crowd and a lot of great sessions, it ended up being an awesome time with a lot of great presentations and conversations.&amp;#160; Like conference of this type, you never have time to hit all of the sessions you may want to; however, the ones I was able to attend were still awesome.&amp;#160; Below is an overview on each one. &lt;/p&gt;  &lt;h3&gt;Getting Started With Behavior Driven Development by Lee Brandt&lt;/h3&gt;  &lt;p&gt;In his presentation, Lee provided a good introduction to the concepts of &lt;abbr title="Behavior Driven Development"&gt;BDD&lt;/abbr&gt;.&amp;#160; The presentation focused on the origin of &lt;abbr title="Behavior Driven Development"&gt;BDD&lt;/abbr&gt;, where it fits, and how it's an evolution of &lt;abbr title="Test Driven Development"&gt;TDD&lt;/abbr&gt; from the beginning which helped to truly set the stage.&amp;#160; For those that have done &lt;abbr title="Test Driven Development"&gt;TDD&lt;/abbr&gt; for a bit, it provided a great introduction into bridging the gap between the business case and the code by using tests as a spec.&amp;#160; Through this and Lee's stressing of an Ubiquitous Language as described in various &lt;abbr title="Domain Driven Design"&gt;DDD&lt;/abbr&gt; circles, he showed how &lt;abbr title="Behavior Driven Development"&gt;BDD&lt;/abbr&gt; can be used in order to provide a technique that helps to show the client what the application will do once done as well as a pseudo-burndown chart of what hasn't been finished yet.&amp;#160; I'm definitely looking forward to exploring &lt;abbr title="Behavior Driven Development"&gt;BDD&lt;/abbr&gt; again in the near future.&lt;/p&gt;  &lt;p&gt;Twitter: &lt;a href="http://www.twitter.com/LeeBrandt" target="_blank"&gt;@LeeBrandt&lt;/a&gt;     &lt;br /&gt;Blog: &lt;a href="http://www.geekswithblogs.net/leesblog/Default.aspx" target="_blank"&gt;http://www.geekswithblogs.net/leesblog/Default.aspx&lt;/a&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Going From 0 to 100 Dollars an Hour with .Net you Didn't Know by Mitchel Sellers&lt;/h3&gt;  &lt;p&gt;This session was a good session; however, it wasn't as advanced as I was hoping for.&amp;#160; The abstract of the session focused around using advanced features of .net in order to make you more productive; however, I was hoping for some additional tidbits beyond that of the abstract.&amp;#160; The primary items focused on this presentation were new tips and tricks introduced by .Net 3.5 such as Lambdas, Self Containing Properties, and LINQ. All of these items I already knew and have used them in the past which is why I was hoping for a few tidbits beyond such. That being said though it WAS a good session with a lot of good code samples to convey each concept and technology.&amp;#160; I still learned at least one new thing and was reminded about a few other things as well. While it didn't meet my (probably unrealistic) hopes, I cannot deny that Mitchel's presentation definitely educated a number of people who were also in his session that was overfilled.&lt;/p&gt;  &lt;p&gt;Twitter: &lt;a href="http://www.twitter.com/MitchelSellers" target="_blank"&gt;@MitchelSellers&lt;/a&gt;     &lt;br /&gt;Blog: &lt;a href="http://www.MitchelSellers.com" target="_blank"&gt;http://www.MitchelSellers.com&lt;/a&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Open Spaces&lt;/h3&gt;  &lt;p&gt;I've been to a few open spaces discussion and have came to the conclusion that some will be good, some will be bad, and others will be between or outside of those labels.&amp;#160; The open spaces session at the Iowa Code Camp was an in between session.&amp;#160; The size of the group was smaller and comprised of a diverse set of primary skills which isn't always a bad thing though the topics in discussion didn't flow like I have experienced in other places.&amp;#160; We had a good conversation about how to get the information to the people that don't come to conferences or how to encourage them to come.&amp;#160; We also talked a little bit about MEF, coding war stories, and some of the side effects of completely rewriting/redesigning an externally facing website.&amp;#160; Lastly we talked a little bit about Kanban vs Scrum and the paradox of software estimation.&amp;#160; All in all there was some good things that came up during the conversation; however, part of me was hoping that more people would have been involved in the discussion and the topics would have been more discussion/problem solving based to an extent. &lt;/p&gt;  &lt;h3&gt;Intro to ASP.Net MVC by Chris Sutton&lt;/h3&gt;  &lt;p&gt;I've dabbled in ASP.Net MVC and have wanted to learn more about it; however, &lt;strike&gt;finding&lt;/strike&gt; making the time for such is not always easy.&amp;#160; Everything that I've learned about such has either been about the MVC pattern itself, or about other frameworks in general like &lt;a title="Ruby On Rails" href="http://www.rubyonrails.org" target="_blank"&gt;Rails&lt;/a&gt; or &lt;a title="The Django Project" href="http://www.djangoproject.com" target="_blank"&gt;Django&lt;/a&gt;.&amp;#160; With only a few MVC Videos watched and about 3hrs worth of coding so far, I decided checking out another intro session wouldn't be a bad idea for me.&amp;#160; Chris Sutton did a great job with the presentation.&amp;#160; He explained the MVC pattern very well as well as describing how the ASP.Net MVC framework relates to it and ASP.Net in general.&amp;#160; He showed a couple of the typical demos for this level of session and afterwards answered all of the questions I had about the next step.&amp;#160; All in all it was a very good session and can't wait until I can make time for using such.&lt;/p&gt;  &lt;p&gt;Twitter: &lt;a href="http://www.twitter.com/ChrisSutton" target="_blank"&gt;@ChrisSutton&lt;/a&gt;     &lt;br /&gt;Blog: &lt;a href="http://subjunctive.wordpress.com" target="_blank"&gt;http://subjunctive.wordpress.com&lt;/a&gt;&amp;#160; &lt;/p&gt;  &lt;h3&gt;Silverlight for WPF Developers by Kirstin Juhl&lt;/h3&gt;  &lt;p&gt;In my opinion, none of the last block of sessions really looked appealing to me.&amp;#160; It wasn't the fact that I didn't think any were going to be good, it was just that I wasn't interested in the topics at hand.&amp;#160; I ultimately decided to check out Kirstin's presentation on what WPF Developers would need to know to transition into the Silverlight space.&amp;#160; While I have only dabbled in WPF a little bit, I knew a number of differences and knew the power of XAML was greater in WPF than Silverlight.&amp;#160; The decision to go here was my current adventures in Silverlight and see what I may be able to learn.&amp;#160; All in all, the session was pretty good for the purpose Kirstin was targeting.&amp;#160; She did a good job at explaining the differences as well as provide information on how to share components between Silverlight and WPF applications (something I knew was possible but hadn't seen an example of up to this point).&amp;#160; Good presentation overall.&lt;/p&gt;  &lt;p&gt;Twitter: &lt;a href="http://www.twitter.com/KirstinJ" target="_blank"&gt;@KirstinJ&lt;/a&gt;     &lt;br /&gt;Blog: &lt;a href="http://www.geekswithblogs.net/Kirstinj/Default.aspx" target="_blank"&gt;http://www.geekswithblogs.net/Kirstinj/Default.aspx&lt;/a&gt;&amp;#160; &lt;/p&gt;  &lt;h3&gt;Overall:&lt;/h3&gt;  &lt;p&gt;Overall, I had a great time at the Iowa Code Camp.&amp;#160; For being a free conference, the presentations, facilities, and of course the prizes were all top notch.&amp;#160; It was a great conference with some amazingly talented speakers and attendees.&amp;#160; All in all I can't wait to head to the next one in the April/May/June timeframe.&amp;#160; Hopefully some of the presentations I'm working on will be ready by then since I'd love to present one.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-7454883242110036582?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/11/iowa-code-camp-session-overview.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-5289074571622670699</guid><pubDate>Fri, 06 Nov 2009 16:25:00 +0000</pubDate><atom:updated>2009-11-06T10:28:53.589-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Commentary</category><title>Reviewing This Year's Goals (2009)</title><description>&lt;p&gt;Back in January, I created &lt;a href="http://randomactsofcoding.blogspot.com/2009/01/goals-for-new-year.html"&gt;this post&lt;/a&gt; focusing around what I was hoping to accomplish this year.&amp;#160; I was going through my old posts and stumbled across it.&amp;#160; I figured it would be a good time to look over them once again to gauge my progress along with what else I may have done so far this year.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h4&gt;Learn F#:&lt;/h4&gt;&lt;p&gt;While I do not claim to be an authority of F# by any means, I do feel comfortable in saying that I learned the bulk of the language and be able to determine where it makes sense to use it.&amp;#160; If time allows, I can see myself using it more and more; however, for right now, I've definitely learned a lot from such and can focus on learning other things.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h4&gt;Learn DDD:&lt;/h4&gt;&lt;p&gt;This one I am really only about 1/2 done with.&amp;#160; While I have went through the information and can understand the concepts involved, I haven't had a good way of applying such yet.&amp;#160; There's existing applications that could benefit from the practices of DDD; but I haven't pushed myself into applying such on a new project yet.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h4&gt;Learn Silverlight 2:&lt;/h4&gt;&lt;p&gt;I got sidetracked and ended up procrastinated on this one.&amp;#160; While I wanted to learn SL2, I still was a bit apathetic towards it since SL1 wasn't very impressive to me.&amp;#160; Thankfully, I've seen a lot of what Silverlight 3 can do and am going all out on learning more about it.&amp;#160; Except some posts on Silverlight 3 soon.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h4&gt;Other Things:&lt;/h4&gt;&lt;p&gt;So what else have I been up to so far this year?&amp;#160; Looking back I have worked on some open source projects (namely my SchemaSpy Task for NAnt and contributing to .Net Migrations over on codeplex).&amp;#160; I've also focused a lot of time on keeping up to date on .Net 3.5 and other technologies that I wasn't able to fully take advantage of at a previous employer.&amp;#160; Lastly, I've really been focusing on TDD and just writing better code in general.&amp;#160; There's always room for improvements but being able to learn from what's being talked about over the past year is what's important.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;h4&gt;Things on the Horizon...&lt;/h4&gt;&lt;h4&gt;Learning MEF:&lt;/h4&gt;&lt;p&gt;The Microsoft Extensibility Framework (MEF) provides some great opportunities to make very extensible applications.&amp;#160; With a need to make a project extensible, I'm definitely going to be focusing on understanding MEF more.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h4&gt;Learning Silverlight 3:&lt;/h4&gt;&lt;p&gt;I'm already in the process of working in Silverlight 3 but I have only started to write applications with such.&amp;#160; Just like a person who has finished their first true ASP.Net application, there's always room for improvements and things that one can learn to make things better.&amp;#160; I'm at that stage where there's a lot more I can learn about and I'm all for it since Silverlight 3 is awesome.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h4&gt;More SchemaSpy:&lt;/h4&gt;&lt;p&gt;My SchemaSpy post earlier this year is one of my highest trafficked posts as well as one that I refer back to all of the time.&amp;#160; I'm planning on answering a few outstanding questions associated with that post and also see what else I can do with the tool to make things easier for everyone.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h4&gt;&amp;lt;Unknown&amp;gt; Things:&lt;/h4&gt;&lt;p&gt;I always leave myself open to the unknown and unforeseen opportunities.&amp;#160; While November and December are usually swamped for me, I never know when inspiration will hit me and I learn something new. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-5289074571622670699?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/11/reviewing-this-year-goals-2009.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-7032404615607288674</guid><pubDate>Fri, 30 Oct 2009 12:55:00 +0000</pubDate><atom:updated>2009-10-30T08:07:03.764-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Reviews</category><category domain="http://www.blogger.com/atom/ns#">Automation</category><category domain="http://www.blogger.com/atom/ns#">Continuous Integration</category><title>Reviewing UppercuT - A Build Framework Based On NAnt</title><description>&lt;p&gt;Earlier this week I went to the Kansas City .Net User Group meeting where the topic of discussion was UppercuT, a build management framework created by Rob Reynolds.  The discussion was pretty good and Rob did a good job at showing a number of demonstrations on how to use the various aspects of UppercuT.  All in all, I feel like the presentation got the point across as to the typical why/when/how/etc. questions.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;What Is UppercuT?&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;UppercuT is a build management framework based on NAnt.  It was created in order to establish a consistent way to build .Net applications with a minimum amount of configuration while providing areas for extensibility.  In addition to just compiling, UppercuT provides a number of options to manage application versioning, automated testing, and code packaging.  While it can be extended to include such steps through NAnt, UppercuT doesn't deploy code...it only stages it since every company/project's deployment strategies may be different.  One nice thing that UppercuT does do in terms of deployments though is provide you instructions on how to wire it up to CruiseControl.net.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;When Should UppercuT Be Used?&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;UppercuT provides a way for people who have not started to take advantage of automated builds to do so quickly.  Because of this, it's best suited for projects that don't have automated build systems integrated into them yet.  With some configuration changes, it is possible to integrate with your current scripts; however, changes would need to be made on both side to the point where it would honestly be easier to convert your current scripts to custom steps for UppercuT to take advantage on.  If you currently use some build framework like MSBuild or NAnt, I would probably recommend at least checking out UppercuT to see if it's a good fit; however, if you or your company already have some system that works for you in place, it may be better to just keep with what you have.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Where Can I Download and Learn More?&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;You can find more information on Uppercut by going to it's project website at &lt;a href="http://ProjectUppercuT.org/" target="_blank"&gt;http://ProjectUppercuT.org&lt;/a&gt;.  In addition, you can check out Rob's blog over at &lt;a href="http://ferventcoder.com/" target="_blank"&gt;http://ferventcoder.com/&lt;/a&gt; as well as on Twitter by following &lt;a href="http://www.twitter.com/ferventcoder" target="_blank"&gt;@ferventcoder&lt;/a&gt; and &lt;a href="http://www.twitter.com/ProjectUppercuT" target="_blank"&gt;@ProjectUppercuT&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/10/reviewing-uppercut-build-framework.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'Reviewing UppercuT - A Build Framework Based On NAnt';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = 'A review/opinion of UppercuT, a Build Framework based on NAnt developed by Rob Reynolds.';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/links/widgets/zoneit.js"&gt;&lt;/script&gt; &lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f10%2freviewing-uppercut-build-framework.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f10%2freviewing-uppercut-build-framework.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Random-Acts-of-Coding-Reviewing-UppercuT-A-Build-Framework-Based-On-NAnt"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Frandomactsofcoding.blogspot.com%2F2009%2F10%2Freviewing-uppercut-build-framework.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-7032404615607288674?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/10/reviewing-uppercut-build-framework.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-784688987359592281</guid><pubDate>Mon, 26 Oct 2009 03:13:00 +0000</pubDate><atom:updated>2009-10-27T09:10:00.640-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Commentary</category><title>Is Learning though a UI worth it?</title><description>&lt;p&gt;Do you remember the last time you learned a new, &lt;u&gt;back-end&lt;/u&gt; technology like Linq-to-Sql, Entity Framework, NHibernate, the Twitter API, or some other 3rd party API? How did you first go about learning it?&amp;#160; If you used some tutorial of some sort (be it a blog, video, or some other medium), how did you try it out?&amp;#160; Did they have create a basic web page to present the data from the API that you were consuming? If you DID create any form or UI to consume this API, here's two questions for you...&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;font size="4"&gt;How long did it take you to create that UI compared to writing the code that uses the API?       &lt;br /&gt;&lt;br /&gt;&lt;/font&gt;&lt;/li&gt;    &lt;li&gt;&lt;font size="4"&gt;Did you learn more about the API from the UI or from writing the code that actually interacted with the API?&lt;/font&gt;&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Now, let me restate that I'm aiming these questions specifically at back-end technologies.&amp;#160; Any technology that deals with any aspect of a UI (i.e. JavaScript, Silverlight, etc.) obviously depends on the UI and really does not apply. However, if you're NOT focused on a UI-dependent technology, why do you create a UI to learn something that doesn't require it?&lt;/p&gt;  &lt;p&gt;Don't get me wrong.&amp;#160; I was guilty of this as well and what I found is that I got sick and tired and bored spending so much time creating a UI and it would take me longer to get to the subject of my studies.&amp;#160; Throw in a dash of &lt;a title="Obsessive-Compulsive Disorder" href="http://en.wikipedia.org/wiki/Obsessive-compulsive_disorder" target="_blank"&gt;OCD&lt;/a&gt; or &lt;a title="Attention-deficit hyperactivity disorder" href="http://en.wikipedia.org/wiki/Adhd" target="_blank"&gt;ADHD&lt;/a&gt; because I couldn't just make a simple UI but needed some form of basic layout and color contrasts at the very least and it was a recipe of boredom.&amp;#160; It wasn't really until &lt;a title="Finally Understanding the Merits of TDD" href="http://randomactsofcoding.blogspot.com/2009/08/finally-understanding-merits-of-tdd.html" target="_blank"&gt;something clicked&lt;/a&gt; that I began to really realize that I learned more from the tests or the debugger while stepping through the code consuming these APIs than how the information was presented.&amp;#160; Sure it felt good when I could apply what I learned to a UI but applying the UI layer did not directly provide any value for me towards learning the API.&lt;/p&gt;  &lt;p&gt;But again, if it takes so much time and provides a greater opportunity for distractions, is it worth it to learn a back end process by means of applying such to a UI?&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/10/is-learning-though-ui-worth-it.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'Is Learning Through a UI Worth It?';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = 'When learning some form or back-end component, is it worth while to spend time applying the product to a UI?';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/links/widgets/zoneit.js"&gt;&lt;/script&gt; &lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f10%2fis-learning-though-ui-worth-it.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f10%2fis-learning-though-ui-worth-it.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Random-Acts-of-Coding-Is-Learning-though-a-UI-worth-it"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Frandomactsofcoding.blogspot.com%2F2009%2F10%2Fis-learning-though-ui-worth-it.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-784688987359592281?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/10/is-learning-though-ui-worth-it.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-8665070155855493245</guid><pubDate>Wed, 02 Sep 2009 13:42:00 +0000</pubDate><atom:updated>2009-09-03T09:42:54.671-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Commentary</category><category domain="http://www.blogger.com/atom/ns#">TDD</category><title>My Barriers to Learning TDD</title><description>&lt;p&gt;As a follow up to my &lt;a title="Finally Understanding the Merits of TDD" href="http://randomactsofcoding.blogspot.com/2009/08/finally-understanding-merits-of-tdd.html" target="_blank"&gt;previous post&lt;/a&gt; declaring that I finally &amp;quot;get&amp;quot; &lt;abbr title="Test Driven Development"&gt;TDD&lt;/abbr&gt; to some extent, I figured I'd reflect on the barriers that I have had up to this point which made it difficult for me to learn how to unit test in some effective manner as well as truly understanding the benefits of TDD practices.&amp;#160; Now, I am by no means claiming to be an expert in unit testing, mocking, or TDD.&amp;#160; I didn't open the refrigerator, drink some of the TDD-flavored Kool-Aid, and threw on a subsequent &lt;a title="Wikipedia: Square Academic Cap" href="http://en.wikipedia.org/wiki/Mortarboard" target="_blank"&gt;Mortarboard&lt;/a&gt; to illustrate that I've somehow graduated into this new, higher level of software development.&amp;#160; I'm still learning from others as well as my own &lt;strike&gt;errors&lt;/strike&gt; experiences just like everyone else.&amp;#160; The purpose of this is to reveal to others some of the issues that I had and hopefully provide some insight on how to overcome such.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;The Examples Are Too Simple&lt;/h3&gt;  &lt;p&gt;This barrier was by far the most difficult for me to overcome.&amp;#160; I would read up on all of the buzz about how to add unit tests to your code and how to apply unit testing into TDD.&amp;#160; I would follow the examples and understand it and be fine; however, I would always stall out whenever I tried to do it in a real world scenario. One day, I got extremely frustrated trying to fit all of this this together even if it looked like a square peg for a round hole to me at that time.&amp;#160; I began to wonder how unit testing in general would work on such complex real world objects and that's when it hit me.&amp;#160; Around this same time, I was diving into the &lt;a title="S.O.L.I.D. principles of Object Oriented Design" href="http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod" target="_blank"&gt;S.O.L.I.D. principles of Object Oriented Design&lt;/a&gt; and began to count the dependencies I had in the code.&amp;#160; The more I broke out the code into less complex objects that followed the principles, the easier it was for me to map the unit test examples that previously were &amp;quot;too simple&amp;quot; to my code.&amp;#160; The barrier wasn't so much that the examples were too simple as it was that my code that I was trying to directly apply the lesson to were too complex.&amp;#160; On the last project I had, I didn't apply unit testing to it; however, I tried to adhere to the S.O.L.I.D. principles as much as possible.&amp;#160; When I was trying to retrofit the tests into it, I was able to do it as well as find places where I didn't follow the S.O.L.I.D. principles as much as I thought I did.&amp;#160; Looking back, I probably wouldn't have had any of the refactoring issues I had after the fact if I had used TDD to provide a test-first basis for the object designs.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;But...This Class Uses the Database&lt;/h3&gt;  &lt;p&gt;This was another barrier for me that partially stems from the previous example.&amp;#160; Looking over the majority of Unit Testing and TDD books and blog posts out there, very few of them actually touch dependencies as common as a database.&amp;#160; Looking at my own code at the time, I had repository classes that handled all of the CRUD operations to the database as well as spit out the records as strongly typed collections (where necessary).&amp;#160; How do I test this class when there is such a deep dependency with the database?&amp;#160; I was truly perplexed by this issue and decided to ask &lt;a title="How could I refactor this factory-type method and database call to be testable?" href="http://stackoverflow.com/questions/1233486/" target="_blank"&gt;the question on StackOverflow&lt;/a&gt;.&amp;#160; The responses led me to realize that my class was doing 2 things; calling the database AND transforming the returned data in to a manner I needed.&amp;#160; By pushing the direct database calls to a separate class, I was able to mock away the database and make sure these particular class could be tested.&lt;/p&gt;  &lt;p&gt;Now, that only solved half of the issue.&amp;#160; I abstracted the dependency of those classes but I still had data provider classes that still interacted with the database.&amp;#160; This is where I truly learned the difference between Unit Testing and Integration Testing.&amp;#160; With such an outside dependency as a database or a web service, I began to see some examples that created separate, controlled instances of those dependencies in order to test the queries and &lt;abbr title="Create, Read, Update, Delete"&gt;CRUD&lt;/abbr&gt; functions.&amp;#160; The technique I use now for database integration is to use NHibernate, even if the primary project doesn't use it.&amp;#160; NHibernate has the ability to recreate table schemas for each tests which helps automate the state of the database for each test.&amp;#160; An example of this can be shown over at &lt;a title="NHibernate&amp;#39;s Community Portal" href="http://nhforge.org" target="_blank"&gt;NHForge.org's&lt;/a&gt; How-To section under &lt;a title="NHForge.org - Your First NHibernate Based Application" href="http://nhforge.org/wikis/howtonh/your-first-nhibernate-based-application.aspx" target="_blank"&gt;Your First NHibernate Based Application&lt;/a&gt;.&amp;#160; After setting this up, it provides me an easy way to test the barrier of the database.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Am I Just Testing the Mocking Framework?&lt;/h3&gt;  &lt;p&gt;I had a class the called into a 3rd party library that I wanted to test.&amp;#160; I abstracted the 3rd party library into a proxy and called such from my class.&amp;#160; The 3rd party library sent messages over a TCP socket connection and returned back an &amp;quot;OK&amp;quot; or an &amp;quot;ERR&amp;quot; message.&amp;#160; The class that I wanted to test created and sent the messages and then reported on what it got back.&amp;#160; For example, I would call a method in the class and it would send a message &amp;quot;FOO&amp;quot; to the proxy and get back &amp;quot;OK&amp;quot;.&amp;#160; That's a little simplified (see barrier #1 above) but the class itself did pretty much that.&amp;#160; When I setup the test, I mocked out the proxy dependency and had it return &amp;quot;OK&amp;quot; whenever my class sent it &amp;quot;FOO&amp;quot;.&amp;#160; This is not that meaningful of a test since there is no logic in that 1 method.&amp;#160; Other methods had logic based on the parameters; however, this one method was just this simple.&amp;#160; Was I just testing the mocking framework with this particular test?&amp;#160; Arguably, yes...I was; however, in the future, if that ever had to change, I now have a test that I can use to ensure that I get the information correctly.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;But Unit Testing = More Code &amp;amp; Time&lt;/h3&gt;  &lt;p&gt;This wasn't so much a barrier for me mentally but was a barrier to adopt it at work.&amp;#160; From what I've experienced now, writing unit tests AFTER the code has already been written DOES lead to more code being written, more refactoring of existing code to make it testable, and more time to do all of this.&amp;#160; However, I have seen that writing your unit tests BEFORE you write any code (as advocated in TDD), you tend to code at the same speed if not a little faster.&amp;#160; I found that I wrote code faster when I did tests before since the production code was already designed for me through the tests I had just written.&amp;#160; There was less thought at the time of coding since the design was setup while I was writing the tests.&amp;#160; I also found myself near-instantly defaulting into the S.O.L.I.D. principles instead of looking at them sometimes as a refactoring step.&amp;#160; Lastly, I wrote less code that would have been for future use (i.e. &lt;abbr title="You Ain&amp;#39;t Gonna Need It"&gt;YAGNI&lt;/abbr&gt;).&amp;#160; &lt;/p&gt;  &lt;p&gt;All of this came with a paradigm shift in my object design style.&amp;#160; While some of the basic directory structure and such was the same, I looked at my classes more at a &amp;quot;how do I want to call this class&amp;quot; as opposed to &amp;quot;what methods do I want to show in this class&amp;quot;.&amp;#160; The shift in my thinking was more of a consumer than a provider or retailer.&amp;#160; If you only code what you need, you tend to not code things you don't need.&amp;#160; It's as if you go to the grocery store for 1 item and that's the only item that the store has.&amp;#160; Nothing else to distract you in that point in time.&amp;#160; No other products around that you may need in the future.&amp;#160; You are in that 1 moment in time and in that moment, you only have 1 need as a consumer. &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Summary&lt;/h3&gt;  &lt;p&gt;While there were other barriers I came across, the rest were either very minor or more about basic implementation like how to return an IDataReader object. I'm sure that I'll stumble across more barriers and moments of enlightenment the more I practice TDD or just unit testing in general.&amp;#160; Until then, I hope some of the items described and discussed here can help others who have struggled to get their head around unit testing in general and some of the principles of TDD.&lt;/p&gt;  &lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/09/my-barriers-to-learning-tdd.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'My Barriers to Learning TDD';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = '[description]';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/links/widgets/zoneit.js"&gt;&lt;/script&gt; &lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f09%2fmy-barriers-to-learning-tdd.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f09%2fmy-barriers-to-learning-tdd.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Random-Acts-of-Coding-My-Barriers-to-Learning-TDD"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Frandomactsofcoding.blogspot.com%2F2009%2F09%2Fmy-barriers-to-learning-tdd.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-8665070155855493245?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/09/my-barriers-to-learning-tdd.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-8036348975490766693</guid><pubDate>Wed, 26 Aug 2009 15:32:00 +0000</pubDate><atom:updated>2009-09-03T09:43:17.763-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Commentary</category><category domain="http://www.blogger.com/atom/ns#">TDD</category><title>Finally Understanding the Merits of TDD</title><description>&lt;p&gt;I'm not a TDD person...or at least I wasn't until last week.&amp;#160; Up until then, I had read the blogs and looked at the examples to try to understand TDD and unit testing (with mocking) in general.&amp;#160; Almost all of the examples I was shown demonstrated very basic scenarios that, in most cases, were too trivial to show value.&amp;#160; I would ask people who would speak about unit testing in general how you'd do a specific scenario and would get mix responses ranging from &amp;quot;just try it&amp;quot; to &amp;quot;you should be using this tool and it'll just write the tests for you&amp;quot;. &lt;/p&gt;  &lt;p&gt;Last week, I had some free time to where I could truly evaluate a code base I finished up with the prior week and see if I could apply some tests to it.&amp;#160; The code I wanted to add tests to were simple repositories where I had abstracted the database calls to separate classes.&amp;#160; Being told to mock the databases out in the past, I started to do that and focus solely on these repositories.&amp;#160; In some instances, it felt like I was testing the abilities of the mocking framework instead of my code but these methods were simple by design (i.e. &amp;quot;Get Customer by Id 'X'&amp;quot;).&amp;#160; It was when I started to test more of the methods that I saw that some of the code I wrote had some issues. &lt;/p&gt;  &lt;p&gt;The code was functional; however, it wasn't easily testable.&amp;#160; When I would attempt to describe the test, I found that the code did more than one things (breaking the &lt;a title="Single Responsibility Principle from Wikipedia" href="http://en.wikipedia.org/wiki/Single_responsibility_principle" target="_blank"&gt;Single Responsibility Principle&lt;/a&gt;).&amp;#160; Another incident showed that the name of 1 whole class didn't make sense.&amp;#160; A third incident showed me an issue with the number of complexities that come from multiple dependencies and object inheritance.&amp;#160; After each time that I finished refactoring these issues out of the code and eventually got to working tests, I began to see how the questions that TDD (and BDD) cause you to ask while designing an application really shine.&lt;/p&gt;  &lt;p&gt;One example of this was a duplication of code.&amp;#160; I had a class called, for the sake of this post, &lt;font face="Courier"&gt;UserRepository&lt;/font&gt;.&amp;#160; The &lt;font face="Courier"&gt;UserRepository&lt;/font&gt; had a method to get all users in the system and returned a &lt;font face="Courier"&gt;List&amp;lt;User&amp;gt;&lt;/font&gt; back to the calling code.&amp;#160; This class also had a second method that did the same thing but the &lt;font face="Courier"&gt;List&amp;lt;User&amp;gt;&lt;/font&gt; only had the &lt;font face="Courier"&gt;FirstName&lt;/font&gt; and &lt;font face="Courier"&gt;LastName&lt;/font&gt; properties populated.&amp;#160; Why did I write such months ago?&amp;#160; Short answer - I have no idea.&amp;#160; Looking through the code, I found that a different feature needed just the &lt;font face="Courier"&gt;FirstName&lt;/font&gt; and &lt;font face="Courier"&gt;LastName&lt;/font&gt; properties and nothing else...it was then sending the List&amp;lt;User&amp;gt; to the client for an AJAX call.&amp;#160; While I can understand this now, I could have better implemented the solution by if I looked at the scenario and behavior better initially.&lt;/p&gt;  &lt;p&gt;If you ever find yourself wondering how writing more code for TDD or just basic unit tests can actually help the code, my recommendation is to just try it.&amp;#160; Take a simple class that has only a few pieces of logic in it and test it.&amp;#160; Next, take a simple class that has a dependency that you'll need to mock out and test that too.&amp;#160; After you understand how to write these basic types of tests, you can move into the self-reflective questions that really shine in TDD.&amp;#160; Questions like &amp;quot;What type of data do I want to work with when I call method X?&amp;quot;, &amp;quot;What will this class need (a.k.a. dependencies) to get me data Y?&amp;quot;, and &amp;quot;Is this functionality already present?&amp;quot; are all questions that get forgotten while we're sometimes blindly coding.&amp;#160; &lt;/p&gt;  &lt;p&gt;Looking ahead, I can only imagine how my code will be looking. &lt;/p&gt;  &lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/08/finally-understanding-merits-of-tdd.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'Finally Understanding the Merits of TDD';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = '[description]';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/links/widgets/zoneit.js"&gt;&lt;/script&gt; &lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f08%2ffinally-understanding-merits-of-tdd.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f08%2ffinally-understanding-merits-of-tdd.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Random-Acts-of-Coding-Finally-Understanding-the-Merits-of-TDD"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Frandomactsofcoding.blogspot.com%2F2009%2F08%2Ffinally-understanding-merits-of-tdd.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-8036348975490766693?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/08/finally-understanding-merits-of-tdd.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">7</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-3525058677906269154</guid><pubDate>Mon, 24 Aug 2009 00:21:00 +0000</pubDate><atom:updated>2009-09-28T14:16:11.109-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">JavaScript</category><title>ParseWiki.js - A JavaScript Wiki Parsing Engine</title><description>&lt;p&gt;Like most developers, I have a list of applications or pet project that address various scenarios I would like to develop or find solutions for.&amp;#160; While I have to admit my pet project list seems to grow more than shrink, I do knock things out on occasion.&amp;#160; One of these items was a wiki parsing engine.&amp;#160; Now there are plenty of wiki-based solutions out there; however, I wasn't able to find one that allowed me to bring just the parsing engine into my own solution.&amp;#160; Most of the solutions that are available are full solutions that include the parsing engine, data store, and full UI.&amp;#160; Sure they can be tweaked a bit but having a simple tool that will allow me to mark up some text in a &lt;font face="Courier"&gt;&amp;lt;textarea&amp;gt;&lt;/font&gt; field and then preview it is usually too simple for these solutions.&amp;#160; &lt;a title="WikiPlex - A RegEx Wiki Engine" href="http://wikiplex.codeplex.com/" target="_blank"&gt;WikiPlex&lt;/a&gt; is a great solution to fill this gap on the server side and recommend everyone to check it out; however, it got me wondering if a JavaScript solution could be done for client side parsing.&amp;#160; This is when I started to work on ParseWiki.js.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;An Overview of the Wiki Parsing Engine:&lt;/h3&gt;&lt;p&gt;After looking at a lot of wiki solutions and engines, almost all of them use Regular Expressions to parse the raw text.&amp;#160; I decided to do a similar approach since JavaScript has a pretty good RegEx system.&amp;#160; Since the focus is to just build the engine and not a full solution like &lt;a title="A WYSIWYG personal wiki notebook." href="http://luminotes.com" target="_blank"&gt;Luminotes&lt;/a&gt; or &lt;a title="A Non-linear personal web notebook." href="http://www.tiddlywiki.com" target="_blank"&gt;Tiddlywiki&lt;/a&gt;, I needed to look at the bare minimum items to parse in my engine.&amp;#160; Below is a list of what version 1 of ParseWiki.js has:&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;Headings 1-6 &lt;/li&gt;  &lt;li&gt;bold/italic/underline &lt;/li&gt;  &lt;li&gt;horizontal rule &lt;/li&gt;  &lt;li&gt;Named Anchors and Internal Links &lt;/li&gt;  &lt;li&gt;External Links &lt;/li&gt;  &lt;li&gt;Ordered and Unordered Lists (1 level only right now) &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;The Syntax:&lt;/h3&gt;&lt;p&gt;I've used a lot of wiki platforms from &lt;a title="A collection of wikis that anyone can edit." href="http://www.wikia.com" target="_blank"&gt;Wikia&lt;/a&gt; to &lt;a title="Microsoft&amp;#39;s Open Source Hosting Site" href="http://www.codeplex.com" target="_blank"&gt;CodePlex&lt;/a&gt; to &lt;a title="A WYSIWYG personal wiki notebook" href="http://luminotes.com" target="_blank"&gt;Luminotes&lt;/a&gt; and &lt;a title="Microsoft&amp;#39;s SharePoint" href="http://sharepoint.microsoft.com" target="_blank"&gt;SharePoint&lt;/a&gt;.&amp;#160; Of the differences in wiki markup each provide, I found it that &lt;a title="Microsoft&amp;#39;s Open Source Hosting Site" href="http://www.codeplex.com" target="_blank"&gt;CodePlex's&lt;/a&gt; engine provided the easiest/fastest to use for me.&amp;#160; Because of this, I based a lot of my syntax on such as well.&amp;#160; &lt;/p&gt;&lt;ul&gt;  &lt;li&gt;&lt;strong&gt;Headings:&lt;/strong&gt;     &lt;br /&gt;! Heading1 text     &lt;br /&gt;!! Heading2 test&amp;#160; &lt;br /&gt;!!! Heading3 text     &lt;br /&gt;ect.     &lt;br /&gt;&lt;/li&gt;  &lt;li&gt;&lt;strong&gt;Bold:       &lt;br /&gt;&lt;/strong&gt;*Bolded Text*     &lt;br /&gt;&lt;/li&gt;  &lt;li&gt;&lt;strong&gt;Italic:&lt;/strong&gt;     &lt;br /&gt;_Italicized Text_     &lt;br /&gt;&lt;/li&gt;  &lt;li&gt;&lt;strong&gt;Underline:       &lt;br /&gt;&lt;/strong&gt;+Underlined Text+     &lt;br /&gt;&lt;/li&gt;  &lt;li&gt;&lt;strong&gt;Horizontal Rule:&lt;/strong&gt;     &lt;br /&gt;---- (4 hyphens)     &lt;br /&gt;&lt;/li&gt;  &lt;li&gt;&lt;strong&gt;Named Anchors:&lt;/strong&gt;     &lt;br /&gt;[a:Anchor Name]     &lt;br /&gt;&lt;/li&gt;  &lt;li&gt;&lt;strong&gt;Internal Link:       &lt;br /&gt;&lt;/strong&gt;[goto:Anchor Name|Link Text]     &lt;br /&gt;&lt;/li&gt;  &lt;li&gt;&lt;strong&gt;External Link:&lt;/strong&gt;     &lt;br /&gt;[url:External Url|Link Text]     &lt;br /&gt;&lt;/li&gt;  &lt;li&gt;&lt;strong&gt;Unordered Lists:       &lt;br /&gt;&lt;/strong&gt;* Item 1     &lt;br /&gt;* Item 2     &lt;br /&gt;* Item 3     &lt;br /&gt;* etc.     &lt;br /&gt;&lt;/li&gt;  &lt;li&gt;&lt;strong&gt;Ordered Lists:&lt;/strong&gt;     &lt;br /&gt;# Item 1     &lt;br /&gt;# Item 2     &lt;br /&gt;# Item 3     &lt;br /&gt;# etc. &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Using ParseWiki.js:&lt;/h3&gt;&lt;p&gt;Since I wanted a simple wiki engine, using ParseWiki is very simple.&lt;/p&gt;&lt;ol&gt;  &lt;li&gt;Download ParseWiki.js &lt;/li&gt;  &lt;li&gt;Add it to your Html page &lt;/li&gt;  &lt;li&gt;Have your own JavaScript Code pass the marked up text into the &lt;font face="Courier"&gt;ParseWiki()&lt;/font&gt; Method &lt;/li&gt;  &lt;li&gt;Do with the outputted text as wish. &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;In the example files provided with the ParseWiki.js download, a full implementation has been provided where I pass the contents of a &lt;font face="Couier"&gt;&amp;lt;textarea&amp;gt;&lt;/font&gt; field into the &lt;font face="Courier"&gt;ParseWiki()&lt;/font&gt; method and then output it into a &lt;font face="Courier"&gt;&amp;lt;div&amp;gt;&lt;/font&gt; to preview.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Download the Code with Example:&lt;/h3&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;Download ParseWiki.js and Examples: &lt;a href="http://cid-3cb659da2d58facb.skydrive.live.com/self.aspx/Public/ParseWiki%20Example.zip"&gt;Link&lt;/a&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Next Steps:&lt;/h3&gt;&lt;p&gt;What's next on this pet project?&amp;#160; Well, there are a few things that I need to work on in order to make it better and provide more features.&amp;#160; There's a number of syntax features that I still need to add to the engine (obvious ones are multi-level lists and escape syntax).&amp;#160; Until that time, feel free to play around and with it and let me know what you think.&lt;/p&gt;  &lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/08/parsewikijs-javascript-wiki-parsing.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'http://randomactsofcoding.blogspot.com/2009/08/parsewikijs-javascript-wiki-parsing.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = 'An introduction to the start of a client-side wiki-parsing engine that uses regular expressiosn.';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/links/widgets/zoneit.js"&gt;&lt;/script&gt; &lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f08%2fparsewikijs-javascript-wiki-parsing.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f08%2fparsewikijs-javascript-wiki-parsing.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Random-Acts-of-Coding-ParseWikijs-A-JavaScript-Wiki-Parsing-Engine"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Frandomactsofcoding.blogspot.com%2F2009%2F08%2Fparsewikijs-javascript-wiki-parsing.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-3525058677906269154?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/08/parsewikijs-javascript-wiki-parsing.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-9024273498750606127</guid><pubDate>Tue, 04 Aug 2009 14:47:00 +0000</pubDate><atom:updated>2009-08-04T09:47:12.775-05:00</atom:updated><title>SchemaSpy Task for NAnt v1.0 Released</title><description>&lt;p&gt;Over the past couple of months, I've been working on creating a custom task for NAnt to provide a simplified way of using &lt;a title="SchemaSpy: An open source Java application for database documentation and analysis." href="http://schemaspy.sourceforge.net" target="_blank"&gt;SchemaSpy&lt;/a&gt;, the open source Java application for database documentation and analysis.&amp;#160; While the code as been feature complete for about a month now, I have finally finished the documentation and cleaning up the code itself.&amp;#160; Please feel free to hop out to &lt;a title="Microsoft&amp;#39;s Open Source Software Hosting Portal" href="http://www.codeplex.com" target="_blank"&gt;CodePlex&lt;/a&gt; and give it a try.&lt;/p&gt;  &lt;p&gt;&lt;a title="SchemaSpy Task for NAnt" href="http://schemaspynant.codeplex.com/" target="_blank"&gt;SchemaSpy Task for NAnt&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/7881153019980313926-9024273498750606127?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/08/schemaspy-task-for-nant-v10-released.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-1646326213981744782</guid><pubDate>Thu, 30 Jul 2009 00:00:00 +0000</pubDate><atom:updated>2009-07-29T19:07:54.811-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Automation</category><category domain="http://www.blogger.com/atom/ns#">Nant</category><category domain="http://www.blogger.com/atom/ns#">C#</category><title>Writing a Custom NAnt Task (Part 3)</title><description>&lt;p&gt;Over the past couple of months, I have been working on writing the &lt;a href="http://schemaspynant.codeplex.com/"&gt;SchemaSpy Task for NAnt&lt;/a&gt; located on &lt;a href="http://www.codeplex.com"&gt;CodePlex&lt;/a&gt;.&amp;nbsp; When I began to create a few custom tasks for NAnt in the past, I found very little documentation about how to create one.&amp;nbsp; Much of the documentation surrounding the process how to create a custom task is based solely on examples without any supporting information on how to expand such.&amp;nbsp; While this works very well for basic things, there were some experiences I had to work through while writing the task for SchemaSpy that I would like to talk about here.&amp;nbsp; In this, the third of four parts, we'll be diverting away from the example created by part 1 and 2 and dive straight into examples from the &lt;a title="The SchemaSpy Task for NAnt project on CodePlex" href="http://schemaspynant.codeplex.com/" target="_blank"&gt;SchemaSpy Task for NAnt&lt;/a&gt; code in order to examine how to create a custom element collection for your task.&amp;nbsp; In this post, we'll be reviewing the Schemas property of the SchemaSpy Task for NAnt.&lt;/p&gt;&lt;h5&gt;&amp;nbsp;&lt;/h5&gt;&lt;h3&gt;Why Do I Need a Custom Element Collection?&lt;/h3&gt;&lt;p&gt;For a very large number of tasks, basic attribute-based task properties should be enough.&amp;nbsp; However, if you find yourself where you need to allow a list of inputs into your task, you are stuck with two different options.&amp;nbsp; The first option is to simply create a basic property just like those described in the first two parts in this series in order to set a delimited string from the build file.&amp;nbsp; While this is easy to code and implement, it is not the most user friendly after the list grows in size.&amp;nbsp; The second option is to create a child element that represents a collection of elements.&amp;nbsp; This is a little bit more complex to develop; however, it provides a much better experience for the people who have to maintain the build file.&amp;nbsp; Unlike a simple decorated class property, a custom element collection requires things to be implemented in the code.&lt;h5&gt;&amp;nbsp;&lt;/h5&gt;&lt;h3&gt;Creating Collection Items&lt;/h3&gt;&lt;p&gt;The first item that we need to create is a simple object that will represent the children nodes of your custom element collections.&amp;nbsp; Looking at the code, this is represented by the &lt;font face="Courier"&gt;Schema&lt;/font&gt; class in the &lt;font face="Courier"&gt;Schema.cs&lt;/font&gt; file.&amp;nbsp; This class has to inherit from the &lt;font face="Courier"&gt;NAnt.Core.Element&lt;/font&gt; class and be decorated with the &lt;font face="Courier"&gt;ElementName&lt;/font&gt; attribute, the attribute is used to identify the name of the XML node in the build file.&amp;nbsp; In the example (see the code below), the name of the element will be "&lt;font face="Courier"&gt;schema&lt;/font&gt;".&amp;nbsp; After the class is established, we are able to add decorated properties that will represent the different attributes for the element.&amp;nbsp; &lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;[ElementName(&lt;span class="str"&gt;"schema"&lt;/span&gt;)]&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Schema : Element &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;{ &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    &lt;span class="rem"&gt;/// The name of the schema to analyze and document. &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt; &lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;    [TaskAttribute(&lt;span class="str"&gt;"schemaName"&lt;/span&gt;)]  &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;    [StringValidator(AllowEmpty = &lt;span class="kwrd"&gt;false&lt;/span&gt;)]  &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; SchemaName { get; set; } &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;&lt;h3&gt;Creating the Strongly-Typed Collection&lt;/h3&gt;&lt;p&gt;The second item we need to add to our task is a strongly-typed collection to store instances of our &lt;font face="Courier"&gt;Schema&lt;/font&gt; object we just created. Looking at the code, this is represented by the &lt;font face="Courier"&gt;SchemaCollection&lt;/font&gt; class in the &lt;font face="Courier"&gt;SchemaCollection.cs&lt;/font&gt; file.&amp;nbsp; Like many strongly-type collections created in .Net, this class inherits from the &lt;font face="Courier"&gt;System.Collections.CollectionBase&lt;/font&gt; class.&amp;nbsp; Simply by implementing the abstract base class and filling in the code, the custom, strongly-typed collection of &lt;font face="Courier"&gt;Schema&lt;/font&gt; objects will be created and ready to use.&lt;h5&gt;&amp;nbsp;&lt;/h5&gt;&lt;h3&gt;Implementing the Collection&lt;/h3&gt;&lt;p&gt;The third and fourth tasks left to add our collection of custom elements to our NAnt task is to update the task code itself.&amp;nbsp; Now that we have the collection and child elements created, we have to first create a private variable to hold a new instance of our collection object.&amp;nbsp; If the collection is not created &lt;u&gt;and instantiated&lt;/u&gt;, NAnt will not be able to add items to the collection and throw an error.&amp;nbsp; &lt;p&gt;The last thing to do is to create a new decorated property to tell NAnt to access and expect the collection.&amp;nbsp; Unlike the other properties that we declared that describe node elements, we need to decorate a property with the &lt;font face="Courier"&gt;BuildElementCollection&lt;/font&gt; attribute.&amp;nbsp; The attribute requires three parameters.&amp;nbsp; The first describes the name of the collection node.&amp;nbsp; The second describes the name of the children nodes. The last parameter describes the task options.&amp;nbsp; Once all of these items are set, the new code should look like the below:&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;   &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="rem"&gt;/// Instantiates a default collection to add elements to.   &lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;   &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; SchemaCollection _schemaCollection = &lt;span class="kwrd"&gt;new&lt;/span&gt; SchemaCollection();   &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;     &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;   &lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;&lt;span class="rem"&gt;/// Gets or sets the collection of schemas to use.  &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;   &lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;[BuildElementCollection(&lt;span class="str"&gt;"schemas"&lt;/span&gt;, &lt;span class="str"&gt;"schema"&lt;/span&gt;, Required = &lt;span class="kwrd"&gt;false&lt;/span&gt;)]  &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; SchemaCollection Schemas   &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;{  &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;     get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _schemaCollection; }      &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;     set { _schemaCollection = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }  &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&amp;nbsp; &lt;h3&gt;A Look at the Build File &lt;/h3&gt;&lt;p&gt;With everything completed, the code can be compiled and installed for NAnt to begin using it.&amp;nbsp; Once all of that is setup, you can access and update the build file to take advantage of the customer collection similar to the example below:&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;example&lt;/span&gt; &lt;span class="attr"&gt;prop1&lt;/span&gt;&lt;span class="kwrd"&gt;="test"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;   &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;schemas&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;   &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;schema&lt;/span&gt; &lt;span class="attr"&gt;schemaName&lt;/span&gt;&lt;span class="kwrd"&gt;="dbo"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;   &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;schema&lt;/span&gt; &lt;span class="attr"&gt;schemaName&lt;/span&gt;&lt;span class="kwrd"&gt;="sys"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;   &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;schemas&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;   &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;example&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&amp;nbsp; &lt;h3&gt;Summary&lt;/h3&gt;&lt;p&gt;In this section we reviewed the code implemented by the SchemaSpy Task for NAnt I wrote and placed out on CodePlex.&amp;nbsp; We looked at what it takes to implement a custom collection.&amp;nbsp; In the next and final installment of this series, we'll be looking at writing a custom task that is used to call an external application and look at what differences there are between it and the task we have been working with in the first two segments of this series.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/07/writing-custom-nant-task-part-3_29.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'Writing a Custom NAnt Task (Part 3)';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = 'In this, the third of a four post series on create a custom NAnt task, we dive into how to create a custom collection of child elements in order to provide more flexibility to your task.';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/links/widgets/zoneit.js"&gt;&lt;/script&gt; &lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f07%2fwriting-custom-nant-task-part-3_29.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f07%2fwriting-custom-nant-task-part-3_29.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Random-Acts-of-Coding-Writing-a-Custom-NAnt-Task-Part-3"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Frandomactsofcoding.blogspot.com%2F2009%2F07%2Fwriting-custom-nant-task-part-3_29.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-1646326213981744782?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/07/writing-custom-nant-task-part-3_29.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-6584108264649805179</guid><pubDate>Thu, 23 Jul 2009 19:04:00 +0000</pubDate><atom:updated>2009-07-30T07:02:06.418-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Automation</category><category domain="http://www.blogger.com/atom/ns#">Nant</category><category domain="http://www.blogger.com/atom/ns#">C#</category><title>Writing a Custom NAnt Task (Part 4)</title><description>&lt;p&gt;In this final installment of a series of posts looking into how to create a custom NAnt task, we'll dive into how to create a task that executes an external application.&amp;#160; While NAnt has the built in &lt;font face="Courier"&gt;&amp;lt;exec&amp;gt;&lt;/font&gt; task to handling command line programs, there may come a time where the possible arguments or the command itself is just too much for such a generic task.&amp;#160; This was the case that I ran into while trying to integrate &lt;a title="SchemaSpy: An open source Java application for database documentation and analysis." href="http://schemaspy.sourceforge.net/" target="_blank"&gt;SchemaSpy&lt;/a&gt;, the Java-based database analysis and documentation tool, into my build scripts.&amp;#160; With the number of arguments and complexities of the program, I decided to create my own custom task.&amp;#160; We'll be diving into this task while exploring the differences between a basic task and an executable task.&amp;#160; The source code for this project will refer to the &lt;a title="SchemaSpy Task for NAnt on CodePlex" href="http://schemaspynant.codeplex.com/" target="_blank"&gt;SchemaSpy Task for NAnt&lt;/a&gt; located out on &lt;a title="Microsoft&amp;#39;s Open Source Project Hosting Site" href="http://www.CodePlex.com" target="_blank"&gt;CodePlex&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;A Look at the Default &amp;lt;exec&amp;gt; Task.&lt;/h3&gt;&lt;p&gt;NAnt comes bundled with a task that can be used to call external programs as a way to extend the functionality of the build script.&amp;#160; For some applications that take only a few arguments, this is really easy to manage.&amp;#160; This can be seen using a command line program for the &lt;a title="A database versioning and migration tool started by Joshua Poehls" href="http://dotnetmigrations.codeplex.com/" target="_blank"&gt;DotNetMigrations project&lt;/a&gt; also located out on &lt;a title="Microsoft&amp;#39;s Open Source Project Hosting Site" href="http://www.codeplex.com" target="_blank"&gt;CodePlex&lt;/a&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt;  &lt;div class="csharpcode"&gt;    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;exec&lt;/span&gt; &lt;span class="attr"&gt;program&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;db&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;    &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;arg&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;migrate dev 2&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;exec&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;/div&gt;  &lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;However, if you are using an item like SchemaSpy, the cleanliness of the solution begins to deteriorate fairly quickly with only a partial set of its argument.&lt;/p&gt;&lt;div class="csharpcode"&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;exec&lt;/span&gt; &lt;span class="attr"&gt;program&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;java&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;arg&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;-jar SchemaSpy.jar -t mssql05 -host serverName -db myDb -port 1433 -sso -all -o ..\output&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;exec&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;When there is a need to integrate a program like SchemaSpy into a tool like NAnt, creating a custom task to streamline the arguments into a more user-friendly manner can greatly ease script authoring and debugging.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Task vs. ExternalProgramBase&lt;/h3&gt;&lt;p&gt;In previous examples in this series, we would create our custom tasks using the &lt;font face="Courier"&gt;NAnt.Core.Task&lt;/font&gt; abstract base class.&amp;#160; This base class gave us everything we needed to do to handle properties, children elements, and similar items.&amp;#160; One item that the &lt;font face="Courier"&gt;Task&lt;/font&gt; base class did not handle though was running external processes though.&amp;#160; If you were to attempt to start a new process, an error would occur or the script would hang since the &lt;font face="Courier"&gt;Task&lt;/font&gt; base class isn't thread-safe by default.&amp;#160; If you wanted to create the multi-threading code in order to make the process run successfully and safely, then you can definitely do such while inheriting from the &lt;font face="Courier"&gt;Task&lt;/font&gt; base class; however, NAnt has already done this for you by providing the &lt;font face="Courier"&gt;ExternalProgramBase&lt;/font&gt; abstract base class.&amp;#160; The &lt;font face="Courier"&gt;ExternalProgramBase&lt;/font&gt; class inherits from &lt;font face="Courier"&gt;Task&lt;/font&gt; and enhances it by providing specific methods and properties for working with external programs.&amp;#160; In addition, it has all of the threading logic established for you.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Diving Deeper into ExternalProgramBase&lt;/h3&gt;&lt;p&gt;Since &lt;font face="Courier"&gt;ExternalProgramBase&lt;/font&gt; inherits from &lt;font face="Courier"&gt;Task&lt;/font&gt;, every thing we can do when we inherited from &lt;font face="Courier"&gt;Task&lt;/font&gt; previously can still be done when we inherit from &lt;font face="Courier"&gt;ExternalProgramBase&lt;/font&gt;.&amp;#160; Where the differences come into play is when we overwrite the &lt;font face="Courier"&gt;ExecuteTask()&lt;/font&gt; method.&amp;#160; This method is called by the NAnt engine to start the task's specific function.&amp;#160; In the &lt;font face="Courier"&gt;ExternalProgramBase&lt;/font&gt; base class implementation, this method executes the actual external application we want to start.&amp;#160; It does so by looking at the values of 2 properties; &lt;font face="Courier"&gt;ExeName&lt;/font&gt; and &lt;font face="Courier"&gt;ProgramArguments&lt;/font&gt;.&amp;#160; The &lt;font face="Courier"&gt;ExeName&lt;/font&gt; property provides the string name (with extension) of the executable program to run.&amp;#160; The &lt;font face="Courier"&gt;ProgramArguments&lt;/font&gt; property provides a string representing the fully list of arguments.&amp;#160; We can still provide our own custom code inside of the &lt;font face="Courier"&gt;ExecuteTask()&lt;/font&gt; method, and once we're ready for the external program to start, we can simply set the &lt;font face="Courier"&gt;ExeName&lt;/font&gt; property and call &lt;font face="Courier"&gt;base.ExecuteTask()&lt;/font&gt;.&amp;#160; The base class's &lt;font face="Courier"&gt;ExecuteTask()&lt;/font&gt; method will read both properties, create the necessary threads, and execute the program.&amp;#160; Below is a snippet from the SchemaSpy task that illustrates this process.&lt;/p&gt;&lt;div class="csharpcode"&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="rem"&gt;/// The Program Arguments listing used by the ExternalProgramBase class.&lt;/span&gt;&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ProgramArguments&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;{&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;    get { &lt;span class="kwrd"&gt;return&lt;/span&gt; BuildArgumentList(); }&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;}&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;&lt;span class="rem"&gt;/// Executes the task's operation for NAnt.&lt;/span&gt;&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ExecuteTask()&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;{&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;    &lt;span class="kwrd"&gt;bool&lt;/span&gt; isValid = ValidateAttributes();&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!isValid)&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;    {&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;        Log(Level.Error, &lt;span class="str"&gt;&amp;quot;Task Attributes are not valid.&amp;quot;&lt;/span&gt;);&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;    }&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;    &lt;span class="kwrd"&gt;this&lt;/span&gt;.ExeName = &lt;span class="str"&gt;&amp;quot;java.exe&amp;quot;&lt;/span&gt;;&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;    &lt;span class="kwrd"&gt;base&lt;/span&gt;.ExecuteTask();&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;Notice that in the SchemaSpy task for NAnt, I did not directly set the &lt;font face="Courier"&gt;ProgramArguments&lt;/font&gt; property prior to calling &lt;font face="Courier"&gt;base.ExecuteTask()&lt;/font&gt;.&amp;#160; Instead, I had the property execute a method that would do it when the base class is ready.&amp;#160; This method evaluates the various properties/attributes of the task in order to create all of the arguments required by SchemaSpy to run properly.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;The Updated Build Script&lt;/h3&gt;&lt;p&gt;With the custom task created, we can now update the build script to use it instead of relying on the &amp;lt;exec&amp;gt; task.&amp;#160; Below is an example of the SchemaSpy call previously shown.&lt;/p&gt;&lt;div class="csharpcode"&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;schemaSpy&lt;/span&gt;&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;    &lt;span class="attr"&gt;jarPath&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;..\SchemaSpy.jar&amp;quot;&lt;/span&gt;&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;    &lt;span class="attr"&gt;dbType&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;mssql-jtds&amp;quot;&lt;/span&gt;&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;    &lt;span class="attr"&gt;host&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;MyDatabaseServer&amp;quot;&lt;/span&gt;&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    &lt;span class="attr"&gt;port&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;1433&amp;quot;&lt;/span&gt;&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;    &lt;span class="attr"&gt;dbName&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;MyDatabase&amp;quot;&lt;/span&gt;&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;    &lt;span class="attr"&gt;schemaName&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;dbo&amp;quot;&lt;/span&gt;&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;    &lt;span class="attr"&gt;outputDirectory&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;..\MyDatabaseDocumentation&amp;quot;&lt;/span&gt;&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;    &lt;span class="attr"&gt;singleSignOn&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Summary&lt;/h3&gt;&lt;p&gt;Throughout this series of blog posts, we've covered how to make very simple custom tasks for NAnt up through the ability to create complex tasks that contain child elements and/or simplifies running external programs.&amp;#160; Through the steps listed in this series, hopefully all of information you need to create a custom NAnt task will be available to you.&amp;#160; If a scenario comes up that you need assistance with, feel free to post a comment and I'll see what I can do to assist.&lt;/p&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/07/writing-custom-nant-task-part-3.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'Writing a Custom NAnt Task (Part 4)';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = 'In the final segment in my series about creating a custom NAnt task, we dive into how to create a custom task used to execute an external application.';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/links/widgets/zoneit.js"&gt;&lt;/script&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f07%2fwriting-custom-nant-task-part-3.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f07%2fwriting-custom-nant-task-part-3.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt; &lt;a rev="vote-for" href="http://dotnetshoutout.com/Random-Acts-of-Coding-Writing-a-Custom-NAnt-Task-Part-4"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Frandomactsofcoding.blogspot.com%2F2009%2F07%2Fwriting-custom-nant-task-part-3.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-6584108264649805179?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/07/writing-custom-nant-task-part-3.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-4653048972154036608</guid><pubDate>Wed, 01 Jul 2009 02:22:00 +0000</pubDate><atom:updated>2009-06-30T21:29:48.650-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">VB.Net</category><category domain="http://www.blogger.com/atom/ns#">Nant</category><category domain="http://www.blogger.com/atom/ns#">C#</category><title>Writing a Custom NAnt Task (Part 2)</title><description>&lt;p&gt;Over the past couple of months, I have been working on writing the &lt;a title="SchemaSpy Task for NAnt" href="http://schemaspynant.codeplex.com/" target="_blank"&gt;SchemaSpy Task for NAnt&lt;/a&gt; located on CodePlex.&amp;#160; When I began to create a few custom tasks for NAnt in the past, I found very little documentation about how to create one.&amp;#160; Much of the documentation surrounding how to create a custom task is based solely on examples without any supporting information.&amp;#160; While this works very well for basic things, there were some experiences I had to work through while writing the task for SchemaSpy that I would like to talk about here.&amp;#160; In this, the second of four parts, we'll be extending what we created on &lt;a title="Writing a Custom NAnt Task (Part 1)" href="http://randomactsofcoding.blogspot.com/2009/06/writing-custom-nant-task-part-1.html" target="_blank"&gt;Part 1&lt;/a&gt; by adding a &lt;font face="Courier"&gt;FileSet&lt;/font&gt; collection to add some flexibility to our application.&amp;#160; In addition, the accompanying source code will remain in both C# and VB.Net similar to the first section in this series.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Changing the Input Directory Attribute:&lt;/h3&gt;&lt;p&gt;In Part 1 of this series, our Log Combining task contained an attribute to identify the directory that held all files that were to be combined.&amp;#160; What we want to do first is remove this attribute and provide an alternative solution using the NAnt &lt;font face="Courier"&gt;FileSet&lt;/font&gt; object.&amp;#160; The reason to change this is to allow us to not be tied to a single directory for combining files, as well as provide a ways to be more selective of the files to combine. For more general information on the &lt;font face="Courier"&gt;FileSet&lt;/font&gt; Type of NAnt, make sure to check out the official documentation for &lt;a title="FileSet documentation" href="http://nant.sourceforge.net/release/latest/help/types/fileset.html" target="_blank"&gt;&lt;font face="Courier"&gt;FileSet&lt;/font&gt;&lt;/a&gt; over at the NAnt website.&lt;/p&gt;&lt;p&gt;In order to use a &lt;font face="Courier"&gt;FileSet&lt;/font&gt; object, we'll need to import the &lt;font face="Courier"&gt;NAnt.Core.Types&lt;/font&gt; namespace.&amp;#160; In addition, we have to instantiate a private &lt;font face="Courier"&gt;FileSet&lt;/font&gt; object in order to be exposed by the new property.&amp;#160; The reason for this is that the NAnt engine does not look to ensure that the collection-based objects are instantiated.&amp;#160; On collection-based elements that contains children elements, the NAnt engine ultimately just adds items into the collection.&amp;#160; If the collection is not instantiated, a null-reference error will be thrown.&lt;/p&gt;&lt;p&gt;After the property has been setup and the private object has been instantiated, the code for such should look similar to the following:&lt;/p&gt;&lt;div class="csharpcode"&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; FileSet _logFileSet = &lt;span class="kwrd"&gt;new&lt;/span&gt; FileSet();&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&lt;span class="rem"&gt;/// The files that will be combined by this task.&lt;/span&gt;&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;[BuildElement(&lt;span class="str"&gt;&amp;quot;fileset&amp;quot;&lt;/span&gt;)]&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;[StringValidator(AllowEmpty = &lt;span class="kwrd"&gt;false&lt;/span&gt;)]&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; FileSet LogFileSet &lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;{&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;    get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _logFileSet; } &lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;    set { _logFileSet = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;Once this is done, we can update the project's build file to look something like the below to mimic the same functionality as we had with the previous attribute.&lt;/p&gt;&lt;div class="csharpcode"&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;logCombiner&lt;/span&gt; &lt;span class="attr"&gt;outputFile&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;combined.txt&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;fileset&lt;/span&gt; &lt;span class="attr"&gt;basedir&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;..\logs\&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;include&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;**/*&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;fileset&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;logCombiner&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Updating the Combining Method to use the FileSet:&lt;/h3&gt;&lt;p&gt;Now that we have the task attribute and build file setup, we need to update the code to use the collection. In order to keep things simple, I'm not going to touch the current &lt;font face="Courier"&gt;CombineFiles()&lt;/font&gt; method.&amp;#160; Instead, I want to ensure the information I will be getting from the &lt;font face="Courier"&gt;FileSet&lt;/font&gt; object will be able to be valid and fit into that method call. &lt;/p&gt;&lt;p&gt;To do this, we need to change the name of the &lt;font face="Courier"&gt;ValidateInputDirectory()&lt;/font&gt; method to &lt;font face="Courier"&gt;ValidateInputFile()&lt;/font&gt;.&amp;#160; This will ensure the name of the method will not confuse other developers.&amp;#160; In addition, we want to change the logic of this method slightly by changing &lt;font face="Courier"&gt;Directory.Exists()&lt;/font&gt; to &lt;font face="Courier"&gt;File.Exists()&lt;/font&gt;.&amp;#160; We will be working with files at this point instead of directories so testing we want to make sure we test for the proper item.&lt;/p&gt;&lt;div class="csharpcode"&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="rem"&gt;/// Validates the Input Directory Value&lt;/span&gt;&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;path&amp;quot;&amp;gt;The directory location to validate&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ValidateInputFile(&lt;span class="kwrd"&gt;string&lt;/span&gt; path)&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;{&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!File.Exists(path))&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;    {&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; BuildException(&lt;span class="str"&gt;&amp;quot;The input directory of &amp;quot;&lt;/span&gt; + path + &lt;span class="str"&gt;&amp;quot; does not exist.&amp;quot;&lt;/span&gt;);&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;    }&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;Next, we need to update the &lt;font face="Courier"&gt;GetInputFiles()&lt;/font&gt; method.&amp;#160; This method returns an array of strings representing the file paths.&amp;#160; These paths are then passed to the &lt;font face="Courier"&gt;CombineFiles()&lt;/font&gt; method.&amp;#160; We want to keep this signature.&amp;#160; Inside of the method, we need to instantiate an item to hold our string array; like a &lt;font face="Courier"&gt;List&amp;lt;string&amp;gt;&lt;/font&gt;.&amp;#160; Next, we need to loop through the &lt;font face="Courier"&gt;FileSet.FileNames&lt;/font&gt; collection and add each entry into our string list.&amp;#160; Lastly, we want to make sure the files are validated through our &lt;font face="Courier"&gt;ValidateInputFile()&lt;/font&gt; method before returning the string array.&amp;#160; Once all of this is done, the method should look like the following:&lt;/p&gt;&lt;div class="csharpcode"&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="rem"&gt;/// Retrieves a listing of files from a provided directory&lt;/span&gt;&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;A string array of all file paths.&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[] GetInputFiles()&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;{&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;    List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; output = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;();&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt; path &lt;span class="kwrd"&gt;in&lt;/span&gt; _logFileSet.FileNames)&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;    {&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;        ValidateInputFile(path);&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;        output.Add(path);&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;    }&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; output.ToArray();&lt;/pre&gt;  &lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Looking Ahead:&lt;/h3&gt;&lt;p&gt;At this point, we have updated our NAnt task from using a single input directory to combine all files in the directory to a more robust solution that allows us to specify which files to include and exclude.&amp;#160; We can compile the code and install the task as described in the previous segment for testing.&amp;#160; In the next post in this series, I'll be diving into writing a custom element collection that can be added to our NAnt task in order to provide more opportunities.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Source Code:&lt;/h3&gt;&lt;iframe style="border-bottom: #dde5e9 1px solid; border-left: #dde5e9 1px solid; padding-bottom: 0px; background-color: #ffffff; margin: 3px; padding-left: 0px; width: 240px; padding-right: 0px; height: 66px; border-top: #dde5e9 1px solid; border-right: #dde5e9 1px solid; padding-top: 0px" marginheight="0" src="http://cid-3cb659da2d58facb.skydrive.live.com/embedrowdetail.aspx/Public/NAntLogCombiner%20-%20Part%202.zip" frameborder="0" marginwidth="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/06/writing-custom-nant-task-part-2.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'Writing a Custom NAnt Task (Part 2)';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = 'This post continues the series on how to write a custom task for the build script utility of Nant.  In this task we explore modifying the C# and VB.Net code from the previous post to include a the FileSet Collection Element.';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/links/widgets/zoneit.js"&gt;&lt;/script&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f06%2fwriting-custom-nant-task-part-2.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f06%2fwriting-custom-nant-task-part-2.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Random-Acts-of-Coding-Writing-a-Custom-NAnt-Task-Part-2"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Frandomactsofcoding.blogspot.com%2F2009%2F06%2Fwriting-custom-nant-task-part-2.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-4653048972154036608?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/06/writing-custom-nant-task-part-2.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-7719599124412395724</guid><pubDate>Thu, 04 Jun 2009 21:11:00 +0000</pubDate><atom:updated>2009-06-30T21:16:10.532-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">VB.Net</category><category domain="http://www.blogger.com/atom/ns#">Nant</category><category domain="http://www.blogger.com/atom/ns#">C#</category><title>Writing a Custom NAnt Task (Part 1)</title><description>&lt;p&gt;Over the past month, I have been working on writing the SchemaSpy Task for NAnt located on CodePlex.&amp;#160; When I have began to create a few custom tasks for NAnt in the past, I found very little documentation about how to create one.&amp;#160; Much of the documentation surrounding how to create a custom task is based solely on examples without any supporting information.&amp;#160; While this works very well for basic things, there were some experiences I had to work through while writing the task for SchemaSpy that I would talk about them here.&amp;#160; In this, the first of four parts, we'll be going over how to write your first task and add some simple attributes to it.&amp;#160; &lt;/p&gt;  &lt;p&gt;To make the example a bit more practical than &amp;quot;Hello World&amp;quot;, we'll be creating a log combiner task. In addition to attempting to make a more practical example, the accompanying source code contains both a C# and VB examples and has been refactored to assist in readability.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Getting Started Creating the Log Combining Task:&lt;/h3&gt;  &lt;p&gt;In order to get started we'll need to make sure we have downloaded &lt;a title="NAnt&amp;#39;s Homepage" href="http://NAnt.SourceForge.Net" target="_blank"&gt;NAnt&lt;/a&gt;.&amp;#160; Once that is downloaded, we can open up Visual Studio and create a new Class Library project.&amp;#160; In this example, we'll call the project NAntLogCombiner.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_RNnu2VM54fE/Sig4aezPI3I/AAAAAAAAAFQ/MNxmUux8Pvc/s1600-h/NewProjectWindow3.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="New Project Window" src="http://lh6.ggpht.com/_RNnu2VM54fE/Sig4bDjVoEI/AAAAAAAAAFU/7LK0hTvpNuo/NewProjectWindow_thumb1.png?imgmax=800" width="556" height="356" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Once the project is created we need to do 4 things:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Rename Class1.cs to LogCombinerTask.cs &lt;/li&gt;    &lt;li&gt;Add a reference to the NAnt.Core.dll &lt;/li&gt;    &lt;li&gt;Add the NAnt.Core and NAnt.Core.Attributes namespaces to our file &lt;/li&gt;    &lt;li&gt;Have our LogCombinerTask class inherit from the NAnt.Core.Task class and implement its abstract members. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;After these 4 steps are completed, we'll be left with code that looks similar to the code below.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;pre class="brush: csharp;"&gt;using System.IO;&lt;br /&gt;using NAnt.Core;&lt;br /&gt;using NAnt.Core.Attributes;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;namespace NAntLogCombiner&lt;br /&gt;{&lt;br /&gt;    public class LogCombinerTask : Task&lt;br /&gt;    {&lt;br /&gt;        protected override void ExecuteTask()&lt;br /&gt;        {&lt;br /&gt;            throw new System.NotImplementedException();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;The &lt;font face="Courier"&gt;NAnt.Core.Task&lt;/font&gt; abstract class only requires 1 method to be overridden.&amp;#160; The &lt;font face="Courier"&gt;ExecuteTask() &lt;/font&gt;method is called by the NAnt build engine and is where we will need to place our code.&amp;#160; Since we are going to be combining text files, we need 2 things; a directory that holds the files we want to read, and the output file.&amp;#160; For the time being, we'll hard code these variables.&amp;#160; After writing the code that consumes the input files and writes their contents to the output file, we have the following in our LogCombinerTask:&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush: csharp;"&gt;protected override void ExecuteTask()&lt;br /&gt;{&lt;br /&gt;    string inputDirectory = @&amp;quot;..\logs\&amp;quot;;&lt;br /&gt;    string outputFile = &amp;quot;combined.txt&amp;quot;;&lt;br /&gt;&lt;br /&gt;    string[] inputFiles = Directory.GetFiles(inputDirectory);&lt;br /&gt;&lt;br /&gt;    using (StreamWriter outputStream = File.CreateText(outputFile))&lt;br /&gt;    {&lt;br /&gt;        foreach (string file in inputFiles)&lt;br /&gt;        {&lt;br /&gt;            outputStream.Write(ReadFile(file));&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private string ReadFile(string fileToRead)&lt;br /&gt;{&lt;br /&gt;    StringBuilder returnString = new StringBuilder();&lt;br /&gt;&lt;br /&gt;    using (StreamReader inputStream = File.OpenText(fileToRead))&lt;br /&gt;    {&lt;br /&gt;        while (inputStream.Peek() &amp;gt; 0)&lt;br /&gt;        {&lt;br /&gt;            returnString.AppendLine(inputStream.ReadLine());&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return returnString.ToString();&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;While we're missing a few things (like validating the directory exists, making the paths configurable, etc.), the task builds and will work under its current constraints.&amp;#160; Before we can test this inside of NAnt though, we have to configure the class and project a bit more.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Decorating the Class for NAnt:&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;While we have a working class for combining text files located in a single directory, it is not something that can be consumed by NAnt.&amp;#160; NAnt provides an assortment of attributes that can be used to decorate class files in order to inform NAnt how each class (and it's members as we'll see) maps to the markup located in a build file.&lt;/p&gt;&lt;p&gt;In our simple class that we have so far, we only have to add the &lt;font face="Courier"&gt;TaskName&lt;/font&gt; attribute onto the class declaration. This attribute tasks just the string name of our task that will represent the element inside of a build file.&amp;#160; I'm going to name the task &amp;quot;&lt;font face="Courier"&gt;logCombiner&lt;/font&gt;&amp;quot; to be consistent with the casing of other tasks as well as the name and purpose of our project.&amp;#160; With the attribute added, the class declaration part of our code now looks like the following:&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush: csharp;"&gt;[TaskName(&amp;quot;logCombiner&amp;quot;)]&lt;br /&gt;public class LogCombinerTask : Task&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Naming the Assembly:&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;With our class properly decorated, we're ready to build our task in preparation for testing.&amp;#160; The way that NAnt imports tasks is through dynamic loading of assemblies and then using reflection.&amp;#160; This is a fairly common practice; however, NAnt only imports assemblies that meet the following pattern; &amp;quot;&lt;font face="Courier"&gt;NAnt.*.Tasks.dll&lt;/font&gt;&amp;quot;.&amp;#160; Our project, by default, does not output it's assembly into this naming convention.&amp;#160; We can easily remedy this by opening the project properties and setting the Assembly Name to &amp;quot;&lt;font face="Courier"&gt;NAnt.LogCombiner.Tasks.dll&lt;/font&gt;&amp;quot; as shown in the image below.&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_RNnu2VM54fE/Sig4buSLQzI/AAAAAAAAAFY/f7YJ5VuYbyc/s1600-h/ProjectProperties3.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="Project Properties" src="http://lh4.ggpht.com/_RNnu2VM54fE/Sig4cVVua0I/AAAAAAAAAFc/SrJaJfwSQoc/ProjectProperties_thumb1.png?imgmax=800" width="544" height="278" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Testing the Assembly:&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;Now that the Assembly is named correctly for NAnt, we can build the project and test is in NAnt.&amp;#160; We can import our task into NAnt by dropping the DLL into NAnt's bin directory or using NAnt's loadtasks task.&amp;#160; For simplicity sake, I'm going to assume our &lt;font face="Courier"&gt;NAnt.LogCombiner.Tasks.dll&lt;/font&gt; has been copied to NAnt's bin directory.&amp;#160; &lt;/p&gt;&lt;br /&gt;&lt;p&gt;Once the task has been imported, we can call our task in a build file.&amp;#160; Below is an example build file that only calls our new task.&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;&lt;br /&gt;&amp;lt;project name=&amp;quot;Log Combiner&amp;quot; default=&amp;quot;default&amp;quot; basedir=&amp;quot;.&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;description&amp;gt;This is an example build file.&amp;lt;/description&amp;gt;&lt;br /&gt;    &lt;br /&gt;    &amp;lt;target name=&amp;quot;default&amp;quot; description=&amp;quot;Default Task&amp;quot;&amp;gt;&lt;br /&gt;        &amp;lt;logCombiner /&amp;gt;&lt;br /&gt;    &amp;lt;/target&amp;gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Before we run this build file, we need to make sure that we have a directory above the current directory called &amp;quot;&lt;font face="Courier"&gt;logs&lt;/font&gt;&amp;quot; that contain our text files.&amp;#160; Once our log files are in place, we can run our build file where it will sequentially read the files from the directory and merge them into the &lt;font face="Courier"&gt;combined.txt&lt;/font&gt; file.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Congratulations on creating your first NAnt task; however, it's pretty generic and not very configurable.&amp;#160; Let's enhance our task now by moving where we declare our variables for the input directory and output file into task variables instead of being hard coded.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Adding Task Attributes:&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;In order to add attributes to our task so we can declare where the input folder or output file is located, we simply have to add a couple of properties to our class file and decorate them accordingly.&amp;#160; Let's update our LogCombiner class by adding an &lt;font face="Courier"&gt;InputDirectory&lt;/font&gt; property as well as an &lt;font face="Courier"&gt;OutputFile&lt;/font&gt; property and update the code to use them appropriately.&amp;#160; In addition to implementing the properties, we also need to decorate them with the appropriate attributes so NAnt will know how to map the XML-based attributes to our object.&amp;#160; &lt;/p&gt;&lt;br /&gt;&lt;pre class="brush: csharp;"&gt;[TaskAttribute(&amp;quot;inputDirectory&amp;quot;, Required = true)]&lt;br /&gt;[StringValidator(AllowEmpty = false)]&lt;br /&gt;public string InputDirectory { get; set; }&lt;br /&gt;&lt;br /&gt;[TaskAttribute(&amp;quot;outputFile&amp;quot;, Required = true)]&lt;br /&gt;[StringValidator(AllowEmpty = false)]&lt;br /&gt;public string OutputFile { get; set; }&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Each of the two properties have 2 attributes associated with it.&amp;#160; The first, &lt;font face="Courier"&gt;TaskName&lt;/font&gt;, defines what the task attribute is called inside of the build file and if it's required or not.&amp;#160; This name does not have to match the name of the property.&amp;#160; The second, is a &lt;font face="Courier"&gt;StringValidator&lt;/font&gt; to help ensure the integrity of the data that is passed into it.&amp;#160; For the example, the validation on both properties is to just ensure that an empty string is not passed into each attribute. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;With these updates made, the only things we have left to do is recompile and deploy the dll, update the build file, and test.&amp;#160; Below is the updated build file:&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;&lt;br /&gt;&amp;lt;project name=&amp;quot;Log Combiner&amp;quot; default=&amp;quot;default&amp;quot; basedir=&amp;quot;.&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;description&amp;gt;This is an example build file.&amp;lt;/description&amp;gt;&lt;br /&gt;    &lt;br /&gt;    &amp;lt;target name=&amp;quot;default&amp;quot; description=&amp;quot;Default Task&amp;quot;&amp;gt;&lt;br /&gt;        &amp;lt;logCombiner inputDirectory=&amp;quot;..\logs\&amp;quot; outputFile=&amp;quot;combined.txt&amp;quot; /&amp;gt;&lt;br /&gt;    &amp;lt;/target&amp;gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Looking Ahead:&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;In this part of this series, we created a simple task with a few attributes to enhance the customization.&amp;#160; In the next segments, we'll look into what it takes to add our own types for children nodes similar to the NAnt fileset tags to add file separators as well as allow for including and excluding different files.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Source Code:&lt;/h3&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;&lt;a title="Source Code For The Post" href="http://cid-3cb659da2d58facb.skydrive.live.com/self.aspx/Public/NAntLogCombiner%20-%20Part%201.zip" target="_blank"&gt;VS Project for the Log Combiner Task for NAnt.&lt;/a&gt; &lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/06/writing-custom-nant-task-part-1.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'Writing a Custom NAnt Task (Part 1)';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = 'The first of a 3 part series on writing a custom NAnt task.  In this task, we'll be creating a task that combines log files from a single directory.';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/links/widgets/zoneit.js"&gt;&lt;/script&gt; &lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f06%2fwriting-custom-nant-task-part-1.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f06%2fwriting-custom-nant-task-part-1.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Random-Acts-of-Coding-Writing-a-Custom-NAnt-Task-Part-1"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Frandomactsofcoding.blogspot.com%2F2009%2F06%2Fwriting-custom-nant-task-part-1.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-7719599124412395724?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/06/writing-custom-nant-task-part-1.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-1168485074100305858</guid><pubDate>Thu, 28 May 2009 01:31:00 +0000</pubDate><atom:updated>2009-05-27T20:40:10.597-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Automation</category><category domain="http://www.blogger.com/atom/ns#">Nant</category><title>SchemaSpy for NAnt</title><description>&lt;p&gt;Earlier this year, I talked about a couple of tools to help automate pieces of the development process in some fashion.&amp;#160; One such tool was &lt;a title="Database Documentation with SchemaSpy" href="http://randomactsofcoding.blogspot.com/2009/01/database-documentation-using-schemaspy.html" target="_blank"&gt;SchemaSpy&lt;/a&gt;, a Java-based database documentation tool.&amp;#160; SchemaSpy is a tool that I love working with; however, always was annoyed of using it in a manual method.&amp;#160; I streamlined this a little bit using a batch script but it still didn't feel quite right when I hooked it up to my automated deployments.&amp;#160; So, I did what any process driven developer would do; I made it work more naturally into NAnt.&lt;/p&gt;  &lt;p&gt;I started a custom NAnt task for SchemaSpy.&amp;#160; Given the complexity of using SchemaSpy to begin with, I decided to not seek to have it added to the NAnt contrib or similar libraries around the web.&amp;#160; However, even though I wanted it separate, I did decide to open source it.&amp;#160; So, I create a &lt;a title="SchemaSpy Task for NAnt" href="http://schemaspynant.codeplex.com/" target="_blank"&gt;CodePlex project to host my NAnt task for SchemaSpy&lt;/a&gt;.&amp;#160; In it's current version, it only has the bare minimum of options that I have required; however, I am hoping to continue working on it until it's feature complete.&amp;#160; If you are looking for a great way to document your databases in associated with your automated builds with NAnt, take a look at it since it hopefully will provide you options for what you need.&lt;/p&gt;  &lt;p&gt;I'm always open for feedback and recommendations on the task.&amp;#160; Hopefully I'll be posting the next release with in the week.&lt;/p&gt;  &lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/05/schemaspy-for-nant.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'SchemaSpy for NAnt';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = 'A post discussing the start of an open source project to merge the build automation tool of NAnt with the Database Documentation tool of SchemaSpy.';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt; &lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f05%2fschemaspy-for-nant.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f05%2fschemaspy-for-nant.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Random-Acts-of-Coding-SchemaSpy-for-NAnt"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Frandomactsofcoding.blogspot.com%2F2009%2F05%2Fschemaspy-for-nant.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-1168485074100305858?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/05/schemaspy-for-nant.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-6262159452831704019</guid><pubDate>Wed, 13 May 2009 14:17:00 +0000</pubDate><atom:updated>2009-05-13T09:23:15.909-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Commentary</category><category domain="http://www.blogger.com/atom/ns#">Resources</category><category domain="http://www.blogger.com/atom/ns#">Personal Development</category><title>Expecting More From Example Code</title><description>&lt;p&gt;While I'm typing this post, I'm actually on vacation.&amp;#160; A road trip to a destination in hopes to relax and unwind from my daily routines.&amp;#160; However, I had to bring the laptop for informational purposes (of course).&amp;#160; On the road, I was thinking about some of the posts that I have created and also of those that I refer back to.&amp;#160; I also compared a lot of these posts against the increased visibility toward the &lt;a title="Hanselminutes Episode 145: SOLID Principles with Uncle Bob." href="http://www.hanselman.com/blog/HanselminutesPodcast145SOLIDPrinciplesWithUncleBobRobertCMartin.aspx" target="_blank"&gt;S.O.L.I.D. principles of Object Oriented design&lt;/a&gt;.&amp;#160; The more I thought about it, the more I became &lt;a title="Inspiration is Magical - 37Signals" href="http://www.37signals.com/svn/posts/72-inspiration-is-magical" target="_blank"&gt;inspired&lt;/a&gt; on the question of should people who read blogs and go to presentations expect more from the authors?&lt;/p&gt;  &lt;p&gt;In my opinion, the presentations and the traditional style of technical blog posts are fine.&amp;#160; I feel like they teach a concentrated concept in a, hopefully, straight forward manner.&amp;#160; Some topics provide more practical implementation; however, how many times have you ran across a demo where the variables were only named &lt;font face="Courier"&gt;Foo&lt;/font&gt; and &lt;font face="Courier"&gt;Bar&lt;/font&gt;?&amp;#160; Presenting a concept is great and effective; however, should more be provided in the examples of in a supplemental post on how to apply the information &amp;quot;properly&amp;quot;?&lt;/p&gt;  &lt;p&gt;For example, I wrote a post on using &lt;a title="Starting with JQuery: Effects" href="http://randomactsofcoding.blogspot.com/2008/08/starting-with-jquery-effects.html" target="_blank"&gt;jQuery for different types of visual effects&lt;/a&gt; of your elements last year.&amp;#160; It was a very simple post with a moderate amount of code that focused on the topic and didn't deviate.&amp;#160; I, as the author, left it up to the reader to apply this knowledge into their own works.&amp;#160; What if I was to go 1 step further and do a live demo similar to blogs like &lt;a href="http://beckelman.net" target="_blank"&gt;Beckelman.net&lt;/a&gt; and &lt;a href="http://www.JankoAtWarpSpeed.com" target="_blank"&gt;JankoAtWarpSpeed.com&lt;/a&gt;?&amp;#160; Would that help push the concept better?&amp;#160; What if I supplied a zip file with files that apply the concepts learn in a more real-world scenario?&amp;#160; A lot of my more recent posts include VS projects; however, it is usually a direct reflection of the code inside of the post.&amp;#160; In that &lt;a title="Starting with JQuery: Effects" href="http://randomactsofcoding.blogspot.com/2008/08/starting-with-jquery-effects.html" target="_blank"&gt;jQuery effects posts&lt;/a&gt;, I could have easily created a simple directory structure containing the proper files in a traditional/standard method (i.e. separating the CSS and JavaScript into their own directories, etc.).&amp;#160; With regards to my .Net posts, should I make sure that all of my code is commented? Refactored properly to meet the SOLID principles (sans my F# code due to it being functional and not oo)? Include Unit Tests?&amp;#160; I know a lot of people, including myself, who learned some skill by taking someone else's code and then tinkering and tweaking it to learn how things work based on their changes.&amp;#160; I'm wondering if more people would used Unit Testing or &amp;quot;proper&amp;quot; OO design if more of the example code in the blogsphere came with such.&lt;/p&gt;  &lt;p&gt;I said earlier that presentations and the traditional blog post is fine as is.&amp;#160; The reason why I say this yet question the example code is that the extra stuff (i.e. Unit Tests, Full Comments, properly design class structures) can sometimes sidetrack the post or presentation.&amp;#160; Questions often rise about these ancillary items as opposed to the concept you are attempting to teach.&amp;#160; So, with that said, I still believe that the posts and presentations are fine.&lt;/p&gt;  &lt;p&gt;Should we expect more from the Example Code?&amp;#160; In my opinion, yes.&amp;#160; I know I have a lot of work to do since adding such polish is time consuming; however, if it can assist in improving the overall quality of the code someone else uses, then it'd be worth it.&lt;/p&gt;  &lt;p&gt;What do you think?&amp;#160; Should those of us that read blog posts and presentations expect more from the example code tied to such?&amp;#160; Should those of us that author posts provide a more comprehensive look at their code in order to encourage better practices?&lt;/p&gt;  &lt;p&gt;What do you think?&lt;/p&gt;  &lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/05/expecting-more-from-example-code.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'Expecting More From Example Code';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = 'Should blog posts and presentations provide more polished examples in order to encourage better coding practices?';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f05%2fexpecting-more-from-example-code.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f05%2fexpecting-more-from-example-code.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Random-Acts-of-Coding-Expecting-More-From-Example-Code"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Frandomactsofcoding.blogspot.com%2F2009%2F05%2Fexpecting-more-from-example-code.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-6262159452831704019?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/05/expecting-more-from-example-code.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-8208909873917617942</guid><pubDate>Wed, 08 Apr 2009 16:50:00 +0000</pubDate><atom:updated>2009-04-08T11:56:58.044-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Commentary</category><title>Automating Features vs. Fundamentals</title><description>&lt;p&gt;I have been in a lot of meetings over the past few years where inefficiencies in a few practices and policies were being discussed.&amp;#160; In terms of software development, there's a lot of things that can be done to improve how the code is written, deployed, and tested.&amp;#160; The meetings began talking about these possible options; however, after about a 10 minute discussion in the first meeting, everyone seemed intent on designing the tools specific to their domain and not the groundwork that is common across all domains.&amp;#160; Now, nothing is wrong for discussing features to standardize an approach and not reinvent the wheel every time; however, I have learned that the features are domain specific (albeit some may be more common than others) and it's the recreation of the fundamental code that saps a developer's energy, focus, and motivation usually.&amp;#160; &lt;/p&gt;  &lt;p&gt;Years have went by and still the same people talk about the features without giving any thought into the remedial code that is common and takes the longest usually.&amp;#160; Between debating the aspects of the features and evaluating tools, such turned into analysis paralysis very quickly with very few realizing it.&amp;#160; Soon, the feature advocates turned more into idea zealots; preaching their views while not provided any acknowledgement to other opinions.&lt;/p&gt;  &lt;p&gt;Because of all of this talk and no action, I began to run a few tests with some of my colleagues.&amp;#160; There were 3 projects that shared the same core project foundation in it's design but each developer was going to create their own.&amp;#160; For the sake of this story, we'll say that this was going to be a &amp;quot;professional&amp;quot; Hello, World console application that had to handle industry standard command line arguments (i.e. -? and a few others).&amp;#160; Each person took about 5-6hrs writing the basis of their console application; setting the proper output color schemes and the console output for the help information and other fundamental requirements.&amp;#160; Finally it took them about 1hr to do the actual project specific logic. Now, in this example, one could say that Developer-A creates it and then passes it along to the others in a copy/paste sort of way; however, the test needed to be done not only for time purposes but for implementation purposes since all 3 application bases were not consistent.&lt;/p&gt;  &lt;p&gt;From these examples, we refined the foundations and eventually abstracted it into a Visual Studio project template.&amp;#160; The next time they they had an opportunity to use the template, it saved them that much time yet again.&amp;#160; This template was only the fundamentals and didn't have any actual features (no consistent way to do things like emailing or FTP services or error handling).&amp;#160; Later versions have added these features into it (or provided a model to make it easy to do a custom implementation) but the original versions were just the fundamentals.&lt;/p&gt;  &lt;p&gt;In the end of this experience, the idea zealots were still preaching their features without recommending any solution to their implementation and we became more efficient by automating the fundamentals.&amp;#160; If you're looking to improve efficiency, try to find remedial, repetitive areas in your process and see about automating them.&amp;#160; Start with the fundamentals and then add features to it.&amp;#160; There'll be changes; however, if you Develop &amp;gt; Refactor &amp;gt; and then Abstract what works, you'll be in a much better place than if you stayed in a meeting room and debated about what features should be in the initial version of the script or template.&amp;#160; My Rule of Thumb from experience: Version 0 of any automation script or template should only have the minimum amount of features possible and focus on the fundamentals.&lt;/p&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/04/features-vs-fundamentals.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'Automating Features vs. Fundamentals';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = 'A story about where to begin when looking to automate processes and coding practices.';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt; &lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f04%2ffeatures-vs-fundamentals.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f04%2ffeatures-vs-fundamentals.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Random-Acts-of-Coding-Automating-Features-vs-Fundamentals"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Frandomactsofcoding.blogspot.com%2F2009%2F04%2Ffeatures-vs-fundamentals.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-8208909873917617942?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/04/features-vs-fundamentals.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-3522271835080134325</guid><pubDate>Wed, 01 Apr 2009 11:00:00 +0000</pubDate><atom:updated>2009-04-01T12:18:27.797-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">F#</category><title>How I'm Learning F# - Working with .Net Objects and Properties</title><description>&lt;p&gt;Over the past few months, I've been hearing more and more about the use of functional programming concepts and also languages like Haskell and F#.&amp;#160; While some of the initial musings that I've read revolved around how the concepts have been around for decades and that it makes financial and scientific applications easier to read and write, I couldn't find a good reason to start learning it for my typical line-of-business application design and development job or even some of my basic hobby projects.&amp;#160; Nonetheless, I kept getting drawn to the concept and have decided to focus on learning it.&lt;/p&gt;&lt;p&gt;This post marks the fourth entry of a series that I'll be writing to discuss how I'm going about learning F#.&amp;#160; While I'm not saying that my method of learning is ideal and should be followed by others, I'm just reporting how I'm going about doing it.&amp;#160; Over the course of this series, my goal is to provide other .Net developers a(nother) resource for learning the F# language as well as apply the language into some non-financial or scientific scenarios.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Series Table of Contents:&lt;/h3&gt;&lt;ol&gt;  &lt;li&gt;&lt;a title="How I&amp;#39;m Learning F# - Finding Resources" href="http://randomactsofcoding.blogspot.com/2009/02/how-i-learning-f-finding-resources.html" target="_blank"&gt;Finding Resources&lt;/a&gt; &lt;/li&gt;  &lt;li&gt;&lt;a title="How I&amp;#39;m Learning F# - Writing the First Application" href="http://randomactsofcoding.blogspot.com/2009/02/how-i-learning-f-writing-first.html" target="_blank"&gt;Writing the First Application&lt;/a&gt; &lt;/li&gt;  &lt;li&gt;&lt;a title="Interacting with the .Net Framework" href="http://randomactsofcoding.blogspot.com/2009/03/how-i-learning-f-interacting-with-net.html" target="_blank"&gt;Interacting with the .Net Framework&lt;/a&gt; &lt;/li&gt;  &lt;li&gt;Working with .Net Objects and Properties &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&amp;#160; &lt;/p&gt;&lt;h3&gt;Project Overview:&lt;/h3&gt;&lt;p&gt;In this post, I'm going to interact with libraries in the .Net framework to illustrate how to you'll be able to apply F# to functionality that normally may do in another language. Unlike the last project in this series that just brushed on using some static methods of the &lt;font face="Courier"&gt;System.IO.File&lt;/font&gt; class, this post will be focusing on the various steps it takes to send an email message and working with the properties of the &lt;font face="Courier"&gt;System.Net.Mail.MailMessage&lt;/font&gt; class.&amp;#160; In this example, we'll be doing the following:&lt;/p&gt;&lt;ol&gt;  &lt;li&gt;Instantiating a new &lt;font face="Courier"&gt;MailMessage&lt;/font&gt; object. &lt;/li&gt;  &lt;li&gt;Set the &lt;font face="Courier"&gt;To&lt;/font&gt;, &lt;font face="Courier"&gt;From&lt;/font&gt;, &lt;font face="Courier"&gt;Body&lt;/font&gt;, and &lt;font face="Courier"&gt;Subject&lt;/font&gt; properties of the object &lt;/li&gt;  &lt;li&gt;Attach a text file to the message. &lt;/li&gt;  &lt;li&gt;Send the message via a SMTP server. &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Throughout the course of this project, we'll be dealing with a large amount of F# syntax as well as a couple of assemblies from the .Net Framework.&amp;#160; This post will hopefully be pretty straight forward in the steps outlined above. &lt;/p&gt;&lt;h3&gt;&amp;#160;&lt;/h3&gt;&lt;h3&gt;Starting With The Values:&lt;/h3&gt;&lt;p&gt;To keep this example simple, I'm going to be declaring our &lt;font face="Courier"&gt;To Address&lt;/font&gt;, &lt;font face="Courier"&gt;From Address&lt;/font&gt;, &lt;font face="Courier"&gt;Subject&lt;/font&gt;, and SMTP Server values first thing.&amp;#160; We will be using these values as we begin to set the object properties of our &lt;font face="Courier"&gt;MailMessage&lt;/font&gt; object shortly; however, to allow for easier visibility, I'm setting these up prior.&lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;let ToAddress = &amp;quot;MyToAddress@domain.com&amp;quot;     &lt;br /&gt;let FromAddress = &amp;quot;MyFromAddress@domain.com&amp;quot;     &lt;br /&gt;let Subject = &amp;quot;F# Email Example&amp;quot;     &lt;br /&gt;let SMTPServer = &amp;quot;127.0.0.1&amp;quot;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Instantiating Objects in F#:&lt;/h3&gt;&lt;p&gt;Now that we have our values established, let's open up the &lt;font face="Courier"&gt;System.Net.Mail&lt;/font&gt; namespace and instantiate our own &lt;font face="Courier"&gt;MailMessage&lt;/font&gt; object. To do this, we do the following snippet of code:&lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;open System.Net.Mail &lt;/font&gt;  &lt;br /&gt;  &lt;br /&gt;&lt;font face="courier"&gt;let mm = new MailMessage()     &lt;br /&gt;mm.To.Add(ToAddress)     &lt;br /&gt;mm.From &amp;lt;- new MailAddress(FromAddress)     &lt;br /&gt;mm.Subject &amp;lt;- Subject     &lt;br /&gt;mm.Body &amp;lt;- &amp;quot;Hello, F# Email&amp;quot;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;Here we begin to see some new syntax in F#.&amp;#160; The syntax to instantiating a new &lt;font face="Courier"&gt;MailMessage&lt;/font&gt; object is very similar to that of C# or VB.Net in that we are setting a value using the &lt;font face="Courier"&gt;new&lt;/font&gt; keyword. Next we are calling the &lt;font face="Courier"&gt;MailMessage's To&lt;/font&gt; collection proptery's method of &lt;font face="Courier"&gt;Add()&lt;/font&gt; to add our address we assigned initially.&amp;#160; After that, we are assigning the &lt;font face="Courier"&gt;MailMessage&lt;/font&gt;.From property to a new instance of a &lt;font face="Courier"&gt;MailAddress&lt;/font&gt; Object.&amp;#160; Since object properties that are not read-only are mutable (or can change), we use the &lt;font face="Courier"&gt;&amp;lt;-&lt;/font&gt; operator to assign a value to the property.&amp;#160; This action is repeated to assign the &lt;font face="Courier"&gt;Subject&lt;/font&gt; and &lt;font face="Courier"&gt;Body&lt;/font&gt; properties on the last lines of the snippet.&lt;/p&gt;&lt;p&gt;&amp;#160; &lt;/p&gt;&lt;h3&gt;Attaching a File:&lt;/h3&gt;&lt;p&gt;The last item we have to do with our &lt;font face="Courier"&gt;MailMessage&lt;/font&gt; object is to add the attachment.&amp;#160; The file we're going to use is a local text file.&amp;#160; For simplicity sake, we'll use the relative path to the file and assign it to a value first.&amp;#160; Then we'll add the file as a new attachment to our &lt;font face="Courier"&gt;MailMessage&lt;/font&gt; object.&lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;let filePath = @&amp;quot;.\commadelimitedfile.txt&amp;quot;     &lt;br /&gt;mm.Attachments.Add(new Attachment(filePath))&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Sending the Email:&lt;/h3&gt;&lt;p&gt;We now have a perfectly good &lt;font face="Courier"&gt;MailMessage&lt;/font&gt; object sitting in memory.&amp;#160; The only thing that's left to do is to send it out.&lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;let client = new SmtpClient()     &lt;br /&gt;client.Host &amp;lt;- SMTPServer     &lt;br /&gt;client.Send(mm)&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;&lt;/font&gt;&lt;/p&gt;&lt;h3&gt;The Full Project Source:&lt;/h3&gt;&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: gray 1px solid; cursor: text; border-right: gray 1px solid; padding-top: 4px"&gt;  &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; #light&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt;&amp;#160; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt; let ToAddress = &lt;span style="color: #006080"&gt;&amp;quot;MyToAddress@domain.com&amp;quot;&lt;/span&gt;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt; let FromAddress = &lt;span style="color: #006080"&gt;&amp;quot;MyFromAddress@domain.com&amp;quot;&lt;/span&gt;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt; let Subject = &lt;span style="color: #006080"&gt;&amp;quot;F# Email Example&amp;quot;&lt;/span&gt;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt; let SMTPServer = &lt;span style="color: #006080"&gt;&amp;quot;127.0.0.1&amp;quot;&lt;/span&gt;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;&amp;#160; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt; open System.Net.Mail&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;&amp;#160; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt; let mm = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; MailMessage()&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt; mm.To.Add(ToAddress)&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  12:&lt;/span&gt; mm.From &amp;lt;- &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; MailAddress(FromAddress)&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  13:&lt;/span&gt; mm.Subject &amp;lt;- Subject&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  14:&lt;/span&gt; mm.Body &amp;lt;- &lt;span style="color: #006080"&gt;&amp;quot;Hello, F# Email&amp;quot;&lt;/span&gt;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  15:&lt;/span&gt;&amp;#160; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  16:&lt;/span&gt; let filePath = &lt;span style="color: #006080"&gt;@&amp;quot;.\CommaDelimitedFile.txt&amp;quot;&lt;/span&gt;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  17:&lt;/span&gt; let att = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Attachment(filePath)&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  18:&lt;/span&gt; mm.Attachments.Add(att)&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  19:&lt;/span&gt;&amp;#160; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  20:&lt;/span&gt; let client = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SmtpClient()&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  21:&lt;/span&gt; client.Host &amp;lt;- SMTPServer&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  22:&lt;/span&gt; client.Send(mm)&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Summary&lt;/h3&gt;&lt;p&gt;This has been a very short and simple example on how to interact with the .Net framework objects and their properties.&amp;#160; At this point, some basic and typical tasks that are used in applications could be transposed to F# if you so desired.&amp;#160; With F# being a concise language, it has some benefits over traditional object-oriented languages. &lt;/p&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/04/how-i-learning-f-working-with-net.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'How I'm Learning F# - Working with .Net Objects and Properties';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = 'This post marks the fourth entry of a series that I'll be writing to discuss how I'm going about learning F#. In this segment, I'll dive into using .Net objects and their properties.';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt; &lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f04%2fhow-i-learning-f-working-with-net.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f04%2fhow-i-learning-f-working-with-net.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Random-Acts-of-Coding-How-Im-Learning-F-Working-with-Net-Objects-and-Properties"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Frandomactsofcoding.blogspot.com%2F2009%2F04%2Fhow-i-learning-f-working-with-net.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-3522271835080134325?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/04/how-i-learning-f-working-with-net.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-724214158780103170</guid><pubDate>Thu, 26 Mar 2009 02:15:00 +0000</pubDate><atom:updated>2009-03-26T08:38:17.854-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">JavaScript</category><category domain="http://www.blogger.com/atom/ns#">AJAX</category><category domain="http://www.blogger.com/atom/ns#">ASP.Net</category><category domain="http://www.blogger.com/atom/ns#">jQuery</category><title>jQuery, JSON, and ASMX 2.0 Services</title><description>&lt;p&gt;A few weeks ago, I had a project that was grounded in the .Net Framework v2.0 and Visual Studio 2005.&amp;#160; The requirements were very focused on usability and speed so AJAX and jQuery were high on my list to use.&amp;#160; Through the project, I learned that there isn't a large amount of information in one place that tells you how to setup a ASP.Net solution that uses jQuery and ASMX services to effectively transmit json data back and forth from the client.&amp;#160; Because of this, I'll attempt to fill this void since there are still many developers and companies out there that have not been able to upgrade to Visual Studio 2008. &lt;/p&gt;&lt;p&gt;In this post, I'll discuss the process of building a plain ASP.Net 2.0 web application project (not web site project) , setting up the necessary entries in the &lt;font face="Courier"&gt;web.config&lt;/font&gt; file to utilize the ASP.Net 2.0 AJAX Extensions v1.0, and use jQuery at the client side of the transfers.&amp;#160;&amp;#160;&amp;#160; In addition, I'll also show to to use the &lt;font face="Courier"&gt;JavaScriptSerializer&lt;/font&gt; class and how to write your own custom converter for your objects.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;A Note About This Post:&lt;/h3&gt;&lt;p&gt;This post is focused on Visual Studio 2005 with the ASP.Net 2.0 AJAX Extensions v1.0.&amp;#160; The v3.5 of the extensions that came with ASP.Net v3.5 and Visual Studio 2008 have a few changes.&amp;#160; While I will try to point out the differences, the core of this post is going to be focused on Visual Studio 2005 web application projects and v1.0 of the AJAX extensions.&amp;#160; While we all love focusing on the latest and greatest, I'm aware that there are a large number of companies and professionals out there that are locked into using the older version of the software for a number of reasons.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Additions to VS2005 Used in This Post:&lt;/h3&gt;&lt;p&gt;This post will be using the following additions to VS2005.&amp;#160; Below are the items and links to their respective installers:&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/asp.net/aa336618.aspx" target="_blank"&gt;Web Application Project&lt;/a&gt; &lt;/li&gt;  &lt;li&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=ca9d90fa-e8c9-42e3-aa19-08e2c027f5d6&amp;amp;displaylang=en" target="_blank"&gt;ASP.Net 2.0 AJAX Extensions v1.0&lt;/a&gt; &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Code Downloads for This Post:&lt;/h3&gt;&lt;ul&gt;  &lt;li&gt;&lt;a href="http://cid-3cb659da2d58facb.skydrive.live.com/self.aspx/Public/jQuery%20JSON%20and%20ASMX.zip" target="_blank"&gt;Visual Studio 2005 Example Project&lt;/a&gt;&amp;#160;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Creating and Configuring a New WAP:&lt;/h3&gt;&lt;p&gt;Now that we have the required additions established, we're ready to create a new ASP.Net 2.0 Web Application Project.&amp;#160; I'm not going to get into the details of how to do this; however, I want to stress that I'm NOT choosing an ASP.Net AJAX Enabled Web Application.&amp;#160; I'm just choosing to create a new, basic ASP.Net Web Application Project.&amp;#160; Now that the project has been created, we need to add a few references and add some information into the &lt;font face="Courier"&gt;Web.Config&lt;/font&gt; file.&lt;/p&gt;&lt;p&gt;In the Solution Explorer, we'll need to add a reference to the AJAX Extensions v1.0 library, &lt;font face="Courier"&gt;System.Web.Extensions.dll&lt;/font&gt;.&amp;#160; By default, this library is located at C:\Program Files\Microsoft ASP.Net\ASP.Net 2.0 AJAX Extensions\v1.0.61025\ directory.&amp;#160; After adding this reference, we can update our &lt;font face="Courier"&gt;Web.Config&lt;/font&gt; file by including a reference to the &lt;font face="Courier"&gt;ScriptHandlerFactory&lt;/font&gt; HttpHandler using the following snippet inside of the &lt;font face="Courier"&gt;&amp;lt;System.Web&amp;gt;&lt;/font&gt; config section:&lt;/p&gt;&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: gray 1px solid; cursor: text; border-right: gray 1px solid; padding-top: 4px"&gt;  &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;remove&lt;/span&gt; &lt;span style="color: #ff0000"&gt;verb&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;*&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;path&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;*.asmx&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;add&lt;/span&gt; &lt;span style="color: #ff0000"&gt;verb&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;*&amp;quot;&lt;/span&gt; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;      &lt;span style="color: #ff0000"&gt;path&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;*.asmx&amp;quot;&lt;/span&gt; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;      &lt;span style="color: #ff0000"&gt;validate&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;false&amp;quot;&lt;/span&gt; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;      &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;System.Web.Script.Services.ScriptHandlerFactory, &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;            System.Web.Extensions, &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;            Version=1.0.61025.0, &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;            Culture=neutral, &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;            PublicKeyToken=31bf3856ad364e35&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;By adding the AJAX Extensions reference and updating the &lt;font face="Courier"&gt;web.config&lt;/font&gt; file, we're now ready to enable our ASP.Net Web Services (ASMX) to be called from JavaScript.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Setting Up an ASMX Web Service:&lt;/h3&gt;&lt;p&gt;We have our new WAP setup and configured, it's time to write a simple ASMX web service and configure it so that it will be able to return JSON.&amp;#160; To do this, let's add a web service to our project called &lt;font face="Courier"&gt;JsonService.asmx&lt;/font&gt; and add the following code snippet to replace some of the defaults Visual Studio gives you:&lt;/p&gt;&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; height: 265px; max-height: 200px; font-size: 8pt; overflow: auto; border-top: gray 1px solid; cursor: text; border-right: gray 1px solid; padding-top: 4px"&gt;  &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;using&lt;/span&gt; System.Web.Script.Services;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;using&lt;/span&gt; System.Web.Script.Serialization;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;&amp;#160; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt; [WebService(Namespace = &lt;span style="color: #006080"&gt;&amp;quot;http://YourNamespaceHere.com&amp;quot;&lt;/span&gt;)]&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt; [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt; [ScriptService()]&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; JsonService : System.Web.Services.WebService&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;     [WebMethod]&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt;     [ScriptMethod(ResponseFormat = ResponseFormat.Json)]&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  12:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; GetCustomer()&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  13:&lt;/span&gt;     {&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  14:&lt;/span&gt;         &lt;span style="color: #008000"&gt;// Method Body&lt;/span&gt;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  15:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  16:&lt;/span&gt; }&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;Lines 1-3, I imported 3 additional namespaces to use in the code.&amp;#160; &lt;font face="Courier"&gt;System.Collections.Generics&lt;/font&gt; will be used in the next section.&amp;#160; &lt;font face="Courier"&gt;System.Web.Script.Services&lt;/font&gt; allow us to decorate the service and it's methods as Script methods for the &lt;font face="Courier"&gt;ScriptHandlerFactory&lt;/font&gt; to use when making AJAX calls to and from the client.&lt;/p&gt;&lt;p&gt;Line 7 decorates the web service with the &lt;font face="Courier"&gt;[ScriptService()]&lt;/font&gt; attribute.&lt;/p&gt;&lt;p&gt;Line 11 decorates the &lt;font face="Courier"&gt;GetCustomer()&lt;/font&gt; web method with the &lt;font face="Courier"&gt;[ScriptMethod()]&lt;/font&gt; attribute.&amp;#160; This attribute tells the &lt;font face="Courier"&gt;ScriptHandlerFactory&lt;/font&gt; that this method is allowed to be called from an Ajax Client.&amp;#160; The properties inside of the attribute, &lt;font face="Courier"&gt;ResponseFormat = ResponseFormat.Json&lt;/font&gt;, tells the &lt;font face="Courier"&gt;ScriptHandlerFactory&lt;/font&gt; to send the response stream as a json string and not XML or Soap.&amp;#160; If a response to the web service that is not formatted as json, the response will be returned as XML.&lt;/p&gt;&lt;p&gt;At this point, we can create the body of our web method in any fashion as long as it returns a string.&amp;#160; If you are only passing base types, you can skip down to the &lt;strong&gt;Talking to the Server Using jQuery&lt;/strong&gt; section; however, if you want to pass something a bit more complex, I recommend you continue to the next section.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Using the JavaScriptSerializer and a Custom Converter:&lt;/h3&gt;&lt;p&gt;While passing base types is easy enough, it can be important to pass objects back and forth from the client.&amp;#160; In order to assist with this, the ASP.Net AJAX Extensions v1.0 comes with the &lt;font face="Courier"&gt;JavaScriptSerializer&lt;/font&gt; object.&amp;#160; This object has the ability to serialize certain objects into strings representing json objects.&amp;#160; This sounds great and the answer to all of our problem!&amp;#160; Too bad it is very limiting in it's natural state.&amp;#160; It CAN convert &lt;font face="Courier"&gt;Arrays&lt;/font&gt; of base types and (from what I can tell) any framework classes that implements &lt;font face="Courier"&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/font&gt;.&amp;#160; I haven't experimented with some of the more obscure generic collections; however, I do know that it does concern &lt;font face="Courier"&gt;List&amp;lt;T&amp;gt;&lt;/font&gt; and &lt;font face="Courier"&gt;Dictionary&amp;lt;S,V&amp;gt;&lt;/font&gt; just fine.&amp;#160; &lt;/p&gt;&lt;p&gt;In order to use the &lt;font face="Courier"&gt;JavaScriptSerializer&lt;/font&gt;, you simply instantiate it and call its &lt;font face="Courier"&gt;Serialize()&lt;/font&gt; method, passing the object that you wish to serialize.&amp;#160; If this is a string array or an object of type &lt;font face="Courier"&gt;Dictionary&amp;lt;string,string&amp;gt;&lt;/font&gt;, it will do all of the heavy conversion for you and give you a nice little string to return to the client as shown below:&lt;/p&gt;&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: gray 1px solid; cursor: text; border-right: gray 1px solid; padding-top: 4px"&gt;  &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #008000"&gt;// Method Body&lt;/span&gt;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; Dictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;&amp;gt; customerInfo = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;&amp;gt;();&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt; customerInfo.Add(&lt;span style="color: #006080"&gt;&amp;quot;FirstName&amp;quot;&lt;/span&gt;, &lt;span style="color: #006080"&gt;&amp;quot;John&amp;quot;&lt;/span&gt;);&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt; customerInfo.Add(&lt;span style="color: #006080"&gt;&amp;quot;LastName&amp;quot;&lt;/span&gt;, &lt;span style="color: #006080"&gt;&amp;quot;Doe&amp;quot;&lt;/span&gt;);&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt; customerInfo.Add(&lt;span style="color: #006080"&gt;&amp;quot;EmailAddress&amp;quot;&lt;/span&gt;, &lt;span style="color: #006080"&gt;&amp;quot;JohnDoe@Domain.Com&amp;quot;&lt;/span&gt;);&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt; customerInfo.Add(&lt;span style="color: #006080"&gt;&amp;quot;PhoneNumber&amp;quot;&lt;/span&gt;, &lt;span style="color: #006080"&gt;&amp;quot;555-555-1212&amp;quot;&lt;/span&gt;);&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;&amp;#160; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; JavaScriptSerializer().Serialize(customerInfo);&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;In this code snippet, I have instantiated a new &lt;font face="Courier"&gt;Dictionary&amp;lt;string,string&amp;gt;&lt;/font&gt; generic object and populated with the property information for a customer.&amp;#160; Lastly, I instantiate a new &lt;font face="Courier"&gt;JavaScriptSerializer&lt;/font&gt; object and call it's &lt;font face="Courier"&gt;Serialize&lt;/font&gt; method, passing our customer information into it.&amp;#160; The &lt;font face="Courier"&gt;JavaScriptSerializer&lt;/font&gt; will create following string from our dictionary:&lt;/p&gt;&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: gray 1px solid; cursor: text; border-right: gray 1px solid; padding-top: 4px"&gt;  &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; {&lt;span style="color: #006080"&gt;&amp;quot;FirstName&amp;quot;&lt;/span&gt;:&lt;span style="color: #006080"&gt;&amp;quot;John&amp;quot;&lt;/span&gt;,&lt;span style="color: #006080"&gt;&amp;quot;LastName&amp;quot;&lt;/span&gt;:&lt;span style="color: #006080"&gt;&amp;quot;Doe&amp;quot;&lt;/span&gt;,&lt;span style="color: #006080"&gt;&amp;quot;EmailAddress&amp;quot;&lt;/span&gt;:&lt;span style="color: #006080"&gt;&amp;quot;JohnDoe@Domain.Com&amp;quot;&lt;/span&gt;,&lt;span style="color: #006080"&gt;&amp;quot;PhoneNumber&amp;quot;&lt;/span&gt;:&lt;span style="color: #006080"&gt;&amp;quot;555-555-1212&amp;quot;&lt;/span&gt;}&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;This is just a simple string that, technically, we could have concatenated ourselves; however, you see how it converts the name-value pairs of the &lt;font face="Courier"&gt;Dictionary&lt;/font&gt; object and turns them into a json Object with properties and string values.&lt;/p&gt;&lt;p&gt;Seems pretty simple.&amp;#160; Now, let's turn our customer &lt;font face="Courier"&gt;Dictionary&lt;/font&gt; into a &lt;font face="Courier"&gt;CustomerInfo&lt;/font&gt; object with the same four properties.&amp;#160; Below is the class definition:&lt;/p&gt;&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: gray 1px solid; cursor: text; border-right: gray 1px solid; padding-top: 4px"&gt;  &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; CustomerInfo&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; FirstName { get; set; }&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; LastName { get; set; }&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; EmailAddress { get; set; }&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; PhoneNumber { get; set;}&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt; }&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;Now, if we replace our &lt;font face="Courier"&gt;Dictionary&lt;/font&gt; object with our &lt;font face="Courier"&gt;CustomerInfo&lt;/font&gt; object we get code that looks similar to the following, easier to read, snippet:&lt;/p&gt;&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: gray 1px solid; cursor: text; border-right: gray 1px solid; padding-top: 4px"&gt;  &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #008000"&gt;// Method body&lt;/span&gt;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; CustomerInfo custInfo = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; CustomerInfo();&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt; custInfo.FirstName = &lt;span style="color: #006080"&gt;&amp;quot;John&amp;quot;&lt;/span&gt;;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt; custInfo.LastName = &lt;span style="color: #006080"&gt;&amp;quot;Doe&amp;quot;&lt;/span&gt;;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt; custInfo.EmailAddress = &lt;span style="color: #006080"&gt;&amp;quot;JohnDoe@Domain.Com&amp;quot;&lt;/span&gt;;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt; custInfo.PhoneNumber = &lt;span style="color: #006080"&gt;&amp;quot;555-555-1212&amp;quot;&lt;/span&gt;;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;&amp;#160; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; JavaScriptSerializer().Serialize(custInfo);&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;Sadly, running the above code will give you the following error when you attempt to run it:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_RNnu2VM54fE/ScrlOExHYtI/AAAAAAAAAFI/BTmVShJ1_GY/s1600-h/CircularReferenceError3.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="CircularReferenceError" src="http://lh3.ggpht.com/_RNnu2VM54fE/ScrlOkeaSHI/AAAAAAAAAFM/wJBd9PC6kfs/CircularReferenceError_thumb1.png?imgmax=800" width="427" height="295" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;Since the &lt;font face="Courier"&gt;JavaScriptSerializer&lt;/font&gt; doesn't know the definition of our &lt;font face="Courier"&gt;CustomerInfo&lt;/font&gt; object, we get this Circular Reference error.&amp;#160; This causes us to go down one of two roads.&amp;#160; We can either turn the object manually back into our &lt;font face="Courier"&gt;Dictionary&lt;/font&gt; object, or we can write a custom &lt;font face="Courier"&gt;JavaScriptConverter&lt;/font&gt; for our &lt;font face="Courier"&gt;CustomerInfo&lt;/font&gt; Class.&amp;#160; The nice thing about a custom converter is that once it's setup to our &lt;font face="Courier"&gt;JavaScriptSerializer&lt;/font&gt;, we can then have it convert any number of &lt;font face="Courier"&gt;CustomerInfo&lt;/font&gt; classes (or collections of &lt;font face="Courier"&gt;CustomerInfo&lt;/font&gt; objects) we may need.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Writing A Custom JavaScriptConverter&lt;/h3&gt;&lt;p&gt;Writing our own custom &lt;font face="Courier"&gt;JavaScriptConverter&lt;/font&gt; is not as difficult as one may first assume.&amp;#160; Inside the &lt;font face="Courier"&gt;System.Web.Script.Serialization&lt;/font&gt; namespace, we are provided with an abstract base class that helps us outline the definition and gets us started quickly.&amp;#160; In our project, let's add another class called &lt;font face="Courier"&gt;CustomerInfoConverter&lt;/font&gt;.&amp;#160; Have the class inherit from the &lt;font face="Courier"&gt;JavaScriptConverter&lt;/font&gt; class and right-click on the class name and select &amp;quot;Implement Abstract Class&amp;quot;.&amp;#160; What you get is the following code snippet:&lt;/p&gt;&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: gray 1px solid; cursor: text; border-right: gray 1px solid; padding-top: 4px"&gt;  &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; CustomerInfoConverter : JavaScriptConverter&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; Deserialize(IDictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt;&amp;gt; dictionary, Type type, JavaScriptSerializer serializer)&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;     {&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Exception(&lt;span style="color: #006080"&gt;&amp;quot;The method or operation is not implemented.&amp;quot;&lt;/span&gt;);&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;&amp;#160; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; IDictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt;&amp;gt; Serialize(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; obj, JavaScriptSerializer serializer)&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Exception(&lt;span style="color: #006080"&gt;&amp;quot;The method or operation is not implemented.&amp;quot;&lt;/span&gt;);&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  12:&lt;/span&gt;&amp;#160; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  13:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; IEnumerable&amp;lt;Type&amp;gt; SupportedTypes&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  14:&lt;/span&gt;     {&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  15:&lt;/span&gt;         get { &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Exception(&lt;span style="color: #006080"&gt;&amp;quot;The method or operation is not implemented.&amp;quot;&lt;/span&gt;); }&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  16:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  17:&lt;/span&gt; }&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;The first method the &lt;font face="Courier"&gt;JavaScriptConverter&lt;/font&gt; makes us define is the &lt;font face="Courier"&gt;Deserialize&lt;/font&gt; method.&amp;#160; This method is used by the &lt;font face="Courier"&gt;JavaScriptSerializer&lt;/font&gt; to convert a json object from a client into the expected type of the web method uses as a parameter.&amp;#160; The &lt;font face="Courier"&gt;JavaScriptSerializer&lt;/font&gt; automatically converts the json object into a &lt;font face="Courier"&gt;Dictionary&amp;lt;string, object&amp;gt;&lt;/font&gt; collection.&amp;#160; Inside this method, you could add our mappings between the &lt;font face="Courier"&gt;Dictionary&lt;/font&gt; keys to a new &lt;font face="Courier"&gt;CustomerInfo&lt;/font&gt; object's properties and finally return that new instance of the &lt;font face="Courier"&gt;CustomerInfo&lt;/font&gt; object.&amp;#160; Below is the method body:&lt;/p&gt;&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: gray 1px solid; cursor: text; border-right: gray 1px solid; padding-top: 4px"&gt;  &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; CustomerInfo cust = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; CustInfo();&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; cust.FirstName = dictionary[&lt;span style="color: #006080"&gt;&amp;quot;FirstName&amp;quot;&lt;/span&gt;].ToString();&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt; cust.LastName = dictionary[&lt;span style="color: #006080"&gt;&amp;quot;LastName&amp;quot;&lt;/span&gt;].ToString();&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt; cust.EmailAddress = dictionary[&lt;span style="color: #006080"&gt;&amp;quot;EmailAddress&amp;quot;&lt;/span&gt;].ToString();&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt; cust.PhoneNumber = dictionary[&lt;span style="color: #006080"&gt;&amp;quot;PhoneNumber&amp;quot;&lt;/span&gt;].ToString();&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;&amp;#160; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; cust;&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;The second method the &lt;font face="Courier"&gt;JavaScriptConverter&lt;/font&gt; makes us define is the &lt;font face="Courier"&gt;Serialize&lt;/font&gt; method.&amp;#160; This method is used during the actual serialize process.&amp;#160; Here, we're creating a new &lt;font face="Courier"&gt;Dictionary&amp;lt;string, object&amp;gt;&lt;/font&gt; collection for our &lt;font face="Courier"&gt;CustomerInfo&lt;/font&gt; class.&amp;#160; Since our &lt;font face="Courier"&gt;CustomerInfo&lt;/font&gt; class will be boxed through the method's parameter, we'll need to properly cast it before we can start adding the values to the &lt;font face="Courier"&gt;Dictionary&lt;/font&gt; object.&amp;#160; Below is the method body:&lt;/p&gt;&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: gray 1px solid; cursor: text; border-right: gray 1px solid; padding-top: 4px"&gt;  &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #008000"&gt;// Cast the obj parameter&lt;/span&gt;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; CustomerInfo cust = obj &lt;span style="color: #0000ff"&gt;as&lt;/span&gt; CustomerInfo;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;&amp;#160; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (cust != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;     Dictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt;&amp;gt; result = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt;&amp;gt;();&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;     result.Add(&lt;span style="color: #006080"&gt;&amp;quot;FirstName&amp;quot;&lt;/span&gt;, cust.FirstName);&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;     result.Add(&lt;span style="color: #006080"&gt;&amp;quot;LastName&amp;quot;&lt;/span&gt;, cust.LastName);&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;     result.Add(&lt;span style="color: #006080"&gt;&amp;quot;EmailAddress&amp;quot;&lt;/span&gt;, cust.EmailAddress);&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;     result.Add(&lt;span style="color: #006080"&gt;&amp;quot;PhoneNumber&amp;quot;&lt;/span&gt;, cust.PhoneNumber);&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt;&amp;#160; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  12:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; result;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  13:&lt;/span&gt; }&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  14:&lt;/span&gt;&amp;#160; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  15:&lt;/span&gt; &lt;span style="color: #008000"&gt;// If the obj doesn't convert for some reason, return an empty dictionary.&lt;/span&gt;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  16:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt;&amp;gt;();&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;The last item the &lt;font face="Courier"&gt;JavaScriptConverter&lt;/font&gt; makes us define is the &lt;font face="Courier"&gt;SupportedTypes&lt;/font&gt; property of type &lt;font face="Courier"&gt;IEnumerable&amp;lt;Type&amp;gt;&lt;/font&gt;.&amp;#160; This property should be a collection of types that this converter supports.&amp;#160; Since we are using this converter only for our &lt;font face="Courier"&gt;CustomerInfo&lt;/font&gt; class, the property can be simplified to the following line of code:&lt;/p&gt;&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: gray 1px solid; cursor: text; border-right: gray 1px solid; padding-top: 4px"&gt;  &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; get { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Type[] { &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(CustomerInfo) }; }&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;Now that we have our converter built, we can attach it to our serializer to get our json string as shown below:&lt;/p&gt;&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: gray 1px solid; cursor: text; border-right: gray 1px solid; padding-top: 4px"&gt;  &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; CustomerInfo cust = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; CustomerInfo();&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; cust.FirstName = &lt;span style="color: #006080"&gt;&amp;quot;John&amp;quot;&lt;/span&gt;;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt; cust.LastName = &lt;span style="color: #006080"&gt;&amp;quot;Doe&amp;quot;&lt;/span&gt;;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt; cust.EmailAddress = &lt;span style="color: #006080"&gt;&amp;quot;JohnDoe@Domain.com&amp;quot;&lt;/span&gt;;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt; cust.PhoneNumber = &lt;span style="color: #006080"&gt;&amp;quot;555-555-1212&amp;quot;&lt;/span&gt;;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;&amp;#160; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt; JavaScriptSerializer jss = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; JavaScriptSerializer();&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt; jss.RegisterConverters(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; CustomerInfoConverter[] { &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; CustomerInfoConverter() });&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; jss.Serialize(cust);&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Talking to the Server using jQuery:&lt;/h3&gt;&lt;p&gt;Now that we have our server-side infrastructure setup, we can begin to write our AJAX client-side code using jQuery.&amp;#160; Compared to all of the code we've written, this is the easier part.&amp;#160; Below is the JavaScript/jQuery code that can be used to call our web service:&lt;/p&gt;&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: gray 1px solid; cursor: text; border-right: gray 1px solid; padding-top: 4px"&gt;  &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;function&lt;/span&gt; GetCustomerFromServer()&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;     $.ajax({&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;         type: &lt;span style="color: #006080"&gt;&amp;quot;POST&amp;quot;&lt;/span&gt;,&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;         url: &lt;span style="color: #006080"&gt;&amp;quot;/JsonService.asmx/GetCustomer&amp;quot;&lt;/span&gt;,&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;         dataType: &lt;span style="color: #006080"&gt;&amp;quot;json&amp;quot;&lt;/span&gt;,&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;         data: &lt;span style="color: #006080"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;,&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;         contentType: &lt;span style="color: #006080"&gt;&amp;quot;application/json; charset=utf-8&amp;quot;&lt;/span&gt;,&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;         success: &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;(msg){&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; custInfo = eval(&lt;span style="color: #006080"&gt;&amp;quot;(&amp;quot;&lt;/span&gt; + msg + &lt;span style="color: #006080"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;);&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt;             alert(custInfo.FirstName);&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  12:&lt;/span&gt;         }&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  13:&lt;/span&gt;     });&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  14:&lt;/span&gt; }&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;In this client-side code, we're making a HTTP Post call to our web service by calling the web method of it directly.&amp;#160; We are stating that we are sending and receiving data in json format.&amp;#160; Despite the fact that our &lt;font face="Courier"&gt;GetCustomer()&lt;/font&gt; web method does not take any parameters, &lt;u&gt;we still need to send an empty json object in order to have json returned.&amp;#160; &lt;/u&gt;&lt;/p&gt;&lt;p&gt;Lastly, we write an anonymous method to handle the successful message returned to us.&amp;#160; The message is evaluated in order to be turned into a json object on the client side.&amp;#160; We then validate the object by echoing the &lt;font face="Courier"&gt;FirstName&lt;/font&gt; property in an alert box.&lt;/p&gt;&lt;p&gt;One thing to remind, this is for ASP.Net 2.0 Web Services.&amp;#160; The response from ASP.Net 3.5 Web Services IS different in that the response message (msg) has it's content in a property only called &amp;quot;d&amp;quot;.&amp;#160; So instead of &lt;font face="Courier"&gt;eval(&amp;quot;(&amp;quot; + msg + &amp;quot;)&amp;quot;)&lt;/font&gt;, it would be &lt;font face="Courier"&gt;eval(&amp;quot;(&amp;quot; + msg.d + &amp;quot;)&amp;quot;)&lt;/font&gt;.&lt;/p&gt;&lt;h3&gt;Summary:&lt;/h3&gt;&lt;p&gt;This post has covered a large amount of steps to get a json-based web service infrastructure setup using jQuery and ASP.Net 2.0 web services.&amp;#160; After a lot of low level research and asking questions to people, I realized that there was not a single location for this information. Hopefully, this post will help fill that gap.&lt;/p&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/03/jquery-json-and-asmx-20-services.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'jQuery, JSON, and ASMX 2.0 Services';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = 'A few weeks ago, I had a project that was grounded in the .Net Framework v2.0 and Visual Studio 2005.  The requirements were very focused on usability and speed so AJAX and jQuery were high on my list to use.  Through the project, I learned that there isn't a large amount of information in one place that tells you how to setup a ASP.Net solution that uses jQuery and ASMX services to effectively transmit json data back and forth from the client.  Because of this, I'll attempt to fill this voice since there are still many developers and companies out there that have not been able to upgrade to Visual Studio 2008.';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f03%2fjquery-json-and-asmx-20-services.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f03%2fjquery-json-and-asmx-20-services.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Random-Acts-of-Coding-jQuery-JSON-and-ASMX-20-Services"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Frandomactsofcoding.blogspot.com%2F2009%2F03%2Fjquery-json-and-asmx-20-services.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-724214158780103170?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/03/jquery-json-and-asmx-20-services.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">13</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-234798705698259084</guid><pubDate>Wed, 18 Mar 2009 21:57:00 +0000</pubDate><atom:updated>2009-03-18T17:03:48.269-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">F#</category><title>How I'm Learning F# - Interacting with the .Net Framework</title><description>&lt;p&gt;Over the past few months, I've been hearing more and more about the use of functional programming concepts and also languages like Haskell and F#.&amp;#160; While some of the initial musings that I've read revolved around how the concepts have been around for decades and that it makes financial and scientific applications easier to read and write, I couldn't find a good reason to start learning it for my typical line-of-business application design and development job or even some of my basic hobby projects.&amp;#160; Nonetheless, I kept getting drawn to the concept and have decided to focus on learning it.&lt;/p&gt;&lt;p&gt;This post marks the third entry of a series that I'll be writing to discuss how I'm going about learning F#.&amp;#160; While I'm not saying that my method of learning is ideal and should be followed by others, I'm just reporting how I'm going about doing it.&amp;#160; Over the course of this series, my goal is to provide other .Net developers a(nother) resource for learning the F# language as well as apply the language into some non-financial or scientific scenarios.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Series Table of Contents:&lt;/h3&gt;&lt;ol&gt;  &lt;li&gt;&lt;a title="How I&amp;#39;m Learning F# - Finding Resources" href="http://randomactsofcoding.blogspot.com/2009/02/how-i-learning-f-finding-resources.html" target="_blank"&gt;Finding Resources&lt;/a&gt; &lt;/li&gt;  &lt;li&gt;&lt;a title="How I&amp;#39;m Learning F# - Writing the First Application" href="http://randomactsofcoding.blogspot.com/2009/02/how-i-learning-f-writing-first.html" target="_blank"&gt;Writing the First Application&lt;/a&gt; &lt;/li&gt;  &lt;li&gt;Interacting with the .Net Framework &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Downloadable Resources:&lt;/h3&gt;&lt;ul&gt;  &lt;li&gt;&lt;a title="Visual Studio 2008 F# Project." href="http://cid-3cb659da2d58facb.skydrive.live.com/self.aspx/Public/F%7C3%20-%20IOExample.zip" target="_blank"&gt;F# Email Example VS2008 Project&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Project Overview:&lt;/h3&gt;&lt;p&gt;In this post, I'm going to interact with libraries in the .Net framework to illustrate how to you'll be able to apply F# to functionality that normally may do in another language. The basis of this project will incorporate 2 activities:&lt;/p&gt;&lt;ol&gt;  &lt;li&gt;Read from a comma delimited text file &lt;/li&gt;  &lt;li&gt;Create a new Fixed-Width based text file &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Throughout the course of this project, we'll be dealing with a large amount of F# syntax as well as a couple of assemblies from the .Net Framework.&amp;#160; This post is a bit of a step from the previous post; however, I am hoping that a lot of the concepts will be applied through a little more comprehensive example.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;What Does It Take to Read a Text File?:&lt;/h3&gt;&lt;p&gt;While I was writing this example, I began to think of how a person traditionally learns a language.&amp;#160; While in our day to day jobs we may gloss over some of the granular steps of what it takes to read from a text file, I began to look for that level of detail in this program.&amp;#160; To read a text file in any .Net language the follow basic steps must be done:&lt;/p&gt;&lt;ol&gt;  &lt;li&gt;Open the System.IO namespace &lt;/li&gt;  &lt;li&gt;Call the File.ReadAllLines(string) static function, passing the path to the file as a parameter. &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;What's nice about F# is that when you think about the detailed steps of a task, you begin to see the lines that you need to write. Here is a function in F# that does the above steps:&lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;open System.IO     &lt;br /&gt;let readFile =     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; File.ReadAllLines(@&amp;quot;C:\...\myFile.txt&amp;quot;)&lt;/font&gt;&lt;/p&gt;&lt;p&gt;By writing the above code, we have just opened a .Net Assembly (&lt;font face="Courier"&gt;System.IO&lt;/font&gt; in this case) and declared a value that returns an array of strings representing each line of the text file.&amp;#160; In the above code, we could have fully qualified the &lt;font face="Courier"&gt;ReadAllLines()&lt;/font&gt; function instead of opening the assembly; however, we will be creating a new file here in a moment so this works out better.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;How Do I Manipulate This Array of Lines?&lt;/h3&gt;&lt;p&gt;So, we have an array of strings representing the lines of delimited words.&amp;#160; Now what?&amp;#160; If we want to take these lines and break them into a fixed lines, we'll need to do the following things:&lt;/p&gt;&lt;ol&gt;  &lt;li&gt;Identify each word in each line (a.k.a. split the delimited string of words) &lt;/li&gt;  &lt;li&gt;Pad each word with spaces until its total length is 25 &lt;/li&gt;  &lt;li&gt;Concatenate the words into one long string per line &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Once again, we can directly map each of these lines to a line or function of code.&amp;#160; Let's see how these steps would look when we translate them into just functions:&lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;let obtainWords (line : string) =     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; line.Split(&amp;quot;,&amp;quot;.toCharArray())     &lt;br /&gt;    &lt;br /&gt;let padWord (word : string) =     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; word.PadRight(25, ' ')     &lt;br /&gt;    &lt;br /&gt;let joinWords (words : string []) =     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; System.String.Concat(words)     &lt;br /&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;Our 3 steps translate fairly easily into single lined functions thanks to some build in String functions of the .Net Framework. Our &lt;font face="Courier"&gt;obtainWords&lt;/font&gt; function takes a string and splits it using a comma being the delimiter.&amp;#160; Next, our &lt;font face="Courier"&gt;padWord&lt;/font&gt; function takes a string an pads it to the right to ensure that it's 25 characters in length.&amp;#160; Lastly, we call the &lt;font face="Courier"&gt;System.String.Concat&lt;/font&gt; function to take a string array and turn it into a single string.&lt;/p&gt;&lt;p&gt;We have our &amp;quot;what&amp;quot; to do to the lines but we haven't really answered the &amp;quot;how&amp;quot;.&amp;#160; In traditional C# or VB.net, we would probably use a &lt;font face="Courier"&gt;for&lt;/font&gt; loop against each read line and then call each function to update the variables in those languages.&amp;#160; We would end up with something that looks like the following in C# (using our function names from above):&lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;for(int x = 0; x&amp;lt;readFile.Length; x++)     &lt;br /&gt;{&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; string[] words = obtainWords(readFile[x]);     &lt;br /&gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; for(int i = 0; i&amp;lt;words.Length; i++)     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; words[i] = padWord(words[i]);     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; readFile[x] = joinWords(words);     &lt;br /&gt;}&lt;/font&gt;&lt;/p&gt;&lt;p&gt;Here we have a loop that iterates through each line read by the &lt;font face="Courier"&gt;readFile&lt;/font&gt; function.&amp;#160; Then we split each line into another array variable.&amp;#160; Next we iterate over the words array and update the values of the array to the padded versions.&amp;#160; Finally, we update the line with the combined strings of our padded words. &lt;/p&gt;&lt;p&gt;The code is pretty straightforward but I don't know many people who like inner loops.&amp;#160; Also, some developers may fall into a trap and attempt to use a &lt;font face="Courier"&gt;foreach&lt;/font&gt; loop instead of a for loop.&amp;#160; If you are not aware of the difference here, the variable generated by a &lt;font face="Courier"&gt;foreach&lt;/font&gt; loop is readonly.&amp;#160; I could iterate over the arrays in a &lt;font face="Courier"&gt;foreach&lt;/font&gt; loop;however I would have to add the values into a different variable altogether in order to &amp;quot;update&amp;quot; the values like I did above.&amp;#160; Thankfully, F# has a special function that cleans this up for us.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Understanding Array.map()&lt;/h3&gt;&lt;p&gt;One of the built in functions that I have really enjoyed in learning is the &lt;font face="Courier"&gt;Array.map()&lt;/font&gt; function.&amp;#160; The &lt;font face="Courier"&gt;Array.map()&lt;/font&gt; function takes a function value and an array as parameters.&amp;#160; It returns a new array that is comprised of values where the function was applied to each element of the provided array.&amp;#160; An example of this functionality is line C# example where we took the &lt;font face="Courier"&gt;words&lt;/font&gt; array of strings and updated all values of the array with the &lt;font face="Courier"&gt;padWord()&lt;/font&gt; function.&amp;#160; By using the &lt;font face="Courier"&gt;Array.map()&lt;/font&gt; function in F#, we get code that does the same thing but looks like the following:&lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;let newWordsArray =     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Array.map (padWord) words&lt;/font&gt;&lt;/p&gt;&lt;p&gt;This creates a new array (&lt;font face="Courier"&gt;newWordsArray&lt;/font&gt;) where the values are the same as if each string in the &lt;font face="Courier"&gt;words&lt;/font&gt; array was applied to the &lt;font face="Courier"&gt;padWord()&lt;/font&gt; function.&amp;#160; One nice thing about the &lt;font face="Courier"&gt;Array.map()&lt;/font&gt; function is that it also allows lambda expressions to be used in place of the function value also.&amp;#160; Lambdas will be covered at a later time though. By using &lt;font face="Courier"&gt;Array.map()&lt;/font&gt;, we can begin to chain our values together and be able to take our delimited file and turn it into a fixed with file.&amp;#160; However, before we get into that, let's look at a technique in F# that allows us to chain these together even easier called Pipelining.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Pipelining with |&amp;gt;&lt;/h3&gt;&lt;p&gt;Pipelining is a technique where you pass the returned value of 1 item and pass it as the parameter of another function.&amp;#160; This is very similar to the a technique in shell scripting using the pipe (|), greater than (&amp;gt;), and double greater than (&amp;gt;&amp;gt;) operators.&amp;#160; For example, in a command window you can type in type in the &lt;font face="Courier"&gt;dir&lt;/font&gt; command and see a list of directories; however, if you wanted to apply paging to the list you can type in &lt;font face="Courier"&gt;dir | more&lt;/font&gt;.&amp;#160; Likewise, if you wanted to send the directory listing from the &lt;font face="Courier"&gt;dir&lt;/font&gt; command to a file you could type in the &lt;font face="Courier"&gt;dir &amp;gt; file.txt&lt;/font&gt; to create/overwrite a new file with the redirected output or &lt;font face="Courier"&gt;dir &amp;gt;&amp;gt; file.txt&lt;/font&gt; to append the directory listing to the contents of file.txt if the file already exists.&lt;/p&gt;&lt;p&gt;In F#, we can take a function and send it's returned function to another function using the &lt;font face="Courier"&gt;|&amp;gt;&lt;/font&gt; operator. In our last examples, we can illustrate this by pipelining the return value of the &lt;font face="Courier"&gt;obtainWords&lt;/font&gt; function (which returns a string array) into our &lt;font face="Courier"&gt;applyPadding&lt;/font&gt; function.&amp;#160; The resulting function (see below) returns a string array that already has every string in the array padded to 25 characters.&amp;#160; &lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;let obtainWords (line : string) =     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; line.Split(&amp;quot;,&amp;quot;.toCharArray())     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; |&amp;gt; applyPadding&lt;/font&gt;&lt;/p&gt;&lt;p&gt;At first glance, this may seem a bit confusing; however, remember what I said in that the output of the first expression (in this case &lt;font face="Courier"&gt;line.Split()&lt;/font&gt;) is used as the parameter of the second (&lt;font face="Courier"&gt;applyPadding&lt;/font&gt;).&amp;#160; In essence we are just reordering how we are just reordering a chain of events.&amp;#160; This simple example is just to show how we can remove the need for one additional value to hold the output of &lt;font face="Courier"&gt;obtainWords&lt;/font&gt; before passing it to &lt;font face="Courier"&gt;applyPadding&lt;/font&gt;. Below is a more applicable example where we do multiple chains in order to give our initial &lt;font face="Courier"&gt;readFile&lt;/font&gt; function the ability to output an already transformed array of strings.&lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;open System.IO     &lt;br /&gt;    &lt;br /&gt;let obtainWords (line : string) =     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; line.Split(&amp;quot;,&amp;quot;.toCharArray())&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;let padWord (word : string) =     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; word.PadRight(25, ' ')     &lt;br /&gt;    &lt;br /&gt;let applyPadding (words : string []) =     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Array.map (padWord) words     &lt;br /&gt;    &lt;br /&gt;let joinWords (words : string []) =     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; System.String.Concat(words)     &lt;br /&gt;    &lt;br /&gt;let readFile =     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; File.ReadAllLines(@&amp;quot;C:\...\myFile.txt&amp;quot;)     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; |&amp;gt; Array.map(obtainWords)     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; |&amp;gt; Array.map(applyPadding)     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; |&amp;gt; Array.map(joinWords)&lt;/font&gt;&lt;/p&gt;&lt;p&gt;Here, we open our &lt;font face="Courier"&gt;System.IO&lt;/font&gt; namespace.&amp;#160; Next we define our functions that we'll be used to transform the data in the file.&amp;#160; Lastly, we create our function, &lt;font face="Courier"&gt;readFile&lt;/font&gt;, that reads the lines into a string array, pipes the array into the &lt;font face="Courier"&gt;Array.map&lt;/font&gt; function that maps the &lt;font face="Courier"&gt;obtainWords&lt;/font&gt; function to the array and returns an array of words.&amp;#160; Those words are then padded and subsquently joined.&amp;#160; Through all of those steps, the &lt;font face="Courier"&gt;readFile&lt;/font&gt; now contains an array of strings that represent the fixed width version of the comma delimited file that it read.&amp;#160; The final step is to now write those lines to our output file.&lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;File.WriteAllLines(@&amp;quot;C:\...\myOutputFile.txt&amp;quot;, readFile)&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Summary&lt;/h3&gt;&lt;p&gt;At this point, another function can be established to do anything with the output file that you wish.&amp;#160; You could use the &lt;font face="Courier"&gt;System.Net&lt;/font&gt; namespace to gain access to the mail message object and email the new file to another process or possibly even FTP/copy it somewhere.&amp;#160; This is just a simple file transformation example to illustrate some advanced functionality and how to interact with the .Net framework using &lt;font face="Courier"&gt;System.IO&lt;/font&gt; and &lt;font face="Courier"&gt;System&lt;/font&gt;.&amp;#160; If you know any other .Net language, it works exactly the same in F# as in VB or C# from what I can tell so far.&amp;#160; &lt;/p&gt;&lt;p&gt;This project was one where things began to click for me inside of F#.&amp;#160; I knew the basics and seen examples through euler problems and such; however, seeing an example like this saw how easy and straight forward F# can make things.&lt;/p&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/03/how-i-learning-f-interacting-with-net.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'How I'm Learning F# - Interacting with the .Net Framework';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = 'The Third post in a series describing how I'm going about learning F#.';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt; &lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f03%2fhow-i-learning-f-interacting-with-net.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f03%2fhow-i-learning-f-interacting-with-net.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/How-Im-Learning-F-Interacting-with-the-Net-Framework"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Frandomactsofcoding.blogspot.com%2F2009%2F03%2Fhow-i-learning-f-interacting-with-net.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-234798705698259084?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/03/how-i-learning-f-interacting-with-net.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-1871805570157659341</guid><pubDate>Thu, 12 Mar 2009 17:26:00 +0000</pubDate><atom:updated>2009-03-12T12:34:24.084-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Automation</category><category domain="http://www.blogger.com/atom/ns#">Commentary</category><title>Tackling Anxiety Against Automation</title><description>&lt;p&gt;A few years ago, the company that I worked for was preparing to upgrade from MS Sql Server 2000 to Sql Server 2005.&amp;#160; While there wasn't too much abnormal concern about upgrading the databases themselves, there was a lot of concern about the large number of DTS packages that the company created for the majority of their B2B processes.&amp;#160; Their solution until they could come up and complete a test strategy to ensure the DTS packages would run under Sql 2005's DTS runtime, just incase the packages couldn't be converted to SSIS in some fashion, was to stop writing new DTS packages and push the processes into .Net console applications that would be scheduled through a batch processing system.&amp;#160; Personally, I liked this solution since it allowed me to write .net code in VS and not VBS code inside of the DTS Package designer in Enterprise Manager.&amp;#160; Actually abstracting out processes into a more reusable and testable state was a great benefit over VBS and DTS as a whole.&lt;/p&gt;  &lt;p&gt;One of the first console applications written under this initiative was to automate a series of manually ran Sql Scripts that people were running against production to accompany a file import process.&amp;#160; It was a pretty simple project and ran, still to my knowledge, bug free, even when tested by my QA team.&lt;/p&gt;  &lt;p&gt;Now fast forward to today.&amp;#160; The need for the process is still in place and the code hasn't been updated since no changes have been required; however, I found out that the application was only ran once in the past few years and then the person who used to manually go through the steps and scripts didn't want to automate it and has been doing the manual steps ever since.&amp;#160; Even today, this person has continued to manually spend a few hours every other day going through the same ceremony.&amp;#160; I think my brain gave me a BSOD from what I find highly illogical thinking.&lt;/p&gt;  &lt;p&gt;So I approached my coworker who has been doing this and start asking the number of &amp;quot;why&amp;quot; questions I had.&amp;#160; Here are some of the responses I was treated to:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&amp;quot;I don't trust what I cannot see or watch.&amp;quot;&lt;/li&gt;    &lt;li&gt;&amp;quot;I like being able to watch and correct where necessary.&amp;quot;&lt;/li&gt;    &lt;li&gt;&amp;quot;The process had a bug.&amp;quot;&lt;/li&gt;    &lt;li&gt;&amp;quot;I won't ever know when it breaks or succeeds.&amp;quot;&lt;/li&gt;    &lt;li&gt;&amp;quot;What else would I work on?&amp;quot;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;From the discussion around these themes, there are a few design and development themes that can/should be implemented when faced with such an anxious coworker.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Establishing Trust through Quality&lt;/h3&gt;  &lt;p&gt;While I see James Bach's point in his &lt;a title="Quality Is Dead by James Bach" href="http://www.satisfice.com/blog/archives/224" target="_blank"&gt;&amp;quot;Quality Is Dead&amp;quot; blog post&lt;/a&gt;, I disagree with the blanket of the statement.&amp;#160; There are always constraints when you're talking about software development (usually Time/deadlines being the largest constraint), it doesn't mean that every piece of code that you churn out will be of poor quality.&amp;#160; Practices such as TDD or just plain Unit Testing and reporting can be implemented in order to demonstrate and achieve a higher level of quality to someone who doubts quality.&amp;#160; Now, I believe that any developer can write code with and without unit tests and still achieve the same level of quality; however, it's easier to &lt;em&gt;validate&lt;/em&gt; that level of quality through unit tests and TDD practices.&amp;#160; This level of validation is essential to people who do not trust something to be automated.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Establishing Awareness through Instrumentation&lt;/h3&gt;  &lt;p&gt;The bulk of the other themes that I received surrounded the concept of being able to step through the process and watch/correct the data as necessary.&amp;#160; This is a nice thing for debugging; however, if an automated process has to be stepped through, then it's not automated.&amp;#160; One way to handle this issue is to ensure you have a high level of coverage of instrumentation in the code/process.&amp;#160; This means making sure the proper types of notification is provided, auditing is turned on to the degree needed, and any errors (be it bugs or bad data-related) are captured and reported appropriately.&amp;#160; I cannot confirm my coworker's claim that there was a bug in the code since I was unable to find one in the bug database.&amp;#160; If an email to capture the error existed, at the very least, I would begin having my own doubts about the quality of the code; however, even that was not found.&amp;#160; If instrumentation was implemented to a better degree than what I put into it for error logging and tracking, I would be able to verify the claim.&amp;#160; As far as bad-data and catastrophic scenarios (i.e. server loses network connection mid-process), those items can (and was) implemented through logging or some for of process auditing infrastructure.&amp;#160; The more data that can be provided, the more confidence the person will have when automated.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Establishing Automation Can Assist with Workload&lt;/h3&gt;  &lt;p&gt;The last theme that came from the conversation dealt with how the person's routine became.&amp;#160; This person was a very routine-oriented individual who knew exactly when to do when and how long it would take.&amp;#160; This person was a person of ceremony and possibly a bit fearful of being automated out of a job.&amp;#160; After being in the industry for a number of years, I have came to the conclusions that those nightmare stories of people being replaced by programs rarely happen to the developers or analysts that implement the program or automated process.&amp;#160; The automation allows for new, different tasks to be done.&amp;#160; Even if the automated process is kicked off manually, it still frees up time to do other things.&amp;#160; This means you can do more easily or in general transition onto the next big thing.&amp;#160; I do not really know any company out there that would say they have a truly shortage of work.&amp;#160; Even if it's wish-list, lowest priority, internal cost projects, there's always something to do. &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Summary &lt;/h3&gt;  &lt;p&gt;Automation is a beautiful thing that I have grown more and more fond with.&amp;#160; I have grown into a developer where I look for things to automation.&amp;#160; I have seen the themes I talked about here at a couple of different companies I've been with and people that I've talked with.&amp;#160; Each time, I find more and more ways to automate certain elements of a work day and also make the work flow easier.&amp;#160; Hopefully a few things here will help others as well.&amp;#160; Now if only I could find a way to automate my chores at home. :-)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/03/tackling-anxiety-against-automation.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'Tackling Anxiety Against Automation';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = 'An observation on strategies that can be used to promote automation to someone who has fears about such a hands off approach.';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f03%2ftackling-anxiety-against-automation.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f03%2ftackling-anxiety-against-automation.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Tackling-Anxiety-Against-Automation"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Frandomactsofcoding.blogspot.com%2F2009%2F03%2Ftackling-anxiety-against-automation.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-1871805570157659341?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/03/tackling-anxiety-against-automation.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-6793655536116061609</guid><pubDate>Fri, 13 Feb 2009 02:34:00 +0000</pubDate><atom:updated>2009-02-12T20:42:33.575-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">F#</category><title>How I'm Learning F# - Writing the First Application</title><description>&lt;p&gt;Over the past few months, I've been hearing more and more about the use of functional programming concepts and also languages like Haskell and F#.&amp;#160; While some of the initial musings that I've read revolved around how the concepts have been around for decades and that it makes financial and scientific applications easier to read and write, I couldn't find a good reason to start learning it for my typical line-of-business application design and development job or even some of my basic hobby projects.&amp;#160; Nonetheless, I kept getting drawn to the concept and have decided to focus on learning it.&lt;/p&gt;&lt;p&gt;This post marks the second entry of a series that I'll be writing to discuss how I'm going about learning F#.&amp;#160; While I'm not saying that my method of learning is ideal and should be followed by others, I'm just reporting how I'm going about doing it.&amp;#160; Over the course of this series, my goal is to provide other .Net developers a(nother) resource for learning the F# language as well as apply the language into some non-financial or scientific scenarios.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Series Table of Contents:&lt;/h3&gt;&lt;ol&gt;  &lt;li&gt;&lt;a title="How I&amp;#39;m Learning F# - Finding Resources" href="http://randomactsofcoding.blogspot.com/2009/02/how-i-learning-f-finding-resources.html" target="_blank"&gt;Finding Resources&lt;/a&gt; &lt;/li&gt;  &lt;li&gt;Writing the First Application &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;Downloadable Resources:&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;&lt;a title="Hello, World F# Visual Studio Project files." href="http://cid-3cb659da2d58facb.skydrive.live.com/self.aspx/Public/HelloWorldFSharp.zip" target="_blank"&gt;F# Hello, World Visual Studio 2008 Project&lt;/a&gt;&amp;#160;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Setting Up Visual Studio 2008 with F#:&lt;/h3&gt;&lt;p&gt;As of this writing, F# is at CTP status since September 2008 (v1.9.6.2).&amp;#160; For this example, and possibly for the remainder of the series, I'll be using this &lt;a title="Microsoft F#. September 2008 CTP" href="http://www.microsoft.com/downloads/details.aspx?FamilyID=61ad6924-93ad-48dc-8c67-60f7e7803d3c&amp;amp;displaylang=en" target="_blank"&gt;September 2008 CTP of Microsoft F#&lt;/a&gt;.&amp;#160; This CTP installer only works with Visual Studio 2008.&amp;#160; The CTP version does not work with Visual Studio 2005 (which previous versions did) nor the Visual Studio Express editions.&amp;#160; If you would like to use F# using Visual Studio 2005, please refer to &lt;a title="Stack Overflow question about F# and Visual Studio 2005" href="http://stackoverflow.com/questions/120715/setting-up-f-in-visual-studio-2005" target="_blank"&gt;this StackOverflow question about how to set up F# in Visual Studio 2005&lt;/a&gt; using an older version. NOTE: If you are using an older version of F# for use in Visual Studio 2005, I cannot guarantee that the examples presented in this series will work.&amp;#160; After you have downloaded and installed F# (either the CTP or a previous version), we are ready to begin writing our first F# application.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Writing the &amp;quot;Hello,World!&amp;quot;:&lt;/h3&gt;&lt;p&gt;Like many great computer books, this series will be starting with a simple example which we'll dissect afterwards.&amp;#160; In order to write the example, we'll need to start a new F# project in Visual Studio.&amp;#160; If we go to File &amp;gt; New Project..., we are treated to the following dialog window:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_RNnu2VM54fE/SZTcHuJTU6I/AAAAAAAAAEw/yUabifh523s/s1600-h/NewProjectDialog6.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="NewProjectDialog" src="http://lh4.ggpht.com/_RNnu2VM54fE/SZTcISzKscI/AAAAAAAAAE0/-R5EeGsu2ps/NewProjectDialog_thumb4.png?imgmax=800" width="582" height="391" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;The projects listed under Visual F# include a F# Application, a F# Library, and a F# Tutorial.&amp;#160; For the sake of this example, we'll be creating an F# Application named HelloWorldFSharp.&amp;#160; After clicking on the OK button, Visual Studio creates the new F# project containing a single Program.fs file.&amp;#160; &lt;/p&gt;&lt;p&gt;When the project is created, the Program.fs file contains a single line #light.&amp;#160; This tells the F# compiler to use the lightweight syntax of F# which removes some of the verbosity of the language and applies rules around white-space.&amp;#160; In the majority of examples on the Internet and books, the lightweight syntax is used and will be used going forward here as well.&lt;/p&gt;&lt;p&gt;Under the &lt;font face="Courier"&gt;#light&lt;/font&gt; line, add the following code snippet:&lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;let question = &amp;quot;How are you?&amp;quot; &lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;let sayHello name =     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;quot;Hello, &amp;quot; + name + &amp;quot;! &amp;quot; + question&lt;/font&gt;&lt;/p&gt;&lt;p&gt;In this code, we are doing two things.&amp;#160; First, we are declaring a variable named &lt;font face="Courier"&gt;question&lt;/font&gt;.&amp;#160; Second, we are declaring a method called &lt;font face="Courier"&gt;sayHello&lt;/font&gt; and takes a parameter called &lt;font face="COurier"&gt;name&lt;/font&gt;. The &lt;font face="Courier"&gt;sayHello&lt;/font&gt; method concatenates some strings together and returns the composed string. When using the &lt;font face="Courier"&gt;#light&lt;/font&gt; syntax, every indented line is considered part of the function or action with the last line being the return value.&lt;/p&gt;&lt;p&gt;One thing to mention about F# when compared to other languages is that variables are immutable.&amp;#160; Once a variable is declared (and given a value), that value can never change.&amp;#160; I believe there are some exceptions to this when interacting with object properties; however, at the core of the language, basic variables cannot be re-declared nor their values redefined after they have been initially declared. Because of this, many F# documents and tutorials will use &amp;quot;values&amp;quot; instead of &amp;quot;variables&amp;quot; to prevent the confusion.&amp;#160; I'll attempt to follow this pattern.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;One thing that a developer coming from VB.net or C# may notice is that there are no types defined here.&amp;#160; F# infers typing based on the value and how they are used.&amp;#160; If we wanted to declare a type for our &lt;font face="COurier"&gt;question&lt;/font&gt; and &lt;font face="Courier"&gt;name&lt;/font&gt; values, the code would like like the following:&lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;let (question : string) = &amp;quot;How are you?&amp;quot; &lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;let sayHello (name : string) =     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;quot;Hello, &amp;quot; + name + &amp;quot;! &amp;quot; + question&lt;/font&gt;&lt;/p&gt;&lt;p&gt;In F#, you can declare the type by using &lt;font face="COurier"&gt;(variablename : type)&lt;/font&gt; syntax.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;Now that we've seen how to declare a value and a method, we can output a value to a console window using the following line:&lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;printfn &amp;quot;%s &amp;quot; (sayHello &amp;quot;James&amp;quot;)&lt;/font&gt;&lt;/p&gt;&lt;p&gt;Here, we are using the &lt;font face="Courier"&gt;printfn&lt;/font&gt; method which prints formatted text to the console window.&amp;#160; The &lt;font face="Courier"&gt;%s&lt;/font&gt; is a placeholder for a string value which we are supplying by calling our &lt;font face="Courier"&gt;sayHello&lt;/font&gt; method passing in the name &lt;font face="COurier"&gt;&amp;quot;James&amp;quot;.&lt;/font&gt;&lt;font face="Trebuchet MS"&gt; In this example, we're treating the method like a value.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;Here is the full code of Program.fs.  &lt;br /&gt;&lt;/p&gt;&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: gray 1px solid; cursor: text; border-right: gray 1px solid; padding-top: 4px"&gt;  &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; #light&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt;&amp;#160; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt; let question = &amp;quot;How are you?&amp;quot;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;&amp;#160; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt; let sayHello name = &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;     &amp;quot;Hello, &amp;quot; + name + &amp;quot;! &amp;quot; + question&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;&amp;#160; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt; printfn &amp;quot;%s &amp;quot; (sayHello &amp;quot;James&amp;quot;)&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Running the Program using F# Interactive:&lt;/h3&gt;&lt;p&gt;At this point, we can either go the Build menu and build the project like many other console applications or we can use a feature unique to F# called the F# Interactive window.&amp;#160; F# Interactive (fsi.exe) allows you to run sections of your F# program as well as write ad-hoc F# statements.&amp;#160; To use F# Interactive from within Visual Studio, highlight the code you wish to run and press Alt+Enter.&amp;#160; A new Visual Studio panel opens for F# Interactive and reports information about the code (or the error it generates).&lt;/p&gt;&lt;p&gt;For example, if you were to highlight the line where we declare our value &lt;font face="Courier"&gt;question&lt;/font&gt; and press Alt+Enter, the following will appear:&lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;val question : string&lt;/font&gt;&lt;/p&gt;&lt;p&gt;What this line explains is that we have a value called &lt;font face="Courier"&gt;question&lt;/font&gt; that is of type &lt;font face="COurier"&gt;string&lt;/font&gt;. If we do the same to our &lt;font face="Courier"&gt;sayHello&lt;/font&gt; method, the following appears:&lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;val sayHello : string -&amp;gt; string&lt;/font&gt;&lt;/p&gt;&lt;p&gt;This line states that &lt;font face="Courier"&gt;sayHello&lt;/font&gt; is a value that accepts a parameter of type &lt;font face="Courier"&gt;string&lt;/font&gt; and returns (signified by the &lt;font face="Courier"&gt;-&amp;gt;&lt;/font&gt; ) a value of type &lt;font face="Courier"&gt;string&lt;/font&gt;.&amp;#160; If we highlight the all of the code we've written so far, we are shown the following:&lt;/p&gt;&lt;p&gt;&lt;font face="Courier"&gt;val question : string    &lt;br /&gt;val sayHello : string -&amp;gt; string    &lt;br /&gt;    &lt;br /&gt;Hello, James! How are you?&lt;/font&gt;&lt;/p&gt;&lt;p&gt;This shows us the same output as we had previously for &lt;font face="Courier"&gt;question&lt;/font&gt; and &lt;font face="Courier"&gt;sayHello&lt;/font&gt;.&amp;#160; In addition, it executes the last line and displays the output.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Conclusion:&lt;/h3&gt;&lt;p&gt;While this wasn't the largest demo nor the most unique, it is a simple step forward.&amp;#160; The premises of immutable variables (values) being declared and understanding the lightweight syntax are important to learning F#.&amp;#160; Over the next post of the series I'll be making some different applications in order to continue to explore F#'s syntax and it's power.&amp;#160; F# can do pretty much everything that VB.net or C# can do (with a few exceptions I'm now finding out) and hopefully the next posts will help us begin to find examples of where to apply it.&lt;/p&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/02/how-i-learning-f-writing-first.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'How I am learning F# - Writing the First Program';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = 'The second post of a series on how I'm learning the F# language.  In this post, I write the proverbial Hello, World! application and discuss a few core F# features.';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt; &lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f02%2fhow-i-learning-f-writing-first.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f02%2fhow-i-learning-f-writing-first.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/How-Im-learning-F-Writing-the-First-Program"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Frandomactsofcoding.blogspot.com%2F2009%2F02%2Fhow-i-learning-f-writing-first.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-6793655536116061609?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/02/how-i-learning-f-writing-first.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-2243282252114504197</guid><pubDate>Wed, 04 Feb 2009 13:00:00 +0000</pubDate><atom:updated>2009-02-04T07:32:21.027-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">F#</category><title>How I'm Learning F# - Finding Resources</title><description>&lt;p&gt;Over the past few months, I've been hearing more and more about the use of functional programming concepts and also languages like Haskell and F#.&amp;#160; While some of the initial musings that I've read revolved around how the concepts have been around for decades and that it makes financial and scientific applications easier to read and write, I couldn't find a good reason to start learning it for my typical line-of-business application design and development job or even some of my basic hobby projects.&amp;#160; Nonetheless, I kept getting drawn to the concept and have decided to focus on learning it.&lt;/p&gt;  &lt;p&gt;This post marks the beginning of a new series that I'll be writing to discuss how I'm going about learning F#.&amp;#160; While I'm not saying that my method of learning is ideal and should be followed by others, I'm just reporting how I'm going about doing it.&amp;#160; Over the course of this series, my goal is to provide other .Net developers a(nother) resource for learning the F# language as well as apply the language into some non-financial or scientific scenarios.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Series Table of Contents:&lt;/h3&gt;  &lt;ol&gt;   &lt;li&gt;Finding Resources&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Where To Start:&lt;/h3&gt;  &lt;p&gt;One of the challenges of learning anything is to find where to start gathering the necessary information on the subject matter.&amp;#160; Thankfully, there's already a great number of sources that can be used to learn F#.&amp;#160; Here are some that I've been using to get started in F#:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a title="F# on StackOverflow" target="_blank" href="http://stackoverflow.com/questions/tagged/f%23"&gt;StackOverflow.com's F# tagged Questions&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a title="Foundations of F# on Amazon.com" target="_blank" href="http://www.amazon.com/Foundations-F-Experts-Voice-Net/dp/1590597575/ref=pd_bbs_sr_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1233281713&amp;amp;sr=8-1"&gt;Foundations of F#&lt;/a&gt; by Robert Pickering&lt;/li&gt;    &lt;li&gt;&lt;a title="Expert F# on Amazon.com" target="_blank" href="http://www.amazon.com/Expert-F-Experts-Voice-Net/dp/1590598504/ref=pd_bbs_sr_2?ie=UTF8&amp;amp;s=books&amp;amp;qid=1233281713&amp;amp;sr=8-2"&gt;Expert F#&lt;/a&gt; by Don Syme, Adam Granicz, and Antonio Cisternino&lt;/li&gt;    &lt;li&gt;&lt;a target="_blank" href="http://msdn.microsoft.com/en-us/fsharp/default.aspx"&gt;MSDN F# Developer's Portal&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Of these 4 resources, I've so far leaned on StackOverflow and Expert F# the most.&amp;#160; I have examined only a little bit of the MSDN site and have been using it if I cannot find my answer on StackOverflow.&amp;#160; I initially began reading Foundations of F#; however, I was having a hard time building on each chapter.&amp;#160; Expert F# flows a lot better and also build on each previous chapter which makes it ideal for learning.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Why am I learning F#:&lt;/h3&gt;  &lt;p&gt;I'm learning F# in order to broaden my skill set into functional programming.&amp;#160; Initially, there wasn't any other reason for that.&amp;#160; I looked at OCaml, Haskell, and F# as all possibilities and eventually settled on F#.&amp;#160; Since then, I have began seeking a better reason for learning F#.&amp;#160; Many of reasons presented in interviews and blogs and books talked about it's use in financial and scientific fields of study.&amp;#160; While this is fine, I was still looking for more since I, like many other developers, am not in those fields of application development often.&amp;#160; After diving deeper, I found that F# is a very concise language that allows developers to write some code faster and in a more logical way.&amp;#160; Where as there is a large amount of code used to write a program in OO for the sake of being OO, F# allows a very simple and straight forward syntax to write programs or pieces of .Net applications in a functional manner.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;What F# can do:&lt;/h3&gt;  &lt;p&gt;One other thing that I was fooling myself with once I began learning F# was this idea that it could or couldn't do something that a different .Net language could.&amp;#160; It wasn't until I began reading Expert F# that I truly understood how narrow minded I was being.&amp;#160; In Expert F#, the authors do a fantastic job at illustrating not only the language in a general sense, but also how to apply F# as a replacement to VB.net or C# in applications like ASP.Net, Winforms, and even Domain Specific Languages.&amp;#160; While, from what I can tell, many people agree that replacing C# or VB.net with F# in the ASP.Net realm isn't the best or most recommended application for the language, it does illustrate the point that F# can do anything that C# or VB.Net can do today.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Where does F# fit:&lt;/h3&gt;  &lt;p&gt;I have a feeling that I may be skewered a bit for this; however, this is just my perception as a novice F# developer at this point.&amp;#160; I've been developing in Microsoft technologies for years now and have also done work in other languages.&amp;#160; Where I see F# fits is where you have functional steps of processing of data.&amp;#160; I can see F# being a great language for writing the data engines for custom ETL applications and processes, as well as similar business logic processors.&amp;#160; I am certain I'll find additional locations that would assist me in my daily development job as I learn more of F#.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;What's Next:&lt;/h3&gt;  &lt;p&gt;Next up in the series we'll dive into setting up VS2008 with the F# CTP and write the ever so popular &amp;quot;Hello, World!&amp;quot; or something like that :-).&amp;#160; Until then, I highly recommend checking out the F# resources mentioned above and also read a lot of the questions currently out there on Stack Overflow. &lt;/p&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/02/how-i-learning-f-finding-resources.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'How I'm Learning F# - Finding Resouces';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = 'This post begins a new series I'll be doing about how I'm going about learning the F# functional language.  In this section, I begin to identify resources that I'll be using on my learning adventure.';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt; &lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f02%2fhow-i-learning-f-finding-resources.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f02%2fhow-i-learning-f-finding-resources.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Random-Acts-of-Coding-How-Im-Learning-F-Finding-Resources"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Frandomactsofcoding.blogspot.com%2F2009%2F02%2Fhow-i-learning-f-finding-resources.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-2243282252114504197?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/02/how-i-learning-f-finding-resources.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-5804831415120896592</guid><pubDate>Wed, 28 Jan 2009 12:00:00 +0000</pubDate><atom:updated>2009-01-28T07:25:36.016-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Nant</category><category domain="http://www.blogger.com/atom/ns#">Resources</category><title>Saving Time Through the Command Prompt Explorer Bar</title><description>&lt;p&gt;In the last couple of posts, I have been mentioning different command line tools that I've been using (specifically Nant and SchemaSpy).&amp;#160; While some people love command line applications and using the command prompt, there are some that cherish the nice Windows GUI and the mouse.&amp;#160; The issue with the GUI is that applications like Nant and SchemaSpy don't really work well out of the box if you double click on them.&amp;#160; This means that in order to have double click functionality that does something, you will need to script it out using tools like shell or PowerShell scripting that executes the configured command for the desired results.&amp;#160; If you don't create (and subsequently debug) the script wrapper, you will find yourself opening up the command prompt, navigating to the directory, and then typing in the command manually.&amp;#160; Thankfully, there's a tool out there that makes things easier.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;The Command Prompt Explorer Bar&lt;/h3&gt;&lt;p&gt;The Command Prompt Explorer Bar is an open source tool on the Code Project web site developed by Pavel Zolnikov that allows you to place a command prompt window inside of your windows explorer window (see image below).&amp;#160; While this immediately doesn't sound useful, it offers some powerful productivity features that a typical command window doesn't.&amp;#160; First, when you open the Command Prompt Explorer Bar, it immediately takes you to the directory you're in.&amp;#160; So, if you are in the directory that contains the Nant script you want to manually execute, you can open the command prompt and immediately type in your command.&amp;#160; In addition, as you move around windows in the explorer window, your command prompt automatically synchronizes with it.&amp;#160; Last but not least, the Command Prompt Explorer Bar offers the ability to have macros.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_RNnu2VM54fE/SXYPB-RRXjI/AAAAAAAAAEQ/L-d00goDW2E/s1600-h/CPEBScreenShot3.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="Command Prompt Explorer Bar Screen Shot on Windows Vista" src="http://lh6.ggpht.com/_RNnu2VM54fE/SXYPCizFVYI/AAAAAAAAAEU/QgtUUVIAj2Y/CPEBScreenShot_thumb1.png?imgmax=800" width="644" height="484" /&gt;&lt;/a&gt;   &lt;br /&gt;&lt;font size="1"&gt;&lt;strong&gt;Figure 1:&lt;/strong&gt; The Command Prompt Explorer Bar for a user's (named llama in this case) home folder.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Where to Download the Command Prompt Explorer Bar&lt;/h3&gt;&lt;p&gt;As stated previously, the Command Prompt Explorer Bar is an open source tool on the Code Project web site.&amp;#160; You can download the installation binaries and/or the source code from &lt;a title="Click Here to Download the Command Prompt Explorer Bar" target="_blank" href="http://www.codeproject.com/KB/cs/commandbar.aspx"&gt;this location.&lt;/a&gt; After you have downloaded the installer for it, you will be able to begin using it.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;How Do I Open it?&lt;/h3&gt;&lt;p&gt;The Command Prompt Explorer Bar is very simple to use since it's just an embedded command prompt at it's core.&amp;#160; It works in both XP and Vista and there's no special window style needed to have it open (folder bar is supported as is Vista's Aero interface). There are two ways to open the Command Prompt Explorer Bar.&amp;#160; First, you can go to the View Menu &amp;gt; Explorer Bar &amp;gt; Command Prompt menu option.&amp;#160; The second way is to just press Ctrl+M in the folder.&amp;#160; &lt;strong&gt;&lt;u&gt;NOTE&lt;/u&gt;&lt;/strong&gt;: Ctrl+M does not work if you are literally on your windows desktop, a file system/explorer window must be open for the Command Prompt Explorer Bar to open.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;What Are Those Icons For?&lt;/h3&gt;&lt;p&gt;As you may have noticed from the above image or if you've installed the Command Prompt Explorer Bar already, there are a series of buttons/icons on the left sidebar.&amp;#160; These buttons help provide some quick additional functionality.&amp;#160; Going from top to bottom, the buttons are as follows:&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;&lt;strong&gt;Command Menu&lt;/strong&gt; - Provides the command prompt context menu, similar to right clicking inside of the prompt.&amp;#160; Clicking directly on the button shows an &amp;quot;About&amp;quot; dialog. &lt;/li&gt;  &lt;li&gt;&lt;strong&gt;Synchronize&lt;/strong&gt; - Turns on and off the ability for the command prompt to synchronize as you move through folders above it. &lt;/li&gt;  &lt;li&gt;&lt;strong&gt;CLS&lt;/strong&gt; - Sends the CLS command to the command prompt; clearing the screen. &lt;/li&gt;  &lt;li&gt;&lt;strong&gt;Get Selected Folder Items &lt;/strong&gt;- Enters all items you have selected in the folder view above in a &amp;lt;space&amp;gt; separated list. &lt;/li&gt;  &lt;li&gt;&lt;strong&gt;Enter Key&lt;/strong&gt; - For those who don't like to press the enter key on the keyboard...I think. &lt;/li&gt;  &lt;li&gt;&lt;strong&gt;Esc Key&lt;/strong&gt; - Used to clear a partially typed line; same as the Escape Key on the keyboard. &lt;/li&gt;  &lt;li&gt;&lt;strong&gt;Macro &lt;/strong&gt;- A drop down menu containing a list commands that you can use for quick access. (more on this in the next section) &lt;/li&gt;  &lt;li&gt;&lt;strong&gt;Grow&lt;/strong&gt; - Grows the constraints of the Command Prompt Explorer Bar. &lt;/li&gt;  &lt;li&gt;&lt;strong&gt;Shrink&lt;/strong&gt; - Shrinks the constraints of the Command Prompt Explorer Bar. &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Using Macros&lt;/h3&gt;&lt;p&gt;When the Command Prompt Explorer Bar was created, Pavel Zolnikov entered in the ability to create and use macros.&amp;#160; The macros that he supplied with it were very much .Net Command Prompt tools.&amp;#160; Browsing the list, you'll find a number of macros for generating a type library, register a COM compliant assembly, and registering an assembly in the GAC.&amp;#160; There are also some macros for traditional command prompt commands like attrib and cd.&amp;#160; There is also a few macros that contain a {1} in their name.&amp;#160; What this syntax represents is the first selected item in folder list above.&amp;#160; For example, if you highlight a folder and then call the &amp;quot;cd {1}&amp;quot; macro, it executes the change directory command into the selected folder in the command prompt.&amp;#160; It does not sync back to the folder view however.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Adding New Macros&lt;/h3&gt;&lt;p&gt;While the default macros are useful, Pavel also provided us the ability to create our own macros.&amp;#160; This is where it shines.&amp;#160; To create a new macro, Click on the Macro menu button directly.&amp;#160; This will open the C:\Program Files\Command Prompt Explorer Bar\macro.xml file.&amp;#160; Inside of this file you'll see some very basic XML syntax which is described below.&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;&amp;lt;group&amp;gt; - The document element as well as elements that denote a grouping/submenu list of macros     &lt;ul&gt;      &lt;li&gt;text - Sets the text to be shown as the submenu item. &lt;/li&gt;    &lt;/ul&gt;  &lt;/li&gt;  &lt;li&gt;&amp;lt;macro&amp;gt; - Denotes a macro-ed command.     &lt;ul&gt;      &lt;li&gt;text - Sets the menu text to be shown for the macro &lt;/li&gt;      &lt;li&gt;execute - a boolean value telling the command prompt to execute the macro when selected or not. &lt;/li&gt;      &lt;li&gt;command - the command the macro will execute upon selected if different than the text.(optional) &lt;/li&gt;    &lt;/ul&gt;  &lt;/li&gt;  &lt;li&gt;{0} - types out all currently selected files in the folder view &lt;/li&gt;  &lt;li&gt;{1} - types out the first selected file in the folder view (subsequent numbers represent that element of selected items; i.e. {2} is the 2nd selected item). &lt;/li&gt;  &lt;li&gt;{1:n'} - types out the last selected file in the folder view (n' represents the inverse order of the files selected) &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Now that we've looked at the syntax, let's add a new macro group with a Nant command.&amp;#160; This will assume that you have Nant installed and configured with the Nant.bat file in your system path as described by the Nant installation and configuration steps.&lt;/p&gt;&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; max-height: 200px; font-size: 8pt; overflow: auto; border-top: gray 1px solid; cursor: text; border-right: gray 1px solid; padding-top: 4px"&gt;  &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;group&lt;/span&gt; &lt;span style="color: #ff0000"&gt;text&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;Nant&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;macro&lt;/span&gt; &lt;span style="color: #ff0000"&gt;text&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;completeBuild {1}&amp;quot;&lt;/span&gt; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;            &lt;span style="color: #ff0000"&gt;execute&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;true&amp;quot;&lt;/span&gt; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;            &lt;span style="color: #ff0000"&gt;command&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;Nant -buildfile:{1} completeBuild&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;group&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;Adding this snippet to the file (inside of the parent &amp;lt;group&amp;gt; xml document element), the new macro group and command is instantly added to the macro menu (no close and reopen needed).&amp;#160; This command allows us to select our build file in the folder view and then executes the macro to call it's &amp;quot;completeBuild&amp;quot; task that it presumably contains.&amp;#160; Quick and easy for executing command line tools and applications without having to navigate and type in the command in a command prompt nor mess with scripted wrappers.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;In Summary&lt;/h3&gt;&lt;p&gt;While this tool isn't the most amazing one out there, it is very useful if you find yourself working in a command prompt a lot.&amp;#160; Great tools and utilities like Nant and SchemaSpy can be easily reduced to a simple click of a macro while you never have to leave the window you are browsing the file system with.&lt;/p&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/01/saving-time-through-command-prompt.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'Saving Time Through the Command Prompt Explorer Bar';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = 'A brief tutorial of using the Command Prompt Explorer Bar to assist in command line tools and operations from with in Windows Explorer.';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt; &lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f01%2fsaving-time-through-command-prompt.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f01%2fsaving-time-through-command-prompt.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Saving-Time-Through-the-Command-Prompt-Explorer-Bar"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Frandomactsofcoding.blogspot.com%2F2009%2F01%2Fsaving-time-through-command-prompt.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-5804831415120896592?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/01/saving-time-through-command-prompt.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-3959650811427807195</guid><pubDate>Wed, 21 Jan 2009 12:56:00 +0000</pubDate><atom:updated>2009-01-21T07:04:22.333-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Resources</category><title>Database Documentation using SchemaSpy</title><description>&lt;p&gt;One of the largest challenges that developers and software project managers have a difficult time with is how to keep documentation in sync with the code elements.&amp;#160; While there are a large amount of tools that allows for documentation to be created based on code comments (i.e. &lt;a title="nDoc" target="_blank" href="http://ndoc.sourceforge.net/"&gt;nDoc&lt;/a&gt;, &lt;a title="JavaDoc" target="_blank" href="http://java.sun.com/j2se/javadoc/"&gt;JavaDoc&lt;/a&gt;, &lt;a title="Sandcastle" target="_blank" href="http://blogs.msdn.com/sandcastle/default.aspx"&gt;SandCastle&lt;/a&gt;, etc.), there are not a lot of tools that do the same for Databases.&amp;#160; Now, there are tools that will document a database after the fact (or will create the database based on the documentation you're creating), many are very expensive or appear to be no longer support.&amp;#160; One tool that I have started using recently for database documentation was recommended in the book &lt;u&gt;&lt;/u&gt;&lt;a title="The Productive Programmer by Neal Ford via Amazon.com" target="_blank" href="http://www.amazon.com/Productive-Programmer-Theory-Practice-OReilly/dp/0596519788/ref=pd_bbs_sr_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1231381048&amp;amp;sr=8-1"&gt;The Productive Programmer by Neal Ford&lt;/a&gt;.&amp;#160; The tool is called &lt;a title="SchemaSpy" target="_blank" href="http://schemaspy.sourceforge.net/"&gt;SchemaSpy&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;For the sake of brevity, this post will cover how to generate database documentation for only Microsoft SqlServer 2000 and 2005 databases using SchemaSpy.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;What is SchemaSpy?&lt;/h3&gt;  &lt;p&gt;SchemaSpy is a Java command-line application that will connect to your database and generate information about the tables and their relationship.&amp;#160; SchemaSpy does does not address any database programming elements (i.e. Functions, Triggers, Stored Procedures, etc.); however, supplies a large amount of information on the tables and views themselves along with their relationships.&amp;#160; It also evaluates your indexes and keys in order to build relational diagrams.&amp;#160; Furthermore, it retrieves information from the database tables in order to give you a view of the number of records, the types of columns, and a large amount of other information for it.&amp;#160; In addition to large amount of information, it also provides notification if there are any anomalies in the schema; such as implied relationships between columns (no foreign key constraints), tables without indexes, columns marked as both &amp;quot;null&amp;quot; and &amp;quot;must be unique&amp;quot;, single column tables, and more.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;What does SchemaSpy Produce?&lt;/h3&gt;  &lt;p&gt;Below are a few screen shots of the documentation that SchemaSpy creates for the Northwind database.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_RNnu2VM54fE/SWoyHxFMqkI/AAAAAAAAAEA/xbUdGYVILOE/s1600-h/IndexImage%5B4%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; border-top: 0px; border-right: 0px" border="0" alt="The Index page for the documentation SchemaSpy produces." src="http://lh3.ggpht.com/_RNnu2VM54fE/SWoyIrwe88I/AAAAAAAAAEE/krZNWVnmZOk/IndexImage_thumb%5B2%5D.png?imgmax=800" width="496" height="361" /&gt;&lt;/a&gt;&amp;#160; &lt;br /&gt;&lt;font size="1"&gt;&lt;strong&gt;Figure 1:&lt;/strong&gt; SchemaSpy's Index page for the Northwind Database.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_RNnu2VM54fE/SWoyJd2yOeI/AAAAAAAAAEI/DeUtsdhiyTo/s1600-h/ImpliedRelationships%5B4%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; border-top: 0px; border-right: 0px" border="0" alt="An example of the relational diagrams produced by SchemaSpy" src="http://lh6.ggpht.com/_RNnu2VM54fE/SWoyKNRjtHI/AAAAAAAAAEM/5JylyUB0eIY/ImpliedRelationships_thumb%5B2%5D.png?imgmax=800" width="493" height="358" /&gt;&lt;/a&gt;     &lt;br /&gt;&lt;font size="1"&gt;&lt;strong&gt;Figure 2:&lt;/strong&gt; An example of the the diagramed relationships SchemaSpy produces&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;What do I need to start using SchemaSpy?&lt;/h3&gt;  &lt;p&gt;SchemaSpy requires 4 separate components to be installed in order to work properly:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The SchemaSpy application itself (version 4.1.1 as of this post) - &lt;a title="SchemaSpy" target="_blank" href="http://schemaspy.sourceforge.net/"&gt;Download&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;The Graphviz Diagram Engine - &lt;a title="Graphviz Diagraming Engine" target="_blank" href="http://www.graphviz.org/"&gt;Download&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;Java Runtime Environment (v1.5 or higher)&amp;#160; - &lt;a title="Java.Com" target="_blank" href="http://java.com/en/"&gt;Download&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;The Database Driver(s) required for a Java Application to connect to your database.      &lt;ul&gt;       &lt;li&gt;MS SqlServer 2000 / 2005 - JTDS v1.2 - &lt;a title="JTDS Java database driver version 1.2" target="_blank" href="http://sourceforge.net/project/downloading.php?group_id=33291&amp;amp;use_mirror=voxel&amp;amp;filename=jtds-1.2-dist.zip&amp;amp;95629663"&gt;Download&lt;/a&gt; &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Once the 4 components are downloaded and the JRE and Graphviz are installed, the next thing we have to do is install/configure the JTDS drivers (more on why JTDS instead of traditional JDBC in a moment).&amp;#160; As of this post, SchemaSpy only works with the 1.2 version of the JTDS driver and requires the jtds-1.2.jar file to be in the C:\Program Files\Java\Shared\jtds directory.&amp;#160; The driver jar file can be stored in other directories; however, an additional command parameter has to be passed to SchemaSpy if you do (see below).&amp;#160; At this point, the only thing that's left is to execute SchemaSpy with the proper command line arguments.&amp;#160; &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Running SchemaSpy&lt;/h3&gt;  &lt;p&gt;After all of the above components are installed, you are able to execute SchemaSpy from a command prompt using the following (general) syntax:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Courier"&gt;java -jar SchemaSpy_4.1.1.jar -t &lt;em&gt;databaseType &lt;/em&gt;-host &lt;em&gt;serverName &lt;/em&gt;-port &lt;em&gt;portNumber &lt;/em&gt;-db &lt;em&gt;dbName&lt;/em&gt; -u &lt;em&gt;userName&lt;/em&gt; -p &lt;em&gt;password&lt;/em&gt; -s &lt;em&gt;schemaName&lt;/em&gt; -o &lt;em&gt;outputDirectory&lt;/em&gt;&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Let's dissect these command parameters a bit:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;-t&lt;/strong&gt;&amp;#160; : This identifies the type of the database we're using.&amp;#160; Since this post is focusing on MS SqlServer using the JTDS driver, the database type will be either mssql-jtds (for SqlServer 2000) or mssql05-jtds (for SqlServer 2005). &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;-host&lt;/strong&gt;&amp;#160; :&amp;#160; This is required by our type.&amp;#160; It signifies what database server to connect to. &lt;/li&gt;    &lt;li&gt;-&lt;strong&gt;port&lt;/strong&gt;&amp;#160; :&amp;#160; This is required by our type.&amp;#160; This signifies what port to connect to the database.&amp;#160; &lt;u&gt;&lt;em&gt;This will not always be 1433 (see below).&lt;/em&gt;&lt;/u&gt; &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;-db&lt;/strong&gt;&amp;#160; :&amp;#160; This tells SchemaSpy what database to diagram for us. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;-u&lt;/strong&gt;&amp;#160; : This tells SchemaSpy the database user name to login with. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;-p&lt;/strong&gt;&amp;#160; : This tells SchemaSpy the database user's password to login with. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;-s&lt;/strong&gt;&amp;#160; : This tells SchemaSpy what schema to read and diagram.&amp;#160; The user credentials provided must have access to at least read this schema. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;-o&lt;/strong&gt;&amp;#160; : This tells SchemaSpy the output directory to generate the documentation. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;-dp&lt;/strong&gt;&amp;#160; : This tells SchemaSpy the path to locate the database driver file (not used in this example) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;An example of a fully completed command:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Courier"&gt;java -jar SchemaSpy_4.1.1.jar -t mssql-jtds -host myDBServer -port 1433 -db Northwind -u myDbUser -p password -s dbo -o NorthwindDocumentation&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;If your projects use Sql Server's integration authentication option, you can use the &lt;strong&gt;-sso&lt;/strong&gt; option.&amp;#160; The -sso option allows you to remove both the username (-u) and password (-p) parameters and use the identity of the account used to called the Java Runtime Environment.&amp;#160; Modifying the example above to use integrated authentication, we get the following:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Courier"&gt;java -jar SchemaSpy_4.1.1.jar -t mssql-jtds -host myDBServer -port 1433 -bb Northwind -sso -s dbo -o NorthwindDocumentation&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Why JTDS instead of the JDBC drivers?&lt;/h3&gt;  &lt;p&gt;As I mentioned above, I recommend using the JTDS Java Database drivers instead of the traditional JDBC drivers that Microsoft offers off of their web site.&amp;#160; While the fact that JTDS is a single driver as opposed to the 2 separate JDBC drivers is a plus, the main reason is the trouble I had getting the JDBC drivers to work with SqlServer 2005 databases.&amp;#160; If I was working on documenting a database I'm creating for a project on my local system using SQL Server 2005 Express Edition, it would always give me an error stating that the &amp;quot;variant&amp;quot; data type is not supported.&amp;#160; After a lot of research and trial and error, the only result I could only get this working by using the JTDS driver. &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;How to use SchemaSpy to Diagram a Named Instance&lt;/h3&gt;  &lt;p&gt;When installing Microsoft Sql Server, you have the option of installing it as a stand alone service or a named instance.&amp;#160; In the event of a named instance, you would normally connect to it in your .Net code (or via Management Studio/Query Analyzer) as ServerName\InstanceName.&amp;#160; For example, the default instance of a Sql Server 2005 Express Edition is localhost\SQLExpress.&amp;#160; In order to connect to a named instance database with SchemaSpy, you do not need the Instance Name of the database (just the server name as if it wasn't an instance), and you have to use the database's TCP Dynamic Port instead of the typical 1433.&lt;/p&gt;  &lt;p&gt;You can locate a named instance's dynamic port through the following steps:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Open the Sql Server Configuration Manager application (either through the Programs Menu or a MMC Snap In) &lt;/li&gt;    &lt;li&gt;Expand the Sql Server 2005 Network Configuration element &lt;/li&gt;    &lt;li&gt;Click on the Protocols for &amp;quot;INSTANCE&amp;quot; where &amp;quot;INSTANCE&amp;quot; is the name of your named instance &lt;/li&gt;    &lt;li&gt;In the right pane, double click on TCP/IP &lt;/li&gt;    &lt;li&gt;In the TCP/IP Properties dialog that appears, click on the IP Addresses tab. &lt;/li&gt;    &lt;li&gt;Towards the bottom of the IP Addresses tab, you'll find the TCP Dynamic Ports value to use for SchemaSpy &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;The above steps were taken based on a local installation of SQL Server 2005 Express Edition.&amp;#160; Your steps may vary depending upon configuration.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Conclusion&lt;/h3&gt;  &lt;p&gt;SchemaSpy is a tool that I have been using to help with some of the documentation pains that I have experienced on some of my personal and professional projects.&amp;#160; Being able to add the command into a build script to automatically keep the documentation up to date is a huge time saver and is invaluable as people migrate onto the project(s).&amp;#160; I hope you find it as useful as I have, and to assist further, I have added a simple step by step guide to setting up and begin using SchemaSpy below.&amp;#160; &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;The Step-By-Step&lt;/h3&gt;  &lt;ol&gt;   &lt;li&gt;Install the Java Runtime Environment version 1.5 or higher if it is not already installed. &lt;/li&gt;    &lt;li&gt;Install Graphviz Diagramming Engine. &lt;/li&gt;    &lt;li&gt;Download the SchemaSpy jar file. &lt;/li&gt;    &lt;li&gt;Download the JTDS v1.2 driver and place the jar file in the C:\Program Files\Java\Shared\JTDS directory. &lt;/li&gt;    &lt;li&gt;Obtain User Login Credentials with the proper permissions to read the schema for the database you will be documenting if integrated authentication is not available. &lt;/li&gt;    &lt;li&gt;Obtain the TCP Dynamic Port if the database you are accessing is a named instance. &lt;/li&gt;    &lt;li&gt;Open a command window and navigate to the location of the SchemaSpy jar file. &lt;/li&gt;    &lt;li&gt;Execute the SchemaSpy jar file using the proper command line parameters. &lt;/li&gt; &lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/01/database-documentation-using-schemaspy.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'Database Documentation using SchemaSpy';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = 'A blog post that provides a tutorial on how to use SchemaSpy to document Microsoft Sql Server 2000 and 2005 databases.';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt; &lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f01%2fdatabase-documentation-using-schemaspy.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f01%2fdatabase-documentation-using-schemaspy.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt; &lt;a rev="vote-for" href="http://dotnetshoutout.com/Database-Documentation-using-SchemaSpy"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Frandomactsofcoding.blogspot.com%2F2009%2F01%2Fdatabase-documentation-using-schemaspy.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-3959650811427807195?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/01/database-documentation-using-schemaspy.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">11</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-198387417690784771</guid><pubDate>Wed, 14 Jan 2009 14:00:00 +0000</pubDate><atom:updated>2009-01-14T08:58:51.482-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">JavaScript</category><category domain="http://www.blogger.com/atom/ns#">jQuery</category><title>Filtering Table Results with jQuery</title><description>&lt;p&gt;A few weeks ago, I was looking for a way to filter records in a table.&amp;#160; The screen that I was going to use this one was a composite/advanced search screen to where after the results are populated, the user can continue typing in search results into other fields and it would auto-filter.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;There are a large amount of jQuery plug-ins that offer table filtering features.&amp;#160; I reviewed the TableSorter plug-in; however, I didn't want a filtering system where 1 text box would filter all columns.&amp;#160; That plug-in works extremely well and I am using it in other areas, but I'm looking for a text box-to-column filtering mechanism instead. &lt;a title="Bill Beckelmen&amp;#39;s  Blog" target="_blank" href="http://beckelman.net/"&gt;Bill Beckelmen&lt;/a&gt;, who has a lot of great posts and examples on the TableSoter plug-in, suggested trying the &lt;a href="http://www.tomcoote.co.uk/jQueryColumnFilters.aspx"&gt;jQuery Column Filter&lt;/a&gt; or &lt;a href="http://ideamill.synaptrixgroup.com/jquery/tablefilter/tabletest.htm"&gt;tablefilter&lt;/a&gt; plug-ins.&amp;#160; Both were better; however, also auto-created the text boxes in another header row for the table.&amp;#160; After looking a bit more, I came to the conclusion that I would need to write my own functionality.&amp;#160; If I continue working on refining this code, I will probably see about turning it into a plug-in for easier use.&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;Post Downloads:&lt;/h3&gt;&lt;p&gt;&lt;a title="Example HTML Code that demonstrates the topic." target="_blank" href="http://cid-3cb659da2d58facb.skydrive.live.com/self.aspx/Public/TableFilter.zip"&gt;Table Filtering with jQuery Example - TableFilter.zip&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;h3&gt;The &lt;font face="Courier"&gt;filterColumn&lt;/font&gt; Function:&lt;/h3&gt;&lt;p&gt;At the heart of the filtering process is a JavaScript function called &lt;font face="Courier"&gt;filterColumn&lt;/font&gt;.&amp;#160; This function takes 2 parameters.&amp;#160; The first parameter takes the text name of the table column that is being evaluated.&amp;#160; The second parameter is the text value to filter on.&amp;#160; For the sake of the example, the &lt;font face="Courier"&gt;filterColumn&lt;/font&gt; function will be bound to each text box's &lt;font face="Courier"&gt;onKeyUp&lt;/font&gt; event; passing it's current value for the filtering text.&lt;/p&gt;&lt;p&gt;Inside of the &lt;font face="Courier"&gt;filterColumn&lt;/font&gt; function, 3 things occur to make the filtering mechanism work.&amp;#160; First, the two input parameters are inserted into regular expression patterns that will be used to locate the table column header as well as the records in that column once found.&amp;#160; The second thing it does is loop through the column header (first table row in the &lt;font face="Courier"&gt;thead&lt;/font&gt; tag that contains &lt;font face="Courier"&gt;th&lt;/font&gt; tags...or &lt;font face="Courier"&gt;&amp;quot;#resultsTable thead tr:first th&amp;quot;&lt;/font&gt; in jQuery selector syntax) to locate the column's index.&amp;#160; Lastly, it loop through the table's records using the column's index and sets the row's &lt;font face="Courier"&gt;display&lt;/font&gt; style to &lt;font face="Courier"&gt;&amp;quot;none&amp;quot;&lt;/font&gt; if it doesn't match the filtering criteria.&lt;/p&gt;&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; height: 238px; max-height: 200px; font-size: 8pt; overflow: auto; border-top: gray 1px solid; cursor: text; border-right: gray 1px solid; padding-top: 4px"&gt;  &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;function&lt;/span&gt; filterColumn(columnHeader, value){&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt;&amp;#160; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;     &lt;span style="color: #008000"&gt;// set regex objects with the appropriate patterns.&lt;/span&gt;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; headerPattern = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; RegExp(&lt;span style="color: #006080"&gt;'^'&lt;/span&gt; + columnHeader + &lt;span style="color: #006080"&gt;'$'&lt;/span&gt;, &lt;span style="color: #006080"&gt;'i'&lt;/span&gt;);&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; filterPattern = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; RegExp(&lt;span style="color: #006080"&gt;'^'&lt;/span&gt; + value + &lt;span style="color: #006080"&gt;''&lt;/span&gt;, &lt;span style="color: #006080"&gt;'i'&lt;/span&gt;);&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;&amp;#160; &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;     &lt;span style="color: #008000"&gt;// initialize the column identifier&lt;/span&gt;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; colIndex = -1;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;     &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;     &lt;span style="color: #008000"&gt;// loop through the header's first row of cells&lt;/span&gt;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; headerRow = $(&lt;span style="color: #006080"&gt;&amp;quot;#resultsTable thead tr:first th&amp;quot;&lt;/span&gt;);&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  12:&lt;/span&gt;     headerRow.each(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt;(n){&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  13:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (headerPattern.test($.trim(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.innerHTML))){&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  14:&lt;/span&gt;             colIndex = n;        &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  15:&lt;/span&gt;         }    &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  16:&lt;/span&gt;     });&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  17:&lt;/span&gt;     &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  18:&lt;/span&gt;     &lt;span style="color: #008000"&gt;// check to see if the column was found.&lt;/span&gt;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  19:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (colIndex &amp;gt; -1){&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  20:&lt;/span&gt;         &lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  21:&lt;/span&gt;         &lt;span style="color: #008000"&gt;// loop through each table body row and evaulate the proper cell.&lt;/span&gt;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  22:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; bodyRows = $(&lt;span style="color: #006080"&gt;&amp;quot;#resultsTable tbody tr&amp;quot;&lt;/span&gt;);&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  23:&lt;/span&gt;         bodyRows.each(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt;(n){&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  24:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(!filterPattern.test($.trim(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.childNodes[colIndex].innerHTML))){&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  25:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.style.display = &lt;span style="color: #006080"&gt;'none'&lt;/span&gt;;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  26:&lt;/span&gt;             }&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  27:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;else&lt;/span&gt; {&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  28:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.style.display = &lt;span style="color: #006080"&gt;''&lt;/span&gt;;&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  29:&lt;/span&gt;             }&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  30:&lt;/span&gt;         });&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  31:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060"&gt;  32:&lt;/span&gt; }&lt;/pre&gt;  &lt;/div&gt;&lt;/div&gt;&lt;h3&gt;Next Steps:&lt;/h3&gt;&lt;p&gt;I have a lot of refinement to go on this function if I am thinking about converting it into a plug-in at some point.&amp;#160; I need to make the table's id not hard coded and bind the &lt;font face="Courier"&gt;onKeyUp&lt;/font&gt; events when the search button is pressed instead of having it attached all the time in the HTML.&amp;#160; In addition, I need to look into incorporating a zebra-striping plug-in as well to have it address the row styling after the filtering.&amp;#160; &lt;/p&gt;&lt;p&gt;The code is a great starting point and it's very useful as is.&amp;#160; With a little refinement, it can provide a very robust mechanism for simple table filtering without having to learn and use a very complex plug-in.&lt;/p&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var dzone_url = 'http://randomactsofcoding.blogspot.com/2009/01/filtering-table-results-with-jquery.html';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = 'Filtering Table Results with jQuery';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = 'A look into using jQuery to filter results of a table based on specific textboxes';&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = '2';&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt; &lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f01%2ffiltering-table-results-with-jquery.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2frandomactsofcoding.blogspot.com%2f2009%2f01%2ffiltering-table-results-with-jquery.html&amp;bgcolor=006699" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-198387417690784771?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/01/filtering-table-results-with-jquery.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7881153019980313926.post-2583245399845088123</guid><pubDate>Wed, 07 Jan 2009 18:33:00 +0000</pubDate><atom:updated>2009-01-07T12:34:45.026-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Commentary</category><title>Goals for the New Year</title><description>&lt;p&gt;Happy New Year!&amp;#160; Ok, so I'm a week late.&amp;#160; With the start of each year comes a tradition that some view as a farse while others hold as an event of refocusing.&amp;#160; New Year's Resolutions are are great time to reflect and focus what someone wants to achieve.&amp;#160; While I'm not big on making my personal goals known like some other bloggers (it's just not my cup of tea), below are a few goals I've set for myself that relate (directly or indirectly) to this site.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Blog More&lt;/h3&gt;  &lt;p&gt;This is a given.&amp;#160; 2008 was a huge year of transition for me in my personal and professional life.&amp;#160; While I was able to churn out more post than I had before, I struggled on many weeks.&amp;#160; I'm hoping to be able to hit my goal of once per week this year.&amp;#160; Hopefully I'll be able to keep it up while also providing interesting topics for everyone to follow.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Learn F#&lt;/h3&gt;  &lt;p&gt;One of the things that I've wanted to do in recent months is expand my professional arsenal.&amp;#160; Coming from a Java background and transitioned into the .Net world almost exclusively now, I've somewhat been stuck trying to stay afloat with just C# and VB.Net (ASP.Net included).&amp;#160; While I am still working on keeping up with the times and changes in those languages, I'm wanting to expand into F# as well for a truly different perspective.&amp;#160; &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Learn Silverlight 2&lt;/h3&gt;  &lt;p&gt;I dabbled in Silverlight 1 while I was also learning XAML in general for WPF.&amp;#160; It was fun but I didn't get too deep into it due to the JavaScript model that it used and the obvious changes Silverlight 2 (then 1.1 alpha) had.&amp;#160; Now that Silverlight 2 is out.&amp;#160; It's time for me to get back to work on it and begin getting a subtle level of proficiency in it.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Finish the Books I Start Reading&lt;/h3&gt;  &lt;p&gt;For those that know me, I love reading; however, I tend to read books in parallel and rarely finish technical books.&amp;#160; This works well for some books since they are great for references just as much as reading cover-to-cover (i.e. Wrox's Professional C# 2008, etc.).&amp;#160; The issue comes in when I'm reading a book to clarify a topic or to truly learn, I tend to lose attention on the material.&amp;#160; This goal is to simply push myself to finish the books that I feel need to be finished.&amp;#160; For example, here are all of the books I'm currently reading:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a title="Website Optimization: Speed, Search Engine &amp;amp; Conversion Rate Secrets" target="_blank" href="http://www.amazon.com/Website-Optimization-Search-Conversion-Secrets/dp/0596515081/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1231352911&amp;amp;sr=1-1"&gt;Website Optimization&lt;/a&gt; by Andrew B. King&lt;/li&gt;    &lt;li&gt;&lt;a title="jQuery in Action" target="_blank" href="http://www.amazon.com/jQuery-Action-Bear-Bibeault/dp/1933988355/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1231352880&amp;amp;sr=1-1"&gt;jQuery in Action&lt;/a&gt; by Bear Bibeault and Yehuda Katz&lt;/li&gt;    &lt;li&gt;&lt;a title="The Design of Sites: Patterns for Creating Winning Web Sites" target="_blank" href="http://www.amazon.com/Design-Sites-Patterns-Creating-Winning/dp/0131345559/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1231352837&amp;amp;sr=1-1"&gt;The Design of Sites&lt;/a&gt; by Van Duyne, Landay, and Hong&lt;/li&gt;    &lt;li&gt;&lt;a title="Introducing Microsoft Silverlight 2" target="_blank" href="http://www.amazon.com/Introducing-Microsoft-Silverlight-2-0-2nd/dp/073562528X/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1231352714&amp;amp;sr=1-1"&gt;Introducing Microsoft Silverlight 2&lt;/a&gt; by Laurence Moroney&lt;/li&gt;    &lt;li&gt;&lt;a title="Alice in Wonderland" target="_blank" href="http://www.amazon.com/Wonderland-Through-Looking-Wordsworth-Classics/dp/1853261181/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1231352660&amp;amp;sr=1-1"&gt;Alice in Wonderland&lt;/a&gt; by Lewis Carroll (ok not an IT book but is a great way to stimulate the imagination and unwind)&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Learn DDD&lt;/h3&gt;  &lt;p&gt;One concept that is being shown a lot of attention recently is Domain Driven Design.&amp;#160; It's got some great concepts for managing complexity and the research I've done on it so far has yielded some interesting ideas on my application designs.&amp;#160; I just recently picked up a copy of &lt;a title="Domain Driven Design: Tackling Complexity in the Heart of Software" target="_blank" href="http://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215/ref=pd_bbs_sr_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1231352601&amp;amp;sr=8-1"&gt;Eric Evans' book&lt;/a&gt; and will hopefully get to it very soon to clarify a lot of the items I've had some trouble with.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Use jQuery More&lt;/h3&gt;  &lt;p&gt;I love jQuery.&amp;#160; Of all of the JavaScript frameworks that I've used on both personal and professional projects, it is the one I prefer hands down.&amp;#160; With that being said, I haven't had much spare time to work on any personal projects that require new ways of using it so such posts have been reduced a bit.&amp;#160; I have projects queued up so hopefully there'll be more jQuery related posts to come up in the future.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;In Summary&lt;/h3&gt;  &lt;p&gt;I'm sure that I'll have more goals as the year progresses; however, for right now I feel like I have a good focus for the next handful of months.&amp;#160; Next week I'll start up the normal posts again.&amp;#160; This year will have a more diverse mix of posts with more tools and different technologies and techniques coming.&amp;#160; Hopefully I'll be able to stick to my goals :-).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7881153019980313926-2583245399845088123?l=randomactsofcoding.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://randomactsofcoding.blogspot.com/2009/01/goals-for-new-year.html</link><author>James.R.Eggers@gmail.com (J. Eggers)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item></channel></rss>
