<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-3016850660716023308</atom:id><lastBuildDate>Thu, 17 Oct 2024 20:14:34 +0000</lastBuildDate><category>ASP.NET MVC</category><category>Tips and Tricks</category><category>Unit Testing</category><category>Community</category><category>ASP.NET</category><category>Silverlight</category><category>VSTS</category><category>review</category><category>Linux</category><category>UX</category><category>VMWare</category><category>integration</category><category>Agile</category><category>Razor</category><title>Jess Chadwick: Coder</title><description>Am I an expert?  Nah... but I play one on the Internet!</description><link>http://jesschadwick.blogspot.com/</link><managingEditor>noreply@blogger.com (Jess Chadwick)</managingEditor><generator>Blogger</generator><openSearch:totalResults>69</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-1390624942421076226</guid><pubDate>Sat, 01 Oct 2011 19:44:00 +0000</pubDate><atom:updated>2011-10-01T15:44:13.600-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Unit Testing</category><title>Approval Testing–better ROI for UI testing?</title><description>&lt;p&gt;A &lt;a href=&quot;http://herdingcode.com/?p=329&quot;&gt;recent episode of Herding Code&lt;/a&gt; interviewed the creator of the &lt;a href=&quot;http://approvaltests.sourceforge.net/&quot;&gt;Approval Tests&lt;/a&gt; project, Llewellyn Falco.&amp;#160; Initially, I was vehemently against the idea.&amp;#160; Rather, I consider automated UI testing (building scripts that execute the UI and inspect what happens) incredibly time-consuming and flaky. In other words, you spend a lot of time producing something that has limited value - the ROI is just not there.&lt;/p&gt;  &lt;p&gt;But, by the end of the podcast, I was sold.&amp;#160; The concept of Approval Tests seems to drastically reduce the time it takes to create – and, more importantly, maintain – automated UI tests.&amp;#160; The value stays the same but the effort is reduced, which means that the ROI numbers start to become much more tolerable.&amp;#160; Frankly, I think the ROI of backend (non-UI) tests way overshadows UI testing…&amp;#160; but at least it’s palatable.&lt;/p&gt;  </description><link>http://jesschadwick.blogspot.com/2011/10/approval-testingbetter-roi-for-ui.html</link><author>noreply@blogger.com (Jess Chadwick)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-1850198774815807552</guid><pubDate>Fri, 30 Sep 2011 15:16:00 +0000</pubDate><atom:updated>2011-09-30T11:17:43.532-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ASP.NET MVC</category><title>Where do Model Binding values come from?</title><description>&lt;p&gt;ASP.NET MVC Model Binding is a very powerful feature – arguably one of the most valuable features in the entire framework.&amp;#160; As with many “very powerful” features, it is also pretty complex and this means that it works great… most of the time… until it doesn’t.&lt;/p&gt;  &lt;p&gt;One of the biggest questions is “where are these values coming from”?&amp;#160; The simple answer to this question is:&amp;#160; the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/system.web.httprequest.aspx&quot;&gt;Request&lt;/a&gt; object.&amp;#160; The Request object is a core ASP.NET object - a dictionary of values aggregated from various sources such as the querystring (URL), form post values, and server variables.&amp;#160; The Request object is nothing new – it’s been around in one form or another since the days of ASP!&lt;/p&gt;  &lt;p&gt;Ok, so you know how I just said that the model binding values come from the Request object?&amp;#160; Uh…&amp;#160; that was kind of a lie. The truth is that they come from &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/system.web.mvc.ivalueprovider.aspxhttp://msdn.microsoft.com/en-us/library/system.web.mvc.ivalueprovider.aspx&quot;&gt;ValueProviders&lt;/a&gt; (created by &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/system.web.mvc.valueproviderfactory.aspx&quot;&gt;ValueProviderFactories&lt;/a&gt;). These value providers try to retrieve values from the same places - in the same order - as the Request object. Don’t believe me?&amp;#160; Have a look at the source:&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;pre class=&quot;c-sharp&quot; name=&quot;code&quot;&gt;public static class ValueProviderFactories {&lt;br /&gt;&lt;br /&gt;        private static readonly ValueProviderFactoryCollection _factories = new ValueProviderFactoryCollection() {&lt;br /&gt;            new ChildActionValueProviderFactory(),&lt;br /&gt;            new FormValueProviderFactory(),&lt;br /&gt;            new JsonValueProviderFactory(),&lt;br /&gt;            new RouteDataValueProviderFactory(),&lt;br /&gt;            new QueryStringValueProviderFactory(),&lt;br /&gt;            new HttpFileCollectionValueProviderFactory(),&lt;br /&gt;        };&lt;br /&gt;&lt;br /&gt;        public static ValueProviderFactoryCollection Factories {&lt;br /&gt;            get {&lt;br /&gt;                return _factories;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;In this way, the order of the default collection of Value Providers essentially mimics the Request object… which is why you are usually pretty safe in &lt;em&gt;considering&lt;/em&gt; them “the same” even when they’re not.&amp;#160; &lt;/p&gt;  </description><link>http://jesschadwick.blogspot.com/2011/09/where-do-model-binding-values-come-from.html</link><author>noreply@blogger.com (Jess Chadwick)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-8760253527467521399</guid><pubDate>Fri, 19 Aug 2011 17:02:00 +0000</pubDate><atom:updated>2011-08-19T13:26:40.902-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Tips and Tricks</category><title>Advice for new developers</title><description>&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: arial; font-size: x-small;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;After a recent user group presentation I was asked what advice I had for developers looking to break into the business. The result was the brain dump below. &amp;nbsp;For some reason I&#39;m a huge fan of bulleted lists, so below is my advice in bulleted form. &amp;nbsp;The first two are really all you need. The rest are just icing.&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Find a mentor&amp;nbsp;&lt;/b&gt;What we do is a craft, and the best (quickest, at least) way to go from layman to craftsman is to go through an apprenticeship.&lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Focus on the &quot;why&quot;, not the &quot;how&quot;&amp;nbsp;&lt;/b&gt;There are many ways to skin a cat, but the biggest question is: what are you hoping to accomplish by skinning the cat? Our craft is filled with&amp;nbsp;subtlety,&amp;nbsp;nuance, and often strong opinions. The goal is to create working, useful software and the tools we use to do that are often different with each scenario. Thus, the best answer to &quot;how should I do this?&quot; is &quot;It depends.&quot;&lt;br /&gt;
&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;You might want to be an &quot;&lt;a href=&quot;http://asp.net/&quot; target=&quot;_blank&quot;&gt;ASP.NET&lt;/a&gt;&amp;nbsp;developer&quot;, but&amp;nbsp;&lt;a href=&quot;http://asp.net/&quot; target=&quot;_blank&quot;&gt;ASP.NET&lt;/a&gt;&amp;nbsp;and even .NET as a whole are just a piece of the larger development world. Languages and syntax are not universal, but fundamental concepts and techniques are. When you know the fundamentals you can apply them to&amp;nbsp;quickly grasp&amp;nbsp;any new technology or concept.&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Soak in as many blogs and podcasts as you can&amp;nbsp;&lt;/b&gt;Working physically alongside a mentor cannot be beat. But, if you are trying to &quot;break in to the business&quot; it&amp;nbsp;is often not a viable option. &amp;nbsp;In lieu of face-to-face collaboration, go to the web! Online tutorials and API documentation tells you the&amp;nbsp;&lt;b&gt;how&lt;/b&gt;, but blogs and podcasts usually offer far more insight into the&amp;nbsp;&lt;b&gt;why&lt;/b&gt;.&amp;nbsp;Find as many blogs and podcasts as you can and immerse yourself in them.&amp;nbsp;Here are a few that I love:&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://dotnetrocks.com/&quot;&gt;.NET Rocks!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.hanselminutes.com/&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: inherit;&quot;&gt;Hanselminutes&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://herdingcode.com/&quot;&gt;Herding Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://deepfriedbytes.com/&quot;&gt;Deep Fried Bytes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Code, code, code!&amp;nbsp;&lt;/b&gt;Focus on the&amp;nbsp;&lt;b&gt;why&lt;/b&gt;&amp;nbsp;all you want - it&#39;s useless without the&amp;nbsp;&lt;b&gt;how&lt;/b&gt;! &amp;nbsp;You need to learn languages and frameworks and - like spoken languages - the best way to learn them is to use them... over and over. &amp;nbsp;Until your fingers hurt.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Find all the tutorials you can and run through them (considering the&amp;nbsp;&lt;b&gt;why&lt;/b&gt;&amp;nbsp;along the way)&lt;/li&gt;
&lt;li&gt;Make up your own projects and&amp;nbsp;&lt;i&gt;complete them&lt;/i&gt;. &amp;nbsp;Try to come up with things that resemble &quot;real world scenarios&quot;&lt;/li&gt;
&lt;li&gt;Browse the source of open source projects and see how they do things (this is a tactical twist on the &quot;mentor&quot; concept).&lt;/li&gt;
&lt;li&gt;&lt;i&gt;Commit&lt;/i&gt;&amp;nbsp;to an open source project! &amp;nbsp;Not only will this force you to figure out how to write the code, most open source project coordinators will give you a &quot;free&quot; code review to boot. &amp;nbsp;(Hey, that sounds almost like in-person mentoring!)&lt;/li&gt;
&lt;/ul&gt;&lt;/ul&gt;&lt;div&gt;Software development can be fun, exciting, and very rewarding (in many ways), but in order to get the most out of it, you have to put the time in to learn the craft.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;Good luck, and happy coding!&lt;/div&gt;</description><link>http://jesschadwick.blogspot.com/2011/08/advice-for-new-developers.html</link><author>noreply@blogger.com (Jess Chadwick)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-1495053749375345731</guid><pubDate>Tue, 07 Jun 2011 17:45:00 +0000</pubDate><atom:updated>2011-06-07T13:46:52.007-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Unit Testing</category><title>What is Test-Driven Development (TDD)?</title><description>&lt;p&gt;Test-Driven Development is a development approach that relies on unit tests to drive the development and - more importantly - the &lt;i&gt;design&lt;/i&gt; of applications. In order for software to be considered &amp;quot;testable&amp;quot; it must be adequately decomposable, allowing tests to target specific units of logic (e.g. classes, methods, or even specific portions of a method). The requirement for decomposition drives loosely-coupled, &lt;a href=&quot;http://en.wikipedia.org/wiki/Solid_(object-oriented_design)&quot;&gt;&amp;quot;SOLID&amp;quot;&lt;/a&gt; architecture which embraces OO principles.&lt;/p&gt;  &lt;h3&gt;Benefits of TDD&lt;/h3&gt;  &lt;p&gt;&amp;quot;True&amp;quot;, dogmatic TDD – also called “Test-First Development” - dictates that code may only be written to satisfy a failing test, and only the bare minimum code is written to make that test pass. TDD provides several benefits:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;b&gt;Loosely Coupled Architecture&lt;/b&gt;       &lt;br /&gt;The need for tests to completely control a component’s environment drives loosely-coupled components, which – when extrapolated to the system as a whole - leads to a loosely-coupled architecture.&amp;#160; &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;b&gt;Focused Development&lt;/b&gt;       &lt;br /&gt;Scope of code currently written is limited to the needs of the immediate business requirement. If more code is needed to support future requirements, that work is delayed until future tests will drive that development. This keeps developers focused solely on the task/requirement at hand.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;b&gt;Regression Test Suite&lt;/b&gt;       &lt;br /&gt;Unit tests act as a regression test for the remainder of the application&#39;s lifetime. And, since dogmatic TDD states that no code can be written without a test to back it, this implies that an application developed using TDD will never have less than 100% &lt;a href=&quot;http://en.wikipedia.org/wiki/Code_coverage&quot;&gt;code coverage&lt;/a&gt; (the number of lines of production code covered by unit tests). That said, true 100% code coverage is very impractical for a number of reasons.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;b&gt;Documentation&lt;/b&gt;       &lt;br /&gt;Unit tests are merely code that executes other code, and act as extensive “real-world” examples of how components are used, thus providing a form of documentation.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;b&gt;More Productive Debugging&lt;/b&gt;       &lt;br /&gt;Since “units under test” are adequately isolated and have at least one unit test focused specifically on them, it is often incredibly easy to locate a failing component by looking for the failing test(s). What’s more, since unit tests are executable, &lt;i&gt;debug-able&lt;/i&gt; code, developers can easily attach their debugger to a specific test and execute it.       &lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;Detriments of TDD&lt;/h3&gt;  &lt;ul&gt;   &lt;li&gt;&lt;b&gt;More Code        &lt;br /&gt;&lt;/b&gt;By definition, the test-first methodology produces a test suite which – at a minimum – doubles the size of your solution’s codebase. This leads to:       &lt;ul&gt;       &lt;li&gt;&lt;b&gt;Increased Lines of Code            &lt;br /&gt;&lt;/b&gt;Assuming it takes at least the same amount of time and effort to write test code as it does to write production code, TDD literally doubles the time spent writing code produced (and the corresponding time it takes to write said code).           &lt;br /&gt;&lt;b&gt;Perspective: &lt;/b&gt;In terms of the SDLC, the time spent actually writing code is only a fraction of the Implementation phase – much more time is spent on developer testing/verification, debugging, and bug fixing. Taking this into consideration, the increased coding time introduced by TDD is easily offset by more targeted and productive debugging, not to mention lowering the number of bugs to begin with (both in the long term &lt;i&gt;and&lt;/i&gt; the short term!).&amp;#160; &lt;br /&gt;&lt;/li&gt;        &lt;li&gt;&lt;b&gt;Increased Cost of Change            &lt;br /&gt;&lt;/b&gt;Since unit test code is so closely tied to production code, changes to business requirements mean that both production code and its corresponding tests will need to change. The implications of this change are the same as the preceding bullet: writing and changing code is only a fraction of the SDLC Implementation phase. &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;&lt;b&gt;Even More Code!        &lt;br /&gt;&lt;/b&gt;Developers can easily become carried away with writing an abundance of unit tests in an effort to achieve the highest level of code coverage they can. The ROI of additional unit tests against an already-tested component can drop quickly as the number of tests goes up.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;b&gt;False Sense of Security        &lt;br /&gt;&lt;/b&gt;A high level of code coverage can provide a false sense of security if developers are convinced that the level of code coverage equates to the nonexistence of bugs. However, code coverage only measures whether or not a line of code was executed, not &lt;i&gt;how&lt;/i&gt; it was executed (i.e. under what conditions). Consider a highway system: just because you drove your car over every foot of road doesn’t mean those same roads will react the same when traversed by a bus.&lt;b&gt;&lt;/b&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;  &lt;h3&gt;An Example of TDD in Action&lt;/h3&gt;  &lt;h4&gt;Business Requirement&lt;/h4&gt;  &lt;p&gt;The application must produce the sum of two numbers&lt;/p&gt;  &lt;p&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;  &lt;h4&gt;Step 1: Write a failing test&lt;/h4&gt;  &lt;p&gt;public void ShouldProduceSumOfTwoNumbers() {    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Assert.AreEqual(4, new Calculator().Sum(1, 3));&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;b&gt;FAIL!      &lt;br /&gt;&lt;/b&gt;}&lt;/p&gt;  &lt;h4&gt;Step 2: Write just enough code to make the failing test pass&lt;/h4&gt;  &lt;p&gt;public class Calculator {    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; public int Sum(int number1, int number2) {     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return 4;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;b&gt;PASS!      &lt;br /&gt;&lt;/b&gt;&amp;#160;&amp;#160;&amp;#160; }     &lt;br /&gt;}&lt;/p&gt;  &lt;p&gt;And we’re done! Except that what we’ve produced is a method which returns a hard-coded value! This situation is easy to rectify: write another failing test against the same component.&lt;/p&gt;  &lt;h4&gt;Step 3: Write another test which specifies a different set of parameters&lt;/h4&gt;  &lt;p&gt;public void ShouldProduceSumOfTwoOtherNumbers() {    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Assert.AreEqual(5, new Calculator().Sum(2, 3));&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;b&gt;FAIL!&lt;/b&gt;     &lt;br /&gt;}&lt;/p&gt;  &lt;p&gt;Since the new test asserts a different result based on different inputs, this test fails because the initial implementation of the Sum method returned the hard-coded value different than what this new test expects.&lt;/p&gt;  &lt;h4&gt;Step 4: Revisit and refactor the production code to pass the new test&lt;/h4&gt;  &lt;p&gt;public class Calculator {    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; public int Sum(int number1, int number2) {     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return number1 + number2;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;b&gt;PASS!      &lt;br /&gt;&lt;/b&gt;&amp;#160;&amp;#160;&amp;#160; }     &lt;br /&gt;}&lt;/p&gt;  &lt;p&gt;Though simple and contrived, this example effectively demonstrates the process – and more importantly, the mindset – behind Test-Driven development.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;  &lt;h3&gt;TDD and UI Development&lt;/h3&gt;  &lt;p&gt;As you move further away from the statically-typed compiled “backend” code and closer to the UI, the unit tests associated with these parts of the system tend to introduce less resilient and reliable methods such as string comparison. As a result, the cost of creation and maintenance grows exponentially.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;A word of warning:&lt;/b&gt; because of this exponential cost and loss of strong reliability, the ROI of the TDD approach often becomes negative when applied to the UI layers. It is often better to drive the testing of UI layers by professional (QA) testers as they will likely be applying these approaches anyway.&lt;/p&gt;  &lt;h3&gt;TDD vs BDD (Behavior-Driven Development)&lt;/h3&gt;  &lt;p&gt;Test-Driven Development – as its name implies – relies on unit tests to drive production code. Ideally, these unit tests derive from business requirements, however strict adherence to the Test First approach often means that developers end up writing unit tests to allow them to write code and ensure that that code works… not that it meets any kind of business requirements.&lt;/p&gt;  &lt;p&gt;Behavior-Driven Development (BDD) is a philosophy grown from TDD which focuses on the software requirements of - and human interaction with - “the business” to deliver software that provides value to the business. Though the two approaches are variations on the same theme and the differences are subtle, BDD aims to please customers by satisfying their (ever-changing) requirements, as opposed to simply focusing on “working code”. This usually means less stringent code coverage requirements&lt;/p&gt;  &lt;h3&gt;Resources&lt;/h3&gt;  &lt;p&gt;General internet searches for the concepts in this document such as “test driven development” and “behavior-driven development” rarely leave much to be desired. I have not come across many &lt;i&gt;bad&lt;/i&gt; resources in regards to Test-Driven Development. Unfortunately, because these are heavily philosophical concepts that go far beyond simply learning a language or syntax, the only way to truly understand it is to find a mentor and do it (and learn from your mistakes).&lt;/p&gt;  &lt;p&gt;Regardless, here is a short list of some of the better resources I’ve found recently:&lt;/p&gt;  &lt;p&gt;· &lt;a href=&quot;http://en.wikipedia.org/wiki/Test-driven_development&quot;&gt;Test-Driven Development&lt;/a&gt; Wikipedia (yes, it’s a great resource!)&lt;/p&gt;  &lt;p&gt;· &lt;a href=&quot;http://c2.com/cgi/wiki?TestDrivenDevelopment&quot;&gt;Test Driven Development&lt;/a&gt; Ward Bell, et al – the grandfather(s) of XP&lt;/p&gt;  &lt;p&gt;· &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/aa730844(v=vs.80).aspx&quot;&gt;Guidelines for Test-Driven Development&lt;/a&gt; Jeffery Palermo&lt;/p&gt;  &lt;p&gt;· &lt;a href=&quot;http://behaviour-driven.org/Introduction&quot;&gt;Introduction to Behavior-Driven Development&lt;/a&gt; BddWiki&lt;/p&gt;  &lt;p&gt;· &lt;a href=&quot;http://dannorth.net/introducing-bdd/&quot;&gt;Introducing BDD&lt;/a&gt; Dan North&lt;/p&gt;  &lt;p&gt;· &lt;a href=&quot;http://jamesshore.com/Agile-Book/test_driven_development.html&quot;&gt;The Art of Agile Development: Test-Driven Development&lt;/a&gt; James Shore&lt;/p&gt;  &lt;p&gt;· &lt;a href=&quot;http://jesschadwick.blogspot.com/2009/11/what-unit-test.html&quot;&gt;What is a Unit Test?&lt;/a&gt; Jess Chadwick&lt;/p&gt;  &lt;p&gt;· &lt;a href=&quot;http://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0321146530&quot;&gt;Test-Driven Development: By Example&lt;/a&gt; Kent Beck&lt;/p&gt;  &lt;p&gt;· &lt;a href=&quot;http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052&quot;&gt;Working Effectively With Legacy Code&lt;/a&gt; Michael Feathers (applying TDD to existing codebases)&lt;/p&gt;  </description><link>http://jesschadwick.blogspot.com/2011/06/what-is-test-driven-development-tdd.html</link><author>noreply@blogger.com (Jess Chadwick)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-5289087597454802451</guid><pubDate>Wed, 18 May 2011 02:08:00 +0000</pubDate><atom:updated>2011-05-17T23:47:02.697-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Agile</category><title>“Being Agile” Means No Documentation, Right?</title><description>&lt;p&gt;&lt;a href=&quot;http://lh3.ggpht.com/_sH3XWh6OzVE/TdMsw9r490I/AAAAAAAAAKg/_ef4xVDoUYw/s1600-h/agile-pills%5B16%5D.png&quot;&gt;&lt;img style=&quot;background-image: none; border-right-width: 0px; margin: 15px 10px 15px 30px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px&quot; title=&quot;agile-pills&quot; border=&quot;0&quot; alt=&quot;agile-pills&quot; align=&quot;right&quot; src=&quot;http://lh5.ggpht.com/_sH3XWh6OzVE/TdMsxYY0rPI/AAAAAAAAAKk/SqWJMm7vxAU/agile-pills_thumb%5B14%5D.png?imgmax=800&quot; width=&quot;378&quot; height=&quot;270&quot; /&gt;&lt;/a&gt;Ask most software professionals what Agile is and they’ll probably start talking about flexibility and delivering what the customer wants.&amp;#160; Some may even mention the word “iterations”.&amp;#160; But inevitably, they’ll say at some point that it means less or even no documentation.&amp;#160; After all, doesn’t creating, updating, and circulating painstakingly comprehensive documentation that everyone and their mother have officially signed off on go against the very core of Agile?&amp;#160; Of course it does!&amp;#160; But really, they’re missing the point!&lt;/p&gt;  &lt;p&gt;Read &lt;a href=&quot;http://agilemanifesto.org/&quot;&gt;The Agile Manifesto&lt;/a&gt;. (No, seriously - read it now. It’s short. I’ll wait.)&amp;#160; It’s essentially a list of values.&amp;#160; More specifically, it’s a right-side/left-side weighted list of values:&amp;#160; “Value &lt;strong&gt;this&lt;/strong&gt; over &lt;strong&gt;that&lt;/strong&gt;”. Many people seem to get the impression that this is really a “good vs. bad” list and that those values on the right side are evil and should essentially be tossed on the floor.&amp;#160; This leads to the conclusion that in order to be Agile we must throw away our fancy expensive tools, document as little as possible, and scoff at the idea of a project plan.&amp;#160; This conclusion is quite convenient because it essentially means “less work, more productivity!” (particularly in regards to the documentation and project planning).&amp;#160; I couldn’t disagree with this conclusion more.&lt;/p&gt;  &lt;p&gt;My interpretation of the Manifesto targets “over” as the operative word.&amp;#160; It’s not just a list of right vs. wrong or good vs. bad.&amp;#160; It’s a list of &lt;strong&gt;priorities&lt;/strong&gt;.&amp;#160; In other words, none of the concepts on the list should be removed from your development lifecycle – &lt;strong&gt;they are all important&lt;/strong&gt;… just not &lt;strong&gt;equally&lt;/strong&gt; important.&amp;#160; This is not a unique interpretation, in fact &lt;em&gt;it says so right at the end of the manifesto!&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;So, the next time your team sits down to tackle that big new project, don’t make the first order of business to outlaw all meetings, documentation, and project plans.&amp;#160; Instead, &lt;strong&gt;collaborate&lt;/strong&gt; with both your team and the business members involved (you &lt;em&gt;do&lt;/em&gt; have business members sitting in the room, directly involved in the project planning, right?) and determine the &lt;strong&gt;bare minimum&lt;/strong&gt; that will allow all of you to work and communicate in the best way possible.&amp;#160; This often means that you can pick and choose which parts of the Agile methodologies and process work for your particular project and end up with an amalgamation of Waterfall, Agile, XP, SCRUM and whatever other methodologies the members of your team have been exposed to (my favorite is “SCRUMerfall”).&lt;/p&gt;  &lt;p&gt;The biggest implication of this is that there is no one way to implement Agile.&amp;#160; There is no checklist with which you can tick off boxes and confidently conclude that, “Yep, we’re Agile™!”&amp;#160; In fact, depending on your business and the members of your team, moving to Agile full-bore may actually be ill-advised.&amp;#160; Such a drastic change just ends up taking everyone out of their comfort zone which they inevitably fall back into by the end of the project.&amp;#160; This often results in frustration to the point that Agile is abandoned altogether because “we just need to ship something!”&amp;#160; Needless to say, this is far more devastating to a project.&lt;/p&gt;  &lt;p&gt;Instead, I offer this approach: keep it simple and take it slow.&amp;#160; If your business members or customers are only involved at the beginning phases and nowhere to be seen until the project is delivered, invite them to your daily meetings; encourage them to keep up to speed on what’s going on on a daily basis and provide feedback.&amp;#160; If your current process is heavy on the documentation, try to &lt;em&gt;reduce&lt;/em&gt; it as opposed to eliminating it outright.&amp;#160; If you need a “TPS Change Request” signed in triplicate with a 5-day “cooling off period” before a change is implemented, try a simple bug tracking system!&amp;#160; Tighten the feedback loop!&lt;/p&gt;  &lt;p&gt;Finally, at the end of every “iteration” (whatever that means to you, as long as it’s relatively frequent), take as much time as you can spare (even if it’s an hour or so) and perform some kind of retrospective.&amp;#160; Learn from your mistakes.&amp;#160; Figure out what’s working for you and what’s not, then fix it.&amp;#160; Before you know it you’ve got a handful of iterations and/or projects under your belt and you sit down with your team to realize that, “Hey, this is working - we’re pretty Agile!”&amp;#160; &lt;/p&gt;  &lt;p&gt;After all, Agile is a Zen state.&amp;#160; It’s a destination that you aim for, not force, and even if you never reach true “enlightenment” that doesn’t mean your team can’t be exponentially better off from merely taking the journey.&lt;/p&gt;  </description><link>http://jesschadwick.blogspot.com/2011/05/being-agile-means-no-documentation.html</link><author>noreply@blogger.com (Jess Chadwick)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/_sH3XWh6OzVE/TdMsxYY0rPI/AAAAAAAAAKk/SqWJMm7vxAU/s72-c/agile-pills_thumb%5B14%5D.png?imgmax=800" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-3993466946753239930</guid><pubDate>Fri, 11 Mar 2011 06:05:00 +0000</pubDate><atom:updated>2011-03-14T20:44:45.803-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ASP.NET MVC</category><category domain="http://www.blogger.com/atom/ns#">Razor</category><title>Presentation: Razor and the Art of Templating</title><description>&lt;p&gt;Had a blast tonight giving a presentation on Razor to my hometown user group, NJDOTNET.&amp;#160; While I kind of regret how much focus we gave to MVC instead of Razor itself, I’m glad people are so eager to talk about and learn more about MVC.&lt;/p&gt;  &lt;p&gt;If you’re looking for the RazorPad application that I showed and discussed, you can find it here:&amp;#160;&amp;#160; &lt;a href=&quot;http://razorpad.codeplex.com&quot;&gt;&lt;strong&gt;http://razorpad.codeplex.com&lt;/strong&gt;&lt;/a&gt;     &lt;br /&gt;Please feel free to comment publicly and/or privately – any and all feedback is welcome!&amp;#160; Or, if you’d like to help me code it, that’d be awesome, too – just let me know!&lt;/p&gt;  &lt;table border=&quot;0&quot; width=&quot;100%&quot;&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td width=&quot;50%&quot;&gt;&lt;iframe height=&quot;300&quot; src=&quot;http://player.vimeo.com/video/21045362&quot; frameborder=&quot;0&quot; width=&quot;90%&quot;&gt;&lt;/iframe&gt;          &lt;p&gt;&lt;a href=&quot;http://vimeo.com/21045362&quot;&gt;Razor and the Art of Templating&lt;/a&gt; from &lt;a href=&quot;http://vimeo.com/user6159374&quot;&gt;Jess Chadwick&lt;/a&gt; on &lt;a href=&quot;http://vimeo.com&quot;&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;       &lt;/td&gt;        &lt;td width=&quot;50%&quot;&gt;         &lt;div style=&quot;width: 100%&quot; id=&quot;__ss_7227998&quot;&gt;&lt;object id=&quot;__sse7227998&quot; height=&quot;355&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=razortemplating-110311000105-phpapp01&amp;amp;stripped_title=razor-and-the-art-of-templating&amp;amp;userName=jesschadwick&quot; /&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot; /&gt;&lt;param name=&quot;allowScriptAccess&quot; value=&quot;always&quot; /&gt;&lt;embed name=&quot;__sse7227998&quot; src=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=razortemplating-110311000105-phpapp01&amp;amp;stripped_title=razor-and-the-art-of-templating&amp;amp;userName=jesschadwick&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;90%&quot; height=&quot;355&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;       &lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  </description><link>http://jesschadwick.blogspot.com/2011/03/presentation-razor-and-art-of.html</link><author>noreply@blogger.com (Jess Chadwick)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-1927996190784822810</guid><pubDate>Fri, 25 Feb 2011 05:14:00 +0000</pubDate><atom:updated>2011-06-07T13:33:27.849-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Unit Testing</category><title>Presentation: Automated Unit Testing for Mere Mortals</title><description>&lt;p&gt;Last weekend I had the immense pleasure of getting my unit testing presentation selected as one in the great Code Camp NYC lineup.&amp;#160; It was a great crowd and this is the first time I tried to record one of my talks.&amp;#160; I think it turned out alright!&amp;#160; I’ve embedded the low-quality version below.&amp;#160; If you prefer the high-def version, here it is:&amp;#160; &lt;a href=&quot;http://downloads.jesschadwick.com/videos/unit-testing/UnitTesting.html&quot;&gt;Unit Testing for Mere Mortals (720p)&lt;/a&gt;.&amp;#160;&amp;#160; &lt;/p&gt;&lt;p&gt;Enjoy, and please feel free to let me know what you think!&lt;/p&gt;&lt;iframe style=&quot;border-bottom-style: none; border-right-style: none; border-top-style: none; border-left-style: none; scroll: none; margin: none&quot; height=&quot;360&quot; border=&quot;0&quot; src=&quot;http://downloads.jesschadwick.com/videos/unit-testing/UnitTesting-small.html&quot; frameborder=&quot;0&quot; width=&quot;680&quot; scroll=&quot;none&quot;&gt;  Sorry, your browser doesn&#39;t support IFRAMEs!&lt;/iframe&gt;</description><link>http://jesschadwick.blogspot.com/2011/02/presentation-automated-unit-testing-for.html</link><author>noreply@blogger.com (Jess Chadwick)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-6809845996432884846</guid><pubDate>Fri, 09 Apr 2010 03:18:00 +0000</pubDate><atom:updated>2011-06-07T13:27:35.229-04:00</atom:updated><title>Presentation: Leveraging Continuous Integration for Fun and Profit!</title><description>&lt;p&gt;This evening I had another chance to speak in front of a great group of folks:&amp;#160; the members of my “hometown” NJDOTNET!&amp;#160; Everyone had a lot of great questions and overall I thought it was a lot of fun, and (as always) I look forward to the opportunity to speak to this group again.&amp;#160; I just hope everyone got a lot out of it – I look forward to hearing about how everyone goes back to work tomorrow morning and asks their team to start doing continuous integration! :)&lt;/p&gt;&lt;p&gt;For those of you who were interested in my source code, config files or slides, I’ve uploaded them to &lt;a href=&quot;http://cid-229ed79d402c9b40.skydrive.live.com/browse.aspx/Community/Presentations/Continuous%20Integration%20with%20CruiseControl.NET&quot;&gt;my secret Internet file lair&lt;/a&gt;.&amp;#160; Feel free to download them and check them out, as well as hit me up with any questions – I’d be glad to try to answer them!&lt;/p&gt;&lt;p&gt;If you don’t care to download the files, you can peruse the slide deck online: &lt;div style=&quot;width:425px&quot; id=&quot;__ss_3671390&quot;&gt;&lt;strong style=&quot;display:block;margin:12px 0 4px&quot;&gt;&lt;a href=&quot;http://www.slideshare.net/jesschadwick/leveraging-continuous-integration-for-fun-and-profit&quot; title=&quot;Leveraging Continuous Integration For Fun And Profit!&quot;&gt;Leveraging Continuous Integration For Fun And Profit!&lt;/a&gt;&lt;/strong&gt;&lt;object width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=leveragingcontinuousintegrationforfunandprofit-100408214526-phpapp02&amp;amp;stripped_title=leveraging-continuous-integration-for-fun-and-profit&quot; /&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot; /&gt;&lt;param name=&quot;allowScriptAccess&quot; value=&quot;always&quot; /&gt;&lt;embed src=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=leveragingcontinuousintegrationforfunandprofit-100408214526-phpapp02&amp;amp;stripped_title=leveraging-continuous-integration-for-fun-and-profit&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style=&quot;padding:5px 0 12px&quot;&gt;View more &lt;a href=&quot;http://www.slideshare.net/&quot;&gt;presentations&lt;/a&gt; from &lt;a href=&quot;http://www.slideshare.net/jesschadwick&quot;&gt;jesschadwick&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;/p&gt;</description><link>http://jesschadwick.blogspot.com/2010/04/presentation-leveraging-continuous.html</link><author>noreply@blogger.com (Jess Chadwick)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-2686226215457160116</guid><pubDate>Sat, 06 Mar 2010 19:07:00 +0000</pubDate><atom:updated>2010-03-06T16:17:21.062-05:00</atom:updated><title>NYC Code Camp 2010</title><description>&lt;p&gt;I had a great time presenting on the ASP.NET MVC Framework at the really awesome NYC Code Camp 2010 event today.&amp;#160; For those who wanted to look through the code, &lt;a href=&quot;http://cid-229ed79d402c9b40.skydrive.live.com/browse.aspx/Community/Presentations/NYC%20Code%20Camp%202010%20-%20ASP.NET%20MVC%20Framework&quot;&gt;here is a link to the code I showed&lt;/a&gt; (with “start” and “finish” versions) and check out the slide deck inline below: &lt;/p&gt;  &lt;div style=&quot;width: 425px&quot; id=&quot;__ss_3353914&quot;&gt;&lt;strong style=&quot;margin: 12px 0px 4px; display: block&quot;&gt;&lt;a title=&quot;Introduction To ASP.NET MVC&quot; href=&quot;http://www.slideshare.net/jesschadwick/introduction-to-aspnet-mvc-3353914&quot;&gt;Introduction To ASP.NET MVC&lt;/a&gt;&lt;/strong&gt;&lt;object width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=introductiontoaspnetmvc-100306151440-phpapp02&amp;amp;stripped_title=introduction-to-aspnet-mvc-3353914&quot; /&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot; /&gt;&lt;param name=&quot;allowScriptAccess&quot; value=&quot;always&quot; /&gt;&lt;embed src=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=introductiontoaspnetmvc-100306151440-phpapp02&amp;amp;stripped_title=introduction-to-aspnet-mvc-3353914&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;/embed&gt;&lt;/object&gt;    &lt;div style=&quot;padding-bottom: 12px; padding-left: 0px; padding-right: 0px; padding-top: 5px&quot;&gt;View more &lt;a href=&quot;http://www.slideshare.net/&quot;&gt;presentations&lt;/a&gt; from &lt;a href=&quot;http://www.slideshare.net/jesschadwick&quot;&gt;jesschadwick&lt;/a&gt;.&lt;/div&gt; &lt;/div&gt;&amp;#160;&amp;#160; As always, feel free to contact me if you have any questions or are interested in learning more!    </description><link>http://jesschadwick.blogspot.com/2010/03/nyc-code-camp-2010.html</link><author>noreply@blogger.com (Jess Chadwick)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-673037473294434316</guid><pubDate>Fri, 13 Nov 2009 03:28:00 +0000</pubDate><atom:updated>2011-06-07T13:33:40.141-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Unit Testing</category><title>What’s a “Unit Test”?</title><description>&lt;div style=&quot;text-align: center; float: right&quot; class=&quot;figure&quot;&gt;&lt;a href=&quot;http://www.entertainmentwallpaper.com/images/desktops/movie/tv_the_unit03.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;border-right-width: 0px; margin: 0px 0px 0px 15px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px&quot; title=&quot;Photo courtesy of those show cancelling bastards at CBS.&quot; border=&quot;0&quot; alt=&quot;Photo courtesy of those show cancelling bastards at CBS.&quot; src=&quot;http://lh3.ggpht.com/_sH3XWh6OzVE/Sv1tlmW7e6I/AAAAAAAAAIc/56pd4uFMphU/tv_the_unit03%5B5%5D.jpg?imgmax=800&quot; width=&quot;244&quot; height=&quot;196&quot; /&gt;&lt;/a&gt;     &lt;p style=&quot;padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px&quot; class=&quot;caption&quot;&gt;&lt;em&gt;&lt;font color=&quot;#000000&quot; size=&quot;1&quot;&gt;No, I’m not talking about these guys...&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;Generally speaking, writing any kind of code that exercises the code you&#39;ve written is a good thing, but the term “unit test” carries with it a very focused and specific meaning. Listed below are what I consider the top-most important qualities of a “&lt;strong&gt;unit test&lt;/strong&gt;”: &lt;/p&gt;&lt;ul&gt;&lt;li&gt;     &lt;p&gt;&lt;strong&gt;Atomic&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;
A unit test should focus on validating one small piece (“unit”) of functionality. Generally, this will be a single behavior or business case that a class exhibits. Quite often, this focus may be as narrow as a single method in a class (sometimes even a specific condition in a single method!). In practice, this equates to short tests with only a few (preferably just one) deliberate and meaningful assertions (Assert.That([…])).&lt;/p&gt;&lt;em&gt;Common Pitfalls &amp;amp; Code Smells&lt;/em&gt;       &lt;ul&gt;&lt;li&gt;Dozens of lines of code in one test &lt;/li&gt;
&lt;li&gt;More than 2-3 assertions, especially when they’re against multiple objects &lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;     &lt;p&gt;&lt;strong&gt;Repeatable&lt;/strong&gt; &lt;/p&gt;&lt;p&gt;&lt;br /&gt;
A unit test should produce exactly the same result at any time on any environment, given that environment fulfills a known set of dependencies, e.g. the .NET Framework. Tests cannot rely on anything in the external environment that isn’t under your direct control. For instance, you should never have to worry about having network/Internet connectivity, access to a database, file system permissions, or even the time of day (think DateTime.Now). Failed unit tests should indicate a bug in the code and nothing else.&lt;/p&gt;&lt;em&gt;Common Pitfalls &amp;amp; Code Smells&lt;/em&gt;       &lt;ul&gt;&lt;li&gt;Tests pass on the first execution, yet some or all fail on subsequent executions (or vice-versa) &lt;/li&gt;
&lt;li&gt;“NOTE: The XYZTest must be run prior to this or it will fail!” &lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;     &lt;p&gt;&lt;strong&gt;Isolated / Independent&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;In a culmination of the first two qualities, a unit test should be completely isolated from any other system or test. That is to say, a unit test should not assume or depend upon any other test having been run or external system (e.g. database) having a specific state or producing some specific result. Additionally, a unit test should also not create or leave behind any artifacts that may trip up other tests. This is certainly not to say that unit tests cannot share methods or even whole classes between each other – in fact, that is encouraged. What this means is that a unit test should not assume some other test has run previously or will run subsequently; these dependencies should instead be represented as explicit function calls or contained in your test fixture’s SetUp and TearDown methods that run prior to and immediately following every single test.&lt;/p&gt;&lt;em&gt;Common Pitfalls &amp;amp; Code Smells&lt;/em&gt;       &lt;ul&gt;&lt;li&gt;Database access &lt;/li&gt;
&lt;li&gt;Tests fail when your network or VPN connection is disabled &lt;/li&gt;
&lt;li&gt;Tests fail when you have not run some kind of external script (other than perhaps an NAnt script to compile, of course) &lt;/li&gt;
&lt;li&gt;Tests fail when configuration settings change or are not correct &lt;/li&gt;
&lt;li&gt;Tests must be executed under specific permissions &lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;     &lt;p&gt;&lt;strong&gt;Fast&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Assuming all of the above conditions are met, all tests should be “fast” (i.e. fractions of a second). Regardless, it is still beneficial to explicitly state that all unit tests should execute practically instantaneously. After all, one of the main benefits of an automated test suite is the ability to get the near-instant feedback about the current quality of your code. As the time to run the test suite increases, the frequency with which you execute it decreases. This directly translates into a great amount of time between the introduction and discovery of bugs.&lt;/p&gt;&lt;em&gt;Common Pitfalls &amp;amp; Code Smells&lt;/em&gt;       &lt;ul&gt;&lt;li&gt;Individual tests take longer than a fraction of a second to run &lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;If one were really clever, they might arrange the above into a cute little acronym like “FAIR”, but the order in which they appear above is very deliberate; it is the rough order of importance that I place on each quality.&lt;/p&gt;&lt;/blockquote&gt;&lt;h3&gt;Unit Tests vs. Integration Tests&lt;/h3&gt;&lt;p&gt;Odds are that if you have written any automated tests recently, you probably violated one of the above guidelines… and probably for very good reason! What you have produced, my friend, is another very valuable form of automated test called an &lt;strong&gt;integration test&lt;/strong&gt;. As opposed to a unit test - whose sole purpose is to validate the logic and/or functionality of a specific class or method – an integration test exists to validate the interaction (or “integration”, as it were) between two or more components. In other words, integration tests give the system a good work-out to make sure that all of the individual parts work together to achieve the desired result – a working application.&lt;/p&gt;&lt;p&gt;As such, integration tests are just as – if not more so – valuable in a business sense as unit tests. Their major drawbacks, however, are their slow speed and fragility. Not only does this mean that they will get executed less frequently than a unit test suite, but the rate of false-positives (or negatives… however you want to look at it) is much higher. When a unit test fails, it is a sure indication of a bug in the code. In contrast, when an integration tests fails it &lt;em&gt;may&lt;/em&gt; mean a bug in the code, but could also very well have been caused by other issues in the testing environment such as a lost database connection or corrupt/unexpected test data. These false positives - though a useful indicator that something is wrong in the developer’s environment – usually just serve to slow down the development process by taking the developer’s focus away from writing working code. Assuming you strive to avoid these distractions whenever possible, the conclusion I come to is that you should therefore strive to rely on extensive test coverage via a solid unit test suite and supplement that coverage with an integration test suite and not vice-versa.&lt;/p&gt;&lt;h3&gt;References&lt;/h3&gt;&lt;p&gt;A great deal of the reason I even took it upon myself to write this blog post was because I couldn’t really find any good online articles or posts concerning “what makes a unit test”!&amp;#160;&amp;#160; Below are a few of the great ones I found.&amp;#160; It may seem like I stole from some of them, but the ideas above really are my opinions…&amp;#160; they just happened to be widely shared. :)&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://codebetter.com/blogs/jeremy.miller/archive/2005/07/20/129552.aspx&quot;&gt;Qualities of a Good Unit Test&lt;/a&gt;:&amp;#160; Jeremy Miller (The Shade Tree Developer) &lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.codeville.net/2009/08/24/writing-great-unit-tests-best-and-worst-practises/&quot;&gt;Writing Great Unit Tests:&amp;#160; Best and Worst Practices&lt;/a&gt;:&amp;#160; Steve Sanderson &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;However, it seems at this point if you are very interested in learning more about this topic, books are your best bet.&amp;#160; Anything by the “usual suspects” (Fowler, Hunt, Thomas, Newkirk…) is a great bet, but here are a few I have read and loved:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://bit.ly/1353Xe&quot;&gt;Pragmatic Unit Testing In C# with NUnit&lt;/a&gt;:&amp;#160; Andy Hunt, Dave Thomas, Matt Hargett &lt;/li&gt;
&lt;li&gt;&lt;a href=&quot; http://bit.ly/fgBhp&quot;&gt;Test Driven Development: By Example&lt;/a&gt;:&amp;#160; Kent Beck&amp;#160;&amp;#160; (focuses on the &lt;em&gt;mentality&lt;/em&gt; behind unit testing over implementation) &lt;/li&gt;
&lt;/ul&gt;</description><link>http://jesschadwick.blogspot.com/2009/11/what-unit-test.html</link><author>noreply@blogger.com (Jess Chadwick)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/_sH3XWh6OzVE/Sv1tlmW7e6I/AAAAAAAAAIc/56pd4uFMphU/s72-c/tv_the_unit03%5B5%5D.jpg?imgmax=800" height="72" width="72"/><thr:total>9</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-6058845386770402132</guid><pubDate>Fri, 16 Oct 2009 06:43:00 +0000</pubDate><atom:updated>2011-06-07T13:32:43.783-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">integration</category><category domain="http://www.blogger.com/atom/ns#">VSTS</category><title>TFS Ain’t So Expensive Anymore</title><description>&lt;p&gt;Those of you who scoffed at the enormous price tag on previous releases of Team Foundation Server will be happy to hear about &lt;a href=&quot;http://blogs.msdn.com/bharry/archive/2009/10/01/tfs-2010-for-sourcesafe-users.aspx&quot; target=&quot;_blank&quot;&gt;“TFS Basic” - the new offering of TFS 2010&lt;/a&gt; (or as Brian calls it, “TFS for SourceSafe users”&amp;#160; **shudder**).&amp;#160; Presumably, this new offering includes all of the functionality that small development shops will need to thrive on TFS, while still offering a sane upgrade path.&lt;/p&gt;&lt;p&gt;I haven’t been able to find exactly how much this new SKU is going to run you, but from what I’ve seen it will not be $0.00 (AKA: free).&amp;#160; As &lt;a href=&quot;http://jesschadwick.blogspot.com/2009/09/issue-tracking-integration-with.html&quot; target=&quot;_blank&quot;&gt;my very last post&lt;/a&gt; may tell you, I am a huge fan of the free &amp;amp; open source offerings out there, but – as my last post shows – making these disparate projects integration together can quite often mean a whole lot of time and energy.&amp;#160; Even with the astronomical price tag of previous versions, the out-of-the-box integration of Source Control, Continuous Integration, and Change Tracking has always been incredibly alluring to me.&amp;#160; And, for those who really desired it, it was probably worth the cost.&amp;#160; The exciting part of this announcement is that you can now get this powerful integration – sans advanced features – for a fraction of what the full TFS system used to cost…&amp;#160; and that is pretty damn cool if you ask me.&lt;/p&gt;&lt;p&gt;Will I make the switch from Subversion+CruiseControl+[whatever change tracking and planning tool I’m using]?&amp;#160; Will I solicit my employer to switch?&amp;#160; No.&amp;#160; It’s nice to know that if one of the components isn’t working out for us or we find something better, we can replace just that one component and leave the others in place.&amp;#160; Additionally - while the initial pain in getting these open source solutions wired together can be substantial - once the initial price of time and effort is paid, it rarely gets in the way again.&amp;#160; However, those are existing installations I’m referring to;&amp;#160; for new projects, I will most definitely be evaluating TFS Basic along with the others and I expect that the savings we’d realize in integration alone will be enough to make it a leading contender.&lt;/p&gt;&lt;p&gt;For those of you who have never had the pleasure of using Team Foundation Server, I strongly suggest you go grab these bits and try it out.&amp;#160; Sure, it’s got its downsides (as anyone who &lt;a href=&quot;http://twitter.com/jchadwick&quot; target=&quot;_blank&quot;&gt;follows me on Twitter&lt;/a&gt; knows), but it is also one hell of a nice product and certainly worth checking out.&amp;#160; What’s more – with TFS Basic, you no longer need to be in a server environment – you can feel free to install it on your local development environment!&amp;#160; Go download and install the bits and come back here and let me know what you think!&lt;/p&gt;</description><link>http://jesschadwick.blogspot.com/2009/10/tfs-aint-so-expensive-anymore.html</link><author>noreply@blogger.com (Jess Chadwick)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-2542779881126140468</guid><pubDate>Fri, 04 Sep 2009 06:03:00 +0000</pubDate><atom:updated>2011-06-07T13:30:40.392-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">integration</category><title>Issue Tracking Integration with Subversion &amp;amp; TortoiseSVN</title><description>&lt;p&gt;Many development shops have the requirement to associate any code changes to a backlog item or defect to help track the time and energy spent working against a particular featureset.&amp;#160; This need is so prevelant, that the awesome TortoiseSVN Windows Explorer Subversion extension actually has some special settings you can use to help make your life a little easier.&lt;/p&gt;&lt;p&gt;Generally when demoing something like this, I like to show the finished result and then jump back to the beginning and follow the whole process step-by-step, but I’m going to break stride with this post.&amp;#160; I’m just gonna do it.&amp;#160; Here it goes:&lt;/p&gt;&lt;h3&gt;How do you associate a backlog item/bug/issue ID with a check-in?&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Add the “bugtraq:message” property to the root folder of your repository, and set it to something like “Backlog ID: %BUGID%”.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Yep, that’s it.&amp;#160; I know - crazy, right?&amp;#160; Next time you go to check in, you’ll see something like this:&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://lh5.ggpht.com/_sH3XWh6OzVE/SqCtj73BcuI/AAAAAAAAAG0/cE8OAnztCDk/s1600-h/image%5B16%5D.png&quot;&gt;&lt;img style=&quot;border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px&quot; title=&quot;image&quot; border=&quot;0&quot; alt=&quot;image&quot; src=&quot;http://lh3.ggpht.com/_sH3XWh6OzVE/SqCtkJ7-r7I/AAAAAAAAAG4/O25bS2j4SDE/image_thumb%5B8%5D.png?imgmax=800&quot; width=&quot;374&quot; height=&quot;419&quot; /&gt;&lt;/a&gt; &lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;For those of you who have never used &lt;a href=&quot;http://svnbook.red-bean.com/en/1.0/ch07s02.html&quot; target=&quot;_blank&quot;&gt;Subversion properties&lt;/a&gt;, the easiest way to add one is to right-click on your Subversion folder, then select “TortoiseSVN &amp;gt; Properties” which will bring you to the dialog where you can add and edit your Subversion properties.&amp;#160; All of the features I discuss in this post are unlocked using these properties.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Then, after filling in a value for the Backlog ID and hitting OK to complete the check-in, you can visit the history logs and see that TortoiseSVN has oh-so-nicely inserted the Backlog ID into your checkin comment for you, like so:&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://lh6.ggpht.com/_sH3XWh6OzVE/SqCtmKBhVVI/AAAAAAAAAG8/ErDvObW8PG4/s1600-h/image%5B4%5D.png&quot;&gt;&lt;img style=&quot;border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px&quot; title=&quot;image&quot; border=&quot;0&quot; alt=&quot;image&quot; src=&quot;http://lh4.ggpht.com/_sH3XWh6OzVE/SqCtmmfdtTI/AAAAAAAAAHA/7EutGK5qZTE/image_thumb%5B2%5D.png?imgmax=800&quot; width=&quot;398&quot; height=&quot;300&quot; /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;Some of you might be thinking, “But hey – I could have just typed that myself!”&amp;#160; Yeah, sure – if you wanna waste a bunch of time typing the same thing in every comment, this probably won’t be of much help to you… but wait – there’s more!&lt;/p&gt;&lt;h3&gt;Make that integration experience a little bit nicer&lt;/h3&gt;&lt;p&gt;For those of you who were underwhelmed with the first section, let’s dive a little deeper and check out some of the other bug tracking properties that TortoiseSVN has made available to us that allow us to customize this behavior:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;bugtraq&lt;/b&gt;:&lt;b&gt;url&lt;/b&gt; – now &lt;em&gt;this&lt;/em&gt; is the stuff you’ve been waiting for!&amp;#160; If you set this property with a URL pattern containing the %BUGID% placeholder, TortoiseSVN will be nice enough to turn those nifty little messages into &lt;strong&gt;direct links to your issue tracking system&lt;/strong&gt;!&amp;#160; Naturally, this link will be different for every issue tracking system, but assuming your system allows you link directly to an issue via it’s ID, this is a pretty sweet option.&amp;#160; Here’s an example:&amp;#160; &lt;br /&gt;
By setting the &lt;strong&gt;bugtraq:url &lt;/strong&gt;property to&lt;strong&gt; “&lt;/strong&gt;&lt;em&gt;&lt;a href=&quot;http://myversioncontrol/issues/%BUGID%&quot;&gt;http://myversioncontrol/issues/%BUGID%&lt;/a&gt;”&lt;/em&gt;, my previous history message (shown below) now contains a link directly into my issue tracking system! &lt;/li&gt;
&lt;/ul&gt;&lt;a href=&quot;http://lh4.ggpht.com/_sH3XWh6OzVE/SqCtm-70jBI/AAAAAAAAAHE/C9ue42moaTo/s1600-h/image%5B19%5D.png&quot;&gt;&lt;img style=&quot;border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px&quot; title=&quot;image&quot; border=&quot;0&quot; alt=&quot;image&quot; align=&quot;left&quot; src=&quot;http://lh5.ggpht.com/_sH3XWh6OzVE/SqCtnAOoA7I/AAAAAAAAAHI/pnKtV1O4r6I/image_thumb%5B11%5D.png?imgmax=800&quot; width=&quot;306&quot; height=&quot;160&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://lh6.ggpht.com/_sH3XWh6OzVE/SqCtnkR7zdI/AAAAAAAAAHM/xRpod1I8yEA/s1600-h/image%5B20%5D.png&quot;&gt;&lt;img style=&quot;border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px&quot; title=&quot;image&quot; border=&quot;0&quot; alt=&quot;image&quot; align=&quot;left&quot; src=&quot;http://lh3.ggpht.com/_sH3XWh6OzVE/SqCtn2UHv4I/AAAAAAAAAHQ/6fhMXspmwj4/image_thumb%5B12%5D.png?imgmax=800&quot; width=&quot;316&quot; height=&quot;238&quot; /&gt;&lt;/a&gt;   &lt;p&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;clear: both&quot;&gt;&lt;li&gt;&lt;b&gt;bugtraq:warnifnoissue&lt;/b&gt; – this awesome setting tells Tortoise to yell at the dev (shown to the right) if they haven’t provided an Issue #.&amp;#160; It’s purely a client-side setting and provides no server-side validation so it’s not going to &lt;em&gt;force&lt;/em&gt; the users to associate an issue #, but it sure is a nice reminder.&amp;#160; &lt;br /&gt;
Note:&amp;#160; If you really want to perform server-side validation, stay tuned – a post on that topic should be coming up soon! &lt;a href=&quot;http://lh4.ggpht.com/_sH3XWh6OzVE/SqCtoUva5dI/AAAAAAAAAHU/HmmJdhUoYuE/s1600-h/clip_image001%5B7%5D%5B6%5D.jpg&quot;&gt;&lt;img style=&quot;border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px&quot; title=&quot;clip_image001[7]&quot; border=&quot;0&quot; alt=&quot;clip_image001[7]&quot; align=&quot;left&quot; src=&quot;http://lh5.ggpht.com/_sH3XWh6OzVE/SqCtovIqBmI/AAAAAAAAAHY/O-kFMfVlbUU/clip_image001%5B7%5D_thumb%5B4%5D.jpg?imgmax=800&quot; width=&quot;351&quot; height=&quot;110&quot; /&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;ul style=&quot;clear: both&quot;&gt;&lt;li&gt;&lt;b&gt;bugtraq:append&lt;/b&gt; – if you’re like me and want the backlog/issue ID right at the beginning of the message instead of the end, you can set the “bugtraq:append” property to “false” so it &lt;b&gt;pre&lt;/b&gt;pends the ID snippet to the beginning of the log message instead of appending it to the end (as is the default behavior shown earlier).       &lt;br /&gt;
&lt;a href=&quot;http://lh4.ggpht.com/_sH3XWh6OzVE/SqCto17QBOI/AAAAAAAAAHc/yya-uTY297Y/s1600-h/clip_image001%5B5%5D%5B4%5D.jpg&quot;&gt;&lt;img style=&quot;border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px&quot; title=&quot;clip_image001[5]&quot; border=&quot;0&quot; alt=&quot;clip_image001[5]&quot; src=&quot;http://lh4.ggpht.com/_sH3XWh6OzVE/SqCtpEijObI/AAAAAAAAAHg/Dyje2Uw_tWE/clip_image001%5B5%5D_thumb%5B2%5D.jpg?imgmax=800&quot; width=&quot;341&quot; height=&quot;227&quot; /&gt;&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;ul style=&quot;clear: both&quot;&gt;&lt;li&gt;&lt;strong&gt;bugtraq:label&lt;/strong&gt; – if you go waaay back to the first screenshot in this post, you’ll see that the label for the Backlog ID input box had the awkward default value of “Bug-ID / Issue-Nr:”&amp;#160; This bugged the heck out of me, and I wanted to change it to match my message of “Backlog ID:”, and luckily the &lt;strong&gt;bugtraq:label&lt;/strong&gt; property let’s you do just that!&amp;#160;&amp;#160; I just set the value of &lt;strong&gt;bugtraq:label&lt;/strong&gt;=Backlog ID:, and I was good to go! &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Well, I hope you found these useful and that they help you in your quest to write better software.&amp;#160; As always, if you know of a better way to do this or have any comments, suggestions, or questions, please feel free to comment below.&lt;/p&gt;&lt;p&gt;Good luck, and happy coding!&lt;/p&gt;</description><link>http://jesschadwick.blogspot.com/2009/09/issue-tracking-integration-with.html</link><author>noreply@blogger.com (Jess Chadwick)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/_sH3XWh6OzVE/SqCtkJ7-r7I/AAAAAAAAAG4/O25bS2j4SDE/s72-c/image_thumb%5B8%5D.png?imgmax=800" height="72" width="72"/><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-5477073899087090192</guid><pubDate>Sun, 26 Jul 2009 03:36:00 +0000</pubDate><atom:updated>2009-07-25T23:36:05.336-04:00</atom:updated><title>On to the Next Set of Challenges!</title><description>&lt;p&gt;You won’t see many of my blog entries get too personal, largely due to the fact that I am a relatively private person to start with, but also because this is supposed to be a technical blog.&amp;#160; That said, I wanted to break stride for one post and speak to the fact that I am leaving Infragistics and have now moved on to new challenges by deciding to start consulting.&lt;/p&gt;  &lt;p&gt;It has been a great 3.5 years at Infragistics for me and I can not speak highly enough of my time there.&amp;#160; Never before have I worked in an environment so rich with knowledge, intensity, and passion.&amp;#160; It is an environment of productivity; it’s where teams of great minds and talented professionals join forces to produce amazing results, wasting no time in shipping amazing stuff.&amp;#160; It’s also fast-paced: a few of us had at one point discussed the concept of “Infragistics Time” joking that one or two days at IG would be the equivalent of up to a week anywhere else… and I’m not just talking deliverables.&amp;#160; To put it another way, I joined Infragistics as a Senior Web Developer, but after only one year in, I’d learned more and gained more experience than the entire rest of my career combined.&lt;/p&gt;  &lt;p&gt;I didn’t do all this learning in a silo.&amp;#160; Reporting to the guy I would end up calling my mentor - &lt;a href=&quot;http://www.ambroselittle.com/&quot; target=&quot;_blank&quot;&gt;Ambrose Little&lt;/a&gt; - was a crucial aspect of my development.&amp;#160; Until you’ve actually met him (and if you haven’t had the pleasure, the least you can do is &lt;a href=&quot;http://twitter.com/ambroselittle&quot; target=&quot;_blank&quot;&gt;follow him on Twitter&lt;/a&gt;!), it’s hard to describe just how awesome this guy is.&amp;#160; Crazy smart, level-headed, patient, and open-minded are just a few words that come to mind.&amp;#160; He guided both me and our group to continuously increasing levels of success… and he was really only doing it “part-time”, having another whole set of responsibilities above and beyond managing me and the website(s)!&amp;#160; It was also through this team that Ambrose led that I was able to foster deep personal and professional relationships with &lt;a href=&quot;http://twitter.com/ToddSnyder&quot; target=&quot;_blank&quot;&gt;Todd Snyder&lt;/a&gt; and &lt;a href=&quot;http://twitter.com/edblankenship&quot; target=&quot;_blank&quot;&gt;Ed Blankenship&lt;/a&gt; – two guys that I guarantee will continue to be two of my most valuable friends and colleagues for the rest of my professional (and personal!) life.&lt;/p&gt;  &lt;p&gt;As an active supporter of the .NET community, Infragistics also introduced me to the amazing rewards of community involvement.&amp;#160; In a matter of months I had gone from never having attended a local user group meeting to becoming a presenter and eventually assuming leadership of or local group, &lt;a href=&quot;http://www.njdotnet.net&quot; target=&quot;_blank&quot;&gt;NJDOTNET&lt;/a&gt; and later earning Microsoft’s MVP award!&amp;#160; This was all great fun, but I only recently realized just how deeply this involvement had affected me when my recent job search had me writing out my professional priorities and “community involvement” emerged as #1!&amp;#160; And, I owe all of this to Infragistics’ support, as well as trying to follow in the footsteps of both Ambrose and Jason Beres… which is not an easy thing to do!&lt;/p&gt;  &lt;p&gt;I didn’t mean for this post to be a biography of my tenure at Infragistics, and as such I am focusing on those with whom I worked the longest and who had the deepest impact on my life. Unfortunately, that means leaving out the myriad other great folks that I was lucky enough to meet and work with.&amp;#160; So, I’m sorry that I am leaving so many of you out, but you know who you are and – even if I wasn’t able to mention you specifically – thank you for making my time at Infragistics a great one!&amp;#160; Farewell everyone – I’m sure I’ll see you all again sooner or later!&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font style=&quot;background-color: #ffffff&quot;&gt;&lt;strong&gt;Shameless Plug:&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font style=&quot;background-color: #ffffff&quot;&gt;So…&amp;#160; as you may have noticed, I opened up this post by mentioning that I decided to start consulting.&amp;#160; That means that if you’re looking for some help to knock out that next awesome project of yours, &lt;strong&gt;please feel free to contact me!&lt;/strong&gt;&amp;#160; &lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font style=&quot;background-color: #ffffff&quot;&gt;If you’re interested, here’s a link to &lt;a href=&quot;http://www.jesschadwick.com/Resume.docx&quot; target=&quot;_blank&quot;&gt;my resume in Word 2007 format&lt;/a&gt;.&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;  </description><link>http://jesschadwick.blogspot.com/2009/07/on-to-next-set-of-challenges.html</link><author>noreply@blogger.com (Jess Chadwick)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-5134514116012825791</guid><pubDate>Sun, 05 Jul 2009 07:12:00 +0000</pubDate><atom:updated>2011-06-07T13:30:29.602-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">review</category><title>Book Review:  NHibernate in Action</title><description>&lt;p&gt;Over a year ago I wrote about my &lt;a href=&quot;http://jesschadwick.blogspot.com/2008/04/nhibernate-lazy-loading-snafu.html&quot; target=&quot;_blank&quot;&gt;NHibernate Lazy Loading Snafu&lt;/a&gt; and in that blog post it was pretty clear I was mostly clueless when it came to NHibernate.&amp;#160; Unfortunately, that hasn’t changed much in the past year, so I was incredibly eager to get my hands on the new Manning book, &lt;a href=&quot;http://www.amazon.com/gp/product/1932394923?ie=UTF8&amp;amp;tag=creativerea0a-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=1932394923&quot; target=&quot;_blank&quot;&gt;NHibernate in Action&lt;/a&gt;.&amp;#160; Believe me, it did not disappoint.&lt;/p&gt;&lt;p&gt;I’d argue that this book may be more appropriately naming something along the lines of “ORM in Action (with a focus on NHibernate)” because it is not only a bible for understanding and using NHibernate, but for ORM concepts in general!&amp;#160; The authors skillfully intertwine detailed and insightful discussion of general database, ORM, and enterprise development concepts with the nitty-gritty implementation details of NHibernate, all in an easy-to-read manner.&amp;#160; Beginning with a tour of many of the various ORM (and ORM-ish) solutions available to .NET developers and ending with a few chapters dedicated to discussing best practices of enterprise application development, this is a very well-rounded book that is easily digested by developers of pretty much any skill level.&amp;#160; I knew only high-level details about NHibernate and had a few mis-guided attempts at implementing it by myself prior to reading this book, but now I feel incredibly confident that I will be able to create plenty of NHibernate-driven applications with ease.&amp;#160; Another great benefit is the comfort I get from knowing that when I hit any more snafus in the future, it is obviously that this book will be there as a solid reference to help get me through.&lt;/p&gt;&lt;p&gt;The cons?&amp;#160; It&#39;d be nice if the book discussed NHibernate 2 &amp;amp; .NET 3.x functionality (like LINQ-to-NHibernate), but I think those expectations are somewhat unrealistic. Because of its open source nature, NHibernate is a living organism with stark contrast to a published book. Due to this contrast, I am more interested in a text that can explain the fundamental concepts than an incredibly in-depth (and quickly obsolete!) explanation of the technical implementation of those concepts.&lt;/p&gt;&lt;p&gt;When it comes down to it, this is a great book that delivers on its promises and provides a comprehensive look at NHibernate in Action and how you can get it working for you.&amp;#160; I’m just gonna come right out and say it – this is the &lt;strong&gt;NHibernate Bible&lt;/strong&gt;.&lt;/p&gt;</description><link>http://jesschadwick.blogspot.com/2009/07/book-review-nhibernate-in-action.html</link><author>noreply@blogger.com (Jess Chadwick)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-7666720060394767064</guid><pubDate>Fri, 12 Jun 2009 06:52:00 +0000</pubDate><atom:updated>2009-06-12T02:52:39.599-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ASP.NET MVC</category><title>Using WebForms Controls in ASP.NET MVC: The Unholy (and Cost-Effective!) Union</title><description>&lt;p&gt;My buddy and fellow Infragisticsian, Craig Shoemaker, &lt;a href=&quot;http://community.infragistics.com/blogs/craig_shoemaker/archive/2009/06/11/netadvantage-asp-net-in-asp-net-mvc.aspx&quot; target=&quot;_blank&quot;&gt;posted a blog post&lt;/a&gt; and &lt;a href=&quot;http://community.infragistics.com/aspnet/media/p/98918.aspx&quot; target=&quot;_blank&quot;&gt;a video on our Community site&lt;/a&gt; showing how you can use the current Infragistics Web controls in ASP.NET MVC.&amp;#160; Craig’s posts are invaluable because he shows you how you can &lt;strong&gt;leverage your current investment&lt;/strong&gt; in the WebForms controls &lt;em&gt;you’ve already purchased&lt;/em&gt; by using them in your ASP.NET MVC applications.&lt;/p&gt;  &lt;p&gt;I worked with Craig on some parts of the sample he’s discussing (which is to say that I wrote about a dozen lines of code and then sat back while he did the rest…) and I can say that we’re not trying to play any tricks here – we’re not trying to &lt;a href=&quot;http://en.wikipedia.org/wiki/Snake_oil&quot; target=&quot;_blank&quot;&gt;sell you snake oil&lt;/a&gt;.&amp;#160; In fact, in his post, he admits almost immediately that mixing WebForms server controls and MVC is an “unholy union” – something I (and I’m sure most other MVC-ers) whole-heartedly agree with. &lt;/p&gt;  &lt;p&gt;We all know that WebForms controls are not &amp;quot;MVC controls&amp;quot; (a concept which has yet to be clearly defined) and vice-versa.&amp;#160; However, that’s not to say that the product offerings available &lt;em&gt;today&lt;/em&gt; can’t offer you a good of value if applied deliberately and judiciously.&amp;#160; That subjective phrase, “deliberately and judiciously”, is exactly what Craig does a great job of addressing with these posts by offering guidance on when, where, and how you might use these existing controls.&amp;#160; Hopefully, this guidance can help get you through until there are true “MVC controls” available for you to use.&amp;#160; After all, you may need to make some compromises and sacrifices along the way, but it still beats writing this stuff from scratch!&lt;/p&gt;  &lt;p&gt;But hey - don’t let me jam my opinions down your throat.&amp;#160; What do &lt;em&gt;you&lt;/em&gt; think?&amp;#160; Is this “unholy union” so unholy that it’s actually blasphemous?&amp;#160; Do you like this approach?&amp;#160; Are there any ways it could be better?&amp;#160; The only way the situation can improve is if we developers all constructively contribute to the larger discussion about what &lt;em&gt;we&lt;/em&gt; want to see happen in this space… so let’s get it started!&lt;/p&gt;  </description><link>http://jesschadwick.blogspot.com/2009/06/using-webforms-controls-in-aspnet-mvc.html</link><author>noreply@blogger.com (Jess Chadwick)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-916857720309146962</guid><pubDate>Thu, 21 May 2009 00:41:00 +0000</pubDate><atom:updated>2009-05-20T21:35:58.255-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ASP.NET MVC</category><category domain="http://www.blogger.com/atom/ns#">Silverlight</category><title>Helping Silverlight and ASP.NET MVC Work Together</title><description>&lt;p&gt;If you’ve worked with Silverlight you’ve probably used the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/cc838274(VS.95).aspx&quot; target=&quot;_blank&quot;&gt;WebForms control that comes with the Silverlight SDK&lt;/a&gt;.&amp;#160; Technically, you can still continue to use this control with ASP.NET MVC, you’ll just need to add the &lt;strong&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/bb398863.aspx&quot; target=&quot;_blank&quot;&gt;ScriptManager&lt;/a&gt;&lt;/strong&gt; with &lt;strong&gt;EnablePartialRendering=”false”&lt;/strong&gt; like so:&lt;/p&gt;  &lt;pre class=&quot;xhtml&quot; name=&quot;code&quot;&gt;    &amp;lt;form id=&amp;quot;form&amp;quot; runat=&amp;quot;server&amp;quot;&amp;gt;&lt;br /&gt;        &amp;lt;asp:ScriptManager runat=&amp;quot;server&amp;quot; EnablePartialRendering=&amp;quot;false&amp;quot; /&amp;gt;&lt;br /&gt;        &amp;lt;asp:Silverlight ID=&amp;quot;MySLApp&amp;quot; runat=&amp;quot;server&amp;quot; &lt;br /&gt;            MinimumVersion=&amp;quot;2.0.31005.0&amp;quot;&lt;br /&gt;            Source=&amp;quot;~/ClientBin/MySLApp.xap&amp;quot;&lt;br /&gt;            OnPluginLoaded=&amp;quot;pluginLoaded&amp;quot; &lt;br /&gt;            InitParameters=&amp;quot;myParam=true&amp;quot;&lt;br /&gt;            Width=&amp;quot;415&amp;quot; Height=&amp;quot;280&amp;quot; /&amp;gt;&lt;br /&gt;    &amp;lt;/form&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Sure, this &lt;em&gt;technically&lt;/em&gt; still works, but it&#39;s not very MVC-like, is it? The new ASP.NET MVC parlance is filled with code snippets and &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/bb383977.aspx&quot; target=&quot;_blank&quot;&gt;Extension Methods&lt;/a&gt;, not Server Controls! We&#39;ll instead want something that looks like this:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;c-sharp&quot; name=&quot;code&quot;&gt;&amp;lt;%= Html.Silverlight(&amp;quot;~/ClientBin/MySLApp.xap&amp;quot;, new Size(415, 280),&lt;br /&gt;                     new {&lt;br /&gt;                            MinimumVersion=&amp;quot;2.0.31005.0&amp;quot;,&lt;br /&gt;                            OnPluginLoaded=&amp;quot;pluginLoaded&amp;quot;, &lt;br /&gt;                            InitParameters=&amp;quot;myParam=true&amp;quot;&lt;br /&gt;                         }) %&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;&lt;p&gt;Personally, I think the Extension Method way looks a lot cleaner and feels a lot more natural in MVC Land. However, if you don&#39;t really see a difference between those two, or see the difference and don&#39;t really care one way or another, feel free to continue using the WebForms example and don&#39;t bother reading any further. Just be sure to include that &lt;strong&gt;ScriptManager&lt;/strong&gt;, make sure you set &lt;strong&gt;EnablePartialRendering=&amp;quot;false&amp;quot;&lt;/strong&gt; and you&#39;ll be ready to go. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Creating the Extension Methods&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;I&#39;m assuming if you&#39;re still reading that you not only dig the &lt;strong&gt;Html.Silverlight&lt;/strong&gt; Extension Method above, but you&#39;re more interested to see how it works! Well, it&#39;s pretty simple, really... &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Before I show you the code, let&#39;s take a step back and reevaluate what I&#39;m really looking to do here. Sure, I said before that I wanted to replace the Silverlight WebForms control, but what I really want to do is duplicate the HTML it renders (since that&#39;s what it&#39;s all about, right?). So, here&#39;s the markup I&#39;m shooting for:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;xhtml&quot; name=&quot;code&quot;&gt;    &amp;lt;object data=&amp;quot;data:application/x-silverlight-2,&amp;quot; type=&amp;quot;application/x-silverlight-2&amp;quot; height=&amp;quot;280px&amp;quot; width=&amp;quot;415px&amp;quot;&amp;gt;&lt;br /&gt;        &amp;lt;param name=&#39;minRuntimeVersion&#39; value=&#39;2.0.31005.0&#39; /&amp;gt;&lt;br /&gt;        &amp;lt;param name=&#39;autoUpgrade&#39; value=&#39;true&#39; /&amp;gt;&lt;br /&gt;        &amp;lt;param name=&#39;source&#39; value=&#39;/ClientBin/LogUploader.xap&#39; /&amp;gt;&lt;br /&gt;        &amp;lt;param name=&#39;OnPluginLoaded&#39; value=&#39;pluginLoaded&#39; /&amp;gt;&lt;br /&gt;        &amp;lt;param name=&#39;InitParameters&#39; value=&#39;customParam=true&#39; /&amp;gt;&lt;br /&gt;        &amp;lt;!-- [ Silverlight not installed message here ] --&amp;gt;&lt;br /&gt;    &amp;lt;/object&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Pretty straighforward, right? Basically, you&#39;ve got the &amp;lt;object&amp;gt; tag with some pretty standard attributes, then a bunch of &amp;lt;param&amp;gt; tags inside, filled with name/value pairs. Should be pretty simple to reproduce - let&#39;s a shot at it. The way I went about it was actually just copying and pasting the above snippet into my C# class and replacing each line with the appropriate C# calls to generate it. Here&#39;s what it looks like:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;c-sharp&quot; name=&quot;code&quot;&gt;    public static string Silverlight(this HtmlHelper html, string relativeControlPath, &lt;br /&gt;                                     Size size, object parameters)&lt;br /&gt;    {&lt;br /&gt;        var controlPath = VirtualPathUtility.ToAbsolute(relativeControlPath);&lt;br /&gt;&lt;br /&gt;        var objectTag = new TagBuilder(&amp;quot;object&amp;quot;)&lt;br /&gt;        {&lt;br /&gt;            Attributes = {&lt;br /&gt;                            {&amp;quot;data&amp;quot;, &amp;quot;data:application/x-silverlight-2,&amp;quot;},&lt;br /&gt;                            {&amp;quot;type&amp;quot;, &amp;quot;application/x-silverlight-2&amp;quot;},&lt;br /&gt;                            {&amp;quot;width&amp;quot;, size.Width.ToString()},&lt;br /&gt;                            {&amp;quot;height&amp;quot;, size.Height.ToString()},&lt;br /&gt;                        }&lt;br /&gt;        };&lt;br /&gt;&lt;br /&gt;        var innerHtml = new StringBuilder();&lt;br /&gt;        innerHtml.AppendFormat(ParamHtmlFormatString, &amp;quot;minRuntimeVersion&amp;quot;, &amp;quot;2.0.31005.0&amp;quot;);&lt;br /&gt;        innerHtml.AppendFormat(ParamHtmlFormatString, &amp;quot;autoUpgrade&amp;quot;, &amp;quot;true&amp;quot;);&lt;br /&gt;        innerHtml.AppendFormat(ParamHtmlFormatString, &amp;quot;source&amp;quot;, controlPath);&lt;br /&gt;&lt;br /&gt;        foreach (var param in new RouteValueDictionary(parameters))&lt;br /&gt;            innerHtml.AppendFormat(ParamHtmlFormatString, param.Key, param.Value);&lt;br /&gt;&lt;br /&gt;        innerHtml.AppendLine(&amp;quot;\n&amp;lt;!-- [ Silverlight not installed message here ] --/&amp;gt;&amp;quot;);&lt;br /&gt;&lt;br /&gt;        objectTag.InnerHtml = innerHtml.ToString();&lt;br /&gt;&lt;br /&gt;        return objectTag.ToString();&lt;br /&gt;    }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;There are a couple interesting things going on in this snippet. First off, I start by resolving the absolute path to the Silverlight XAP; this needs to be resolved because this URL will be sent down to the client, and an application-relative path (starting with &amp;quot;~/&amp;quot;) does us no good in a browser. Next, I use the new &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/system.web.mvc.tagbuilder_members.aspx&quot; target=&quot;_blank&quot;&gt;System.Web.Mvc.TagBuilder&lt;/a&gt;&lt;strong&gt;&lt;/strong&gt; class which (as Reflector shows us) is what the framework uses to construct HTML in its Extension Methods (such as Html.ActionLink, Html.Form, etc.). I also supply it with a few standard attributes. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote style=&quot;height: 50px&quot;&gt;&lt;img style=&quot;border-right-width: 0px; margin: -8px 20px 0px 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px&quot; border=&quot;0&quot; align=&quot;left&quot; src=&quot;http://jchad.mediafreak.org/d/images/rabid_hamster.jpg&quot; width=&quot;45&quot; height=&quot;60&quot; /&gt; &lt;br /&gt;&lt;br /&gt;  &lt;p style=&quot;margin-top: 10px&quot;&gt;Note that I&#39;ve hard-coded the Silverlight 2 version info and MIME type... I&#39;m not recommending that you actually do this - it will most certainly attract rabid hamsters to come and eat your code - but for simplicity&#39;s sake in doing it in this example anyway.&lt;/p&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;By this point, you&#39;ve probably got a pretty good idea about what&#39;s going on, but I want to point out one last thing - the usage of &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/system.web.routing.routevaluedictionary.aspx&quot; target=&quot;_blank&quot;&gt;System.Web.Routing.RouteValueDictionary&lt;/a&gt;&lt;strong&gt;&lt;/strong&gt;. Again taking a cue from the MVC framework itself, I’m using this incredibly helpful (albeit poorly named) class from the new System.Web.Routing namespace to convert anonymous types into a set of key-value pairs that we can then use in our Silverlight method to dynamically add parameters (which are, conveniently enough, simply name/value pairs!). &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;After it&#39;s all done setting everything up, the Silverlight method asks the TagBuilder to render out the markup for our new object tag and its children, and with that, we&#39;re pretty much done! &lt;/p&gt;  </description><link>http://jesschadwick.blogspot.com/2009/05/helping-silverlight-and-aspnet-mvc-work.html</link><author>noreply@blogger.com (Jess Chadwick)</author><thr:total>6</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-2734221551840094336</guid><pubDate>Sat, 16 May 2009 17:18:00 +0000</pubDate><atom:updated>2009-05-16T13:22:45.954-04:00</atom:updated><title>Windows 7 Training and Informational Resources</title><description>&lt;p&gt;Microsoft Learning has just launched three free eLearning Clinics that you or your friends and co-workers may be interested in checking out. These Clinics are geared towards three different audiences, and focus on introducing new features and functionality to those interested in simply learning more about the OS or those that are already considering deploying in the near future. &lt;/p&gt;  &lt;p&gt;&lt;img style=&quot;display: inline; margin-left: 0px; margin-right: 0px&quot; align=&quot;right&quot; src=&quot;http://bit.ly/w5Tjv?r=td&quot; /&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href=&quot;http://www.microsoft.com/learning/elearning/course/10125.mspx&quot;&gt;What’s New in Windows 7 for Consumers&lt;/a&gt; (1 Hour) &lt;/li&gt;    &lt;li&gt;&lt;a href=&quot;http://www.microsoftelearning.com/eLearning/gotoResource.aspx?resourceId=38b7b771-a840-4bc6-a518-c8cf79c9a24c&amp;amp;language=en-US&amp;amp;country=US&amp;amp;locale=en-US&amp;amp;style=Learning&quot;&gt;What’s New in Windows 7 for IT Professionals&lt;/a&gt; (2 Hours) &lt;/li&gt;    &lt;li&gt;&lt;a href=&quot;http://www.microsoftelearning.com/eLearning/gotoResource.aspx?resourceId=0d4cdfd6-b1ad-4a91-899a-7866f498735e&amp;amp;language=en-US&amp;amp;country=US&amp;amp;locale=en-US&amp;amp;style=Learning&quot;&gt;What’s New in Windows 7 for Information Workers&lt;/a&gt; (2 Hours) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Also, in case you are interested in more Windows 7 training and skills development information, the new &lt;a href=&quot;http://www.microsoft.com/learning/windows-7/default.mspx&quot;&gt;Windows 7 Learning Portal&lt;/a&gt; is now live as well! This site is currently showcasing great readiness content, including &lt;a href=&quot;http://www.microsoft.com/learning/snacks/default.mspx#WIN7&quot;&gt;7 Silverlight Learning Snacks&lt;/a&gt;, &lt;a href=&quot;http://www.microsoft.com/learning/windows-7/default.mspx#BOOKS&quot;&gt;free sample chapters from upcoming MS Press Books&lt;/a&gt;, &lt;a href=&quot;http://www.microsoft.com/learning/windows-7/default.mspx#PLANS&quot;&gt;Learning Plans&lt;/a&gt;, &lt;a href=&quot;http://www.microsoft.com/learning/windows-7/default.mspx#CLASSROOM&quot;&gt;links to clinics/HOLs&lt;/a&gt; and more. If you care to check it out, click on any of those links or visit the homepage: &lt;b&gt;&lt;/b&gt;&lt;a href=&quot;http://www.microsoft.com/learning/windows-7/default.mspx&quot;&gt;http://www.microsoft.com/learning/windows-7/default.mspx&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Enjoy, and let me know if you find anything helpful to you!&lt;/p&gt;  </description><link>http://jesschadwick.blogspot.com/2009/05/windows-7-training-and-informational.html</link><author>noreply@blogger.com (Jess Chadwick)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-7774276248364936945</guid><pubDate>Thu, 14 May 2009 04:02:00 +0000</pubDate><atom:updated>2009-05-14T01:52:03.380-04:00</atom:updated><title>Real Software Artisans Ship</title><description>&lt;p&gt;In one of his amazing screenplays, &lt;a href=&quot;http://www.imdb.com/title/tt0104348/&quot;&gt;Glengarry Glen Ross&lt;/a&gt;, David Mamet sends in a rock star salesman (played by Alec Baldwin) to antagonize an office of poorly performing salesmen.&amp;#160; He reminds them of a core tenet of sales: “A-B-C: Always Be Closing”.&amp;#160; Otherwise, First prize is a Cadillac El Dorado; Second Prize is a set of steak knives; Third prize is you’re fired.&lt;/p&gt;  &lt;div style=&quot;float: right; margin-left: 10px&quot;&gt;&lt;object width=&quot;340&quot; height=&quot;285&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/y-AXTx4PcKI&amp;amp;hl=en&amp;amp;fs=1&amp;amp;rel=0&amp;amp;color1=0x006699&amp;amp;color2=0x54abd6&amp;amp;border=1&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;http://www.youtube.com/v/y-AXTx4PcKI&amp;amp;hl=en&amp;amp;fs=1&amp;amp;rel=0&amp;amp;color1=0x006699&amp;amp;color2=0x54abd6&amp;amp;border=1&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;340&quot; height=&quot;285&quot;&gt;&lt;/embed&gt;&lt;/object&gt;    &lt;p style=&quot;margin-left: 15px; clear: both&quot;&gt;&lt;strong&gt;Glengarry Glen Ross&lt;/strong&gt; (warning: NSFW - language)&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Steve Jobs says, “real artists ship.”&amp;#160; Now, I’m no artist, but code undoubtedly contains structure and style. When we developers &lt;a href=&quot;http://en.wikipedia.org/wiki/Software_Craftsmanship&quot; target=&quot;_blank&quot;&gt;care enough about our craft&lt;/a&gt; to consider this structure and style during the course of development, I don’t think it’d be too far off to consider ourselves an artist of sorts.&amp;#160; Or, if you want to sound more original (or pretentious) you might call us “Artisans”.&lt;/p&gt;  &lt;p&gt;Of course, Steve Jobs built a booming hardware and software empire on the motto of “real artists ship,” so I don’t think it’s too far of a stretch to embrace and extend—er, I mean &lt;em&gt;paraphrase&lt;/em&gt; Steve’s great line into, “&lt;strong&gt;real software artisans ship&lt;/strong&gt;.”&amp;#160; &lt;a href=&quot;http://en.wikipedia.org/wiki/Agile_software_development&quot; target=&quot;_blank&quot;&gt;Agile methodologies&lt;/a&gt; preach similarly: “A-B-S:&amp;#160; Always Be Shipping.”&amp;#160; If you’re practicing Agile properly, you are constantly shipping; you are shipping something at the end of every iteration.&amp;#160; Even if your customers/clients aren’t actually getting their hands on it and using it, you should still be “shipping” it.&amp;#160; You should strive to constantly and consistently have something that works. Test-Driven Development helps a great deal with this because, &lt;a title=&quot;This keynote is pretty long, and he says it pretty far in... I&amp;#39;d recommend watching the whole thing regardless.&quot; href=&quot;http://railsconf.blip.tv/file/2089545/&quot;&gt;as Uncle Bob says&lt;/a&gt;, if you’re practicing it zealously you never go more than a few minutes without everything working.&lt;/p&gt;  &lt;p&gt;Ok, so what about the &lt;em&gt;real world&lt;/em&gt;?&amp;#160; I know, I know – there are plenty of Agile shops and TDD zealots working in the “real world”, but even the Agilists will (regretfully) admit that a majority of the software development industry is simply not following these practices (and some aren’t following any practices at all!).&amp;#160; But, does not being an active Agile practitioner preclude you from constantly and consistently shipping?&amp;#160; &lt;/p&gt;  &lt;p&gt;There is obviously a vast difference between the quick iterations preached by Agile methodologies and a &lt;a href=&quot;http://en.wikipedia.org/wiki/Death_march_(software_development)&quot; target=&quot;_blank&quot;&gt;Death March&lt;/a&gt;, I’d like to think that even if you or your team are following a Waterfall or SCRUM-fall or even a Free-fall approach that there is still some room for “constantly shipping”.&amp;#160; Sure, you might have to loosen the definition of “constantly” to fit your reality… but it’s doable!&amp;#160; Following – or better yet, adapting – even some of the Agile methodologies is a great first step (for more on that, check out my follow-up post &lt;a href=&quot;http://jesschadwick.blogspot.com/2009/05/some-tips-on-how-to-ship-better-code.html&quot; target=&quot;_blank&quot;&gt;Some Tips on How to Ship Better Code&lt;/a&gt;).&amp;#160; More importantly, just keeping the goal of a shipping product instead of that next big feature in mind will probably help more than anything.&lt;/p&gt;  &lt;p&gt;What do you think?&amp;#160; Have you been able to effectively employ any techniques in a Waterfall-ish environment to help improve your ability to ship regularly? Is this entire post just full of hot air?&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Note:&amp;#160; This post was heavily influenced by &lt;a href=&quot;http://www.infoq.com/presentations/archaeopteryx-bowkett&quot; target=&quot;_blank&quot;&gt;Giles Bowkett’s incredibly awesome presentation at RubyFringe&lt;/a&gt;.&amp;#160; You &lt;strong&gt;must, must, must&lt;/strong&gt; watch it!!&lt;/p&gt;&lt;/blockquote&gt;  </description><link>http://jesschadwick.blogspot.com/2009/05/real-software-artisans-ship.html</link><author>noreply@blogger.com (Jess Chadwick)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-5669932638341604103</guid><pubDate>Thu, 14 May 2009 03:27:00 +0000</pubDate><atom:updated>2009-05-14T15:20:35.974-04:00</atom:updated><title>Some Tips on How to Ship Better Code</title><description>&lt;p&gt;In my last post, I pontificated about the notion that &lt;a href=&quot;http://jesschadwick.blogspot.com/2009/05/real-software-artisans-ship.html&quot;&gt;Real Software Artists Ship&lt;/a&gt;.&amp;#160; But, I’ve got to take a step back and admit something – in that last post, I was full of crap.&amp;#160; I don’t really consider myself an “Agilist”, nor do I come anywhere close to zealousness when it comes to TDD, but I have studied (and I use the term loosely!) these movements for some time now and have been able to adopt many of them into my daily grind with varying degrees of success.&amp;#160; &lt;/p&gt;  &lt;p&gt;Here are a few that I have found to be the most helpful in shipping better code as fast as possible:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;Use Source Control:&lt;/strong&gt;&amp;#160; I originally didn’t have this listed until I just had to come back and put it as #1.&amp;#160; I’m sure you’re already doing this, but I just had to say it anyway.&amp;#160; If you’re not using source control, &lt;a href=&quot;http://lh5.ggpht.com/_sH3XWh6OzVE/SguPo95GPnI/AAAAAAAAAGo/Y_JINlTE6vQ/s1600-h/zombie_hamsters1%5B2%5D.jpg&quot; target=&quot;_blank&quot;&gt;rabid hamsters&lt;/a&gt; will eat your code and there is nothing you will be able to do about it. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Unit Testing&lt;/strong&gt;:&amp;#160; What always seems to put everyone off about TDD is the seemingly massive amount of additional work it adds and the recommended zealousness with which you should adhere to it. To those complaints I say: obviously it’s more work; nobody’s debating that.&amp;#160; But, the ROI of having a suite of regression tests alone is so incredibly high it’s foolish not to do it. And, if you’re not keen on religiously adhering to a rigid development process of not writing a line of production code that’s not backed by a test, then don’t do it… but do seriously consider writing a least a few tests to cover the &lt;strong&gt;core functionality&lt;/strong&gt; of your code at the very least.&amp;#160; Writing tests after the fact still offers significant value, even if you aren’t enjoying the full suite of benefits that true TDD has to offer. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Continuous Integration (CI) Builds&lt;/strong&gt;:&amp;#160; At my last job, a co-worker of mine had a sticker affixed to his monitor proudly proclaiming, “&lt;a href=&quot;http://www.codinghorror.com/blog/archives/000818.html&quot;&gt;It works on my machine&lt;/a&gt;.”&amp;#160; Even if you are a one-developer shop, the benefits of ensuring that you’ve successfully checked in everything needed to build your application are pretty spectacular.&amp;#160; This is so very relevant because the fact is – one-developer shop or not – your production environment is &lt;strong&gt;not&lt;/strong&gt; your machine (or if it is, well, I don’t know what to say… stop doing that? Pretty please?).&amp;#160; Also, if you’ve already got unit tests from the previous recommendation, you’ll find that they go very well with CI Builds.&amp;#160; They go beyond a simple compile to actually running your full suite of unit tests to exercise your code every time, which is a huge win! &lt;a href=&quot;http://www.codinghorror.com/blog/archives/000818.html&quot; target=&quot;_blank&quot;&gt;&lt;img title=&quot;works-on-my-machine-starburst&quot; style=&quot;border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; margin-left: 0px; margin-right: 0px; border-right-width: 0px&quot; height=&quot;96&quot; alt=&quot;works-on-my-machine-starburst&quot; src=&quot;http://lh4.ggpht.com/_sH3XWh6OzVE/SguPpZK3xkI/AAAAAAAAAGw/EmGh996ofgk/works-on-my-machine-starburst%5B8%5D.png?imgmax=800&quot; width=&quot;100&quot; align=&quot;right&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;       &lt;blockquote&gt;&lt;strong&gt;Your company doesn&#39;t have a CI server? Start one on your machine!&lt;/strong&gt;         &lt;br /&gt;This may sound contrary to avoiding the &amp;quot;Works on my machine&amp;quot; syndrome, but having a continuous integration server - even on your own machine - is better than nothing at all. You may not be testing your code on another machine, but you are at least testing it outside of your working codebase and are still being forced to run your unit tests at regular intervals, which are pretty big wins regardless of which machine they&#39;re occurring on.&lt;/blockquote&gt;   &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Use a Refactoring Tool (Liberally):&lt;/strong&gt;&amp;#160; There are some bugs that just never should have happened.&amp;#160; I’m talking about things like existing code that worked until you wanted to move it into its own method – now it’s throwing null reference exceptions because you forgot to initialize that one variable.&amp;#160; Now, I’m not saying that these tools will eliminate this scenario, but they will make it much more difficult to achieve.&amp;#160; Interestingly enough, for those tools like &lt;a href=&quot;http://www.jetbrains.com/resharper/download/&quot; target=&quot;_blank&quot;&gt;ReSharper&lt;/a&gt; that provide suggestions on improving your code, I found that I was actually &lt;em&gt;learning&lt;/em&gt; some things while using these tools!&amp;#160; At the very least, those suggestions really help encourage you to clean up your code by acting like a nagging parent - “are you really going to leave this like this? This is embarrassing!”&amp;#160; Course, unlike the nagging parent, if you disagree with the suggestion, you can just turn it off! &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Those are my main tips.&amp;#160; What are some of yours?&lt;/p&gt;  </description><link>http://jesschadwick.blogspot.com/2009/05/some-tips-on-how-to-ship-better-code.html</link><author>noreply@blogger.com (Jess Chadwick)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/_sH3XWh6OzVE/SguPpZK3xkI/AAAAAAAAAGw/EmGh996ofgk/s72-c/works-on-my-machine-starburst%5B8%5D.png?imgmax=800" height="72" width="72"/><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-8766725502071182727</guid><pubDate>Sun, 03 May 2009 07:01:00 +0000</pubDate><atom:updated>2009-05-06T22:02:00.399-04:00</atom:updated><title>Leverage ASP.NET Control Adapters for a (slightly) Better UX</title><description>&lt;p&gt;If you’re anything like me, you’ve heard of &lt;a href=&quot;http://msdn.microsoft.com/en-us/magazine/cc163543.aspx&quot; target=&quot;_blank&quot;&gt;ASP.NET Control Adapters&lt;/a&gt;, but had just dismissed them as a tool that CSS enthusiasts and control freaks could use to make the Web Forms controls render out exactly the way they wanted.&amp;#160; Wanted a &amp;lt;div&amp;gt; instead of a &amp;lt;table&amp;gt; layout? Use a Control Adapter!&amp;#160; Want to… oh, I can’t even come up with a second one.&amp;#160; Point is, until recently I’d basically been dismissing Control Adapters as one of those extension points that the ASP.NET Framework offers, but nobody really has to use to get their usual work done.&amp;#160; Actually, I still pretty much feel that way, but I did recently come with what I think is a pretty good application for a Control Adapter.&amp;#160; I’ll explain it below you let me know what you think!&lt;/p&gt;  &lt;h3&gt;Pet Peeve:&amp;#160; Drop-Downs with a Single Selection&lt;/h3&gt;  &lt;p&gt;Select or Drop-down lists (or “combo boxes” as everyone else calls them) are a pretty useful UI element, so it makes sense that they’re used pretty liberally across the web.&amp;#160; But, have you ever gotten halfway through filling out that form and come across this?&lt;/p&gt;  &lt;p style=&quot;padding-left: 20px&quot;&gt;&lt;a href=&quot;http://lh3.ggpht.com/_sH3XWh6OzVE/Sf1BNhgffSI/AAAAAAAAAGI/Xl-_1X-sV6E/s1600-h/image%5B5%5D.png&quot;&gt;&lt;img title=&quot;image&quot; style=&quot;border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px&quot; height=&quot;41&quot; alt=&quot;image&quot; src=&quot;http://lh5.ggpht.com/_sH3XWh6OzVE/Sf1BN388miI/AAAAAAAAAGM/CtCeCl3Vn0Y/image_thumb%5B1%5D.png?imgmax=800&quot; width=&quot;244&quot; border=&quot;0&quot; /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Yeah, me too. And it&#39;s pretty annoying, especially since they&#39;re not usually as evident as this one is and you actually waste time expanding it just to find out that you never had an option to begin with.&amp;#160; The first approach most developers take is to just disable the control, graying it out so it is &amp;quot;clear&amp;quot; to the user that they have no other options to select.&amp;#160; I&#39;m talking about something like this:&lt;/p&gt;  &lt;p style=&quot;padding-left: 20px&quot;&gt;&lt;a href=&quot;http://lh4.ggpht.com/_sH3XWh6OzVE/Sf1BOeYt0WI/AAAAAAAAAGQ/fXCIBhepSaE/s1600-h/image%5B8%5D.png&quot;&gt;&lt;img title=&quot;image&quot; style=&quot;border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px&quot; height=&quot;45&quot; alt=&quot;image&quot; src=&quot;http://lh3.ggpht.com/_sH3XWh6OzVE/Sf1BO9omHBI/AAAAAAAAAGU/MXfQQWBGmHM/image_thumb%5B2%5D.png?imgmax=800&quot; width=&quot;244&quot; border=&quot;0&quot; /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Meh. It certainly doesn&#39;t suck as much as the first example, but it&#39;s far from an ideal interaction. Users are still left wondering, &amp;quot;Well, what other options do I have that they won&#39;t let me see?&amp;quot; (and - depending upon their level of self-esteem - maybe something like, &amp;quot;What, am I not good enough for those other options? Man, this always happens to me - people are always leaving me out and [...]&amp;quot;). While there&#39;s not a whole lot you can do to raise your users&#39; self-esteem (or if there is, that&#39;s a whole separate blog post altogether), you can eliminate this whole situation altogether in a very simple and straight-forward way: just &lt;em&gt;tell them&lt;/em&gt; what the value will be. Just do this:&lt;/p&gt;  &lt;p style=&quot;padding-left: 20px&quot;&gt;&lt;a href=&quot;http://lh4.ggpht.com/_sH3XWh6OzVE/Sf1BPMTCspI/AAAAAAAAAGY/bxY62irrJdo/s1600-h/image%5B11%5D.png&quot;&gt;&lt;img title=&quot;image&quot; style=&quot;border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px&quot; height=&quot;39&quot; alt=&quot;image&quot; src=&quot;http://lh4.ggpht.com/_sH3XWh6OzVE/Sf1BPhZ47GI/AAAAAAAAAGc/qMe1mlbk-zQ/image_thumb%5B3%5D.png?imgmax=800&quot; width=&quot;244&quot; border=&quot;0&quot; /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Looks simple enough, right? I&#39;ll bet for the developers in the crowd, your wheels are already churning, trying to figure out the best way to do this. Just like me, your knee-jerk reaction is probably going to involve extending or wrapping &lt;strong&gt;DropDownList&lt;/strong&gt;, but the problem with that is that you now have this new control and in order to use it you have &lt;em&gt;scour your entire site&lt;/em&gt; and replace any instances of &lt;strong&gt;DropDownList&lt;/strong&gt; with &lt;strong&gt;MySuperAwesomeDropDownList&lt;/strong&gt;. But, since that really wasn&#39;t an option for me, my response was to create a Control Adapter.&lt;/p&gt;  &lt;h3&gt;Implementing a Custom Control Adapter&lt;/h3&gt;  &lt;p&gt;ASP.NET Control Adapters are a neat way of controlling exactly how controls get rendered down to your clients… even the ASP.NET framework controls!&amp;#160; To take advantage of them, there are two steps: first, create your adapter; then, register it in your .browsers file so that the framework will pick it up.&lt;/p&gt;  &lt;p&gt;To achieve the behavior I showed earlier, what we’re going to want to do is override the way our &lt;strong&gt;DropDownList&lt;/strong&gt; controls get rendered out and insert some logic.&amp;#160; Namely, if we’ve got any more than one item, let the control do its thing… but, if we’ve got only one item, take over and instead just render the text of the item out instead of the combo box.&amp;#160; Here’s the code:&lt;/p&gt;  &lt;div class=&quot;wlWriterSmartContent&quot; id=&quot;scid:812469c5-0cb0-4c63-8c15-c81123a09de7:dced15da-858d-4a2b-a6d0-8a5cfa23726d&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;   &lt;pre class=&quot;c#&quot; name=&quot;code&quot;&gt;public class SmartListControlAdapter&lt;br /&gt;    : System.Web.UI.Adapters.ControlAdapter&lt;br /&gt;{&lt;br /&gt;    protected ListControl WrappedControl&lt;br /&gt;    {&lt;br /&gt;        get { return this.Control as ListControl; }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected bool ShouldDisplaySmartText&lt;br /&gt;    {&lt;br /&gt;        get&lt;br /&gt;        {&lt;br /&gt;            return WrappedControl.Items.Count &amp;lt; 2&lt;br /&gt;                &amp;amp;&amp;amp; WrappedControl.SelectedItem != null;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected override void Render(System.Web.UI.HtmlTextWriter writer)&lt;br /&gt;    {&lt;br /&gt;        if (ShouldDisplaySmartText)&lt;br /&gt;            writer.Write(smartText());&lt;br /&gt;        else&lt;br /&gt;            base.Render(writer);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private string smartText()&lt;br /&gt;    {&lt;br /&gt;        return string.Format(&amp;quot;&amp;lt;span class=&#39;smartListValue&#39;&amp;gt;{0}&amp;lt;/span&amp;gt;&amp;quot;,&lt;br /&gt;                             WrappedControl.SelectedItem.Text);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;You’ll see I added the &lt;strong&gt;WrappedControl&lt;/strong&gt; property to cast the base &lt;strong&gt;Control&lt;/strong&gt; property to a &lt;strong&gt;ListControl&lt;/strong&gt; so I don’t have to do that every time I access it.&amp;#160; Wait – why a &lt;strong&gt;ListControl&lt;/strong&gt; when I said earlier that we were targeting a &lt;strong&gt;DropDownList&lt;/strong&gt; control instead?&amp;#160; Well, after I was done writing all the code you see above, ReSharper let me know that based on the way I was using my reference, I was only using those properties and methods defined in the &lt;strong&gt;ListControl&lt;/strong&gt; base class.&amp;#160; Even though I probably won’t ever use this for anything other than the &lt;strong&gt;DropDownList&lt;/strong&gt;, I figured why limit myself? :)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;You’ll also notice that – outside of the casting to a &lt;strong&gt;ListControl&lt;/strong&gt; – that nowhere in this adapter code does it say which control it’s targeting.&amp;#160; In order to actually apply this adapter to the controls on my pages, I’ll need to tell the framework in a separate location which controls I’d like to apply it to.&amp;#160; This is where the &lt;em&gt;.browsers&lt;/em&gt; file(s) come in.&amp;#160; If your project doesn’t have an &lt;strong&gt;App_Browsers&lt;/strong&gt; folder, you can right-click on your project and click &lt;em&gt;Add &amp;gt; Add ASP.NET Folder &amp;gt; App_Browsers&lt;/em&gt;.&amp;#160; Once this is complete, you can again right-click on this new folder and add a new item using the Browser File template (the name, other than .browser, doesn’t matter).&amp;#160; You can then paste the following inside this file:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;wlWriterEditableSmartContent&quot; id=&quot;scid:812469c5-0cb0-4c63-8c15-c81123a09de7:cb23b4cb-73d3-471b-955b-d403ffeb48aa&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;&lt;pre name=&quot;code&quot; class=&quot;xml&quot;&gt;&amp;lt;browsers&amp;gt;&lt;br /&gt;    &amp;lt;browser refID=&quot;Default&quot;&amp;gt;&lt;br /&gt;        &amp;lt;controlAdapters&amp;gt;&lt;br /&gt;            &amp;lt;adapter&lt;br /&gt;                controlType=&quot;System.Web.UI.WebControls.DropDownList&quot;&lt;br /&gt;                adapterType=&quot;ControlAdapters.SmartDropDownListAdapter&quot;&lt;br /&gt;            /&amp;gt;&lt;br /&gt;        &amp;lt;/controlAdapters&amp;gt;&lt;br /&gt;    &amp;lt;/browser&amp;gt;&lt;br /&gt;&amp;lt;/browsers&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Simple enough, right?&amp;#160; Here in the ControlAdapters section for the Default (every) browser, we’re telling the framework to wrap all of our &lt;strong&gt;DropDownList&lt;/strong&gt; instances with our new &lt;strong&gt;SmartDropDownListAdapter&lt;/strong&gt;.&amp;#160; It really doesn’t get much simpler than that!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Now we can create a quick test page:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;wlWriterEditableSmartContent&quot; id=&quot;scid:812469c5-0cb0-4c63-8c15-c81123a09de7:e09985d7-f634-4db3-8123-523ab283578e&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;&lt;pre name=&quot;code&quot; class=&quot;xml&quot;&gt;&amp;lt;p&amp;gt;&lt;br /&gt;    Regular Drop-Down:&lt;br /&gt;    &amp;lt;asp:DropDownList ID=&quot;RegularDropDown&quot; runat=&quot;server&quot; AutoPostBack=&quot;true&quot;&amp;gt;&lt;br /&gt;        &amp;lt;asp:ListItem Text=&quot;First&quot; Value=&quot;1&quot; /&amp;gt;&lt;br /&gt;        &amp;lt;asp:ListItem Text=&quot;Second&quot; Value=&quot;2&quot; /&amp;gt;&lt;br /&gt;        &amp;lt;asp:ListItem Text=&quot;Third&quot; Value=&quot;3&quot; Selected=&quot;True&quot; /&amp;gt;&lt;br /&gt;        &amp;lt;asp:ListItem Text=&quot;Fourth&quot; Value=&quot;4&quot; /&amp;gt;&lt;br /&gt;    &amp;lt;/asp:DropDownList&amp;gt;&lt;br /&gt;    &amp;lt;br /&amp;gt;&lt;br /&gt;    &amp;lt;em&amp;gt;Selected Value:  &amp;lt;%= RegularDropDown.SelectedValue%&amp;gt;&amp;lt;/em&amp;gt;&lt;br /&gt;&amp;lt;/p&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;p&amp;gt;&lt;br /&gt;    Smart Drop-Down:&lt;br /&gt;    &amp;lt;asp:DropDownList ID=&quot;SmartDropDown&quot; runat=&quot;server&quot;&amp;gt;&lt;br /&gt;        &amp;lt;asp:ListItem Text=&quot;One Value&quot; Value=&quot;1&quot; /&amp;gt;&lt;br /&gt;    &amp;lt;/asp:DropDownList&amp;gt;&lt;br /&gt;    &amp;lt;br /&amp;gt;&lt;br /&gt;    &amp;lt;em&amp;gt;Selected Value:  &amp;lt;%= SmartDropDown.SelectedValue%&amp;gt;&amp;lt;/em&amp;gt;&lt;br /&gt;&amp;lt;/p&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;You can see I added a few test lines that write out the &lt;strong&gt;SelectedValue&lt;/strong&gt; after each of the controls to prove that the underlying &lt;strong&gt;DropDownList&lt;/strong&gt; control is not modified, just displayed differently.&amp;#160; This means that the &lt;strong&gt;SelectedValue&lt;/strong&gt; (along with everything else) can still be used as normal.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Finally, the moment we’ve all been waiting for; the results of the previous snippet:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href=&quot;http://lh5.ggpht.com/_sH3XWh6OzVE/Sf1BPyFkiFI/AAAAAAAAAGg/COPwK2bZaDU/s1600-h/image%5B2%5D.png&quot;&gt;&lt;img title=&quot;image&quot; style=&quot;border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px&quot; height=&quot;131&quot; alt=&quot;image&quot; src=&quot;http://lh3.ggpht.com/_sH3XWh6OzVE/Sf1BQQk8isI/AAAAAAAAAGk/bU0bcoY0eBY/image_thumb.png?imgmax=800&quot; width=&quot;244&quot; border=&quot;0&quot; /&gt;&lt;/a&gt; &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Not incredibly styled, but beautiful nonetheless!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Your Thoughts&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;So, what do you think about this approach?&amp;#160; Has this problem bothered you before?&amp;#160; What ways have you solved it?&amp;#160; I’d love to hear about them!&lt;/p&gt;  </description><link>http://jesschadwick.blogspot.com/2009/05/leverage-aspnet-control-adapters-for.html</link><author>noreply@blogger.com (Jess Chadwick)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/_sH3XWh6OzVE/Sf1BN388miI/AAAAAAAAAGM/CtCeCl3Vn0Y/s72-c/image_thumb%5B1%5D.png?imgmax=800" height="72" width="72"/><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-9111758740802890470</guid><pubDate>Sun, 19 Apr 2009 15:53:00 +0000</pubDate><atom:updated>2009-04-19T11:53:00.147-04:00</atom:updated><title>Of HTTP Headers and Firefox Add-Ons…</title><description>&lt;p&gt;Until just last week we had hosted our main website on a single web server, however an impressive team effort of just a few days brought that situation to a screeching halt when we finally moved everything to a brand new, long-awaited web farm. The benefits of web farms are both well-known and mostly obvious, but it’s not all roses and puppy dogs - web farms certainly bring their share of headaches as well.&lt;/p&gt;  &lt;p&gt;One of the pains I immediately felt as soon as we went live was the fact that I had no idea &lt;i&gt;which&lt;/i&gt; server in the farm I was hitting with any given request. Yes, of course to you the site user this really shouldn’t (and doesn’t) matter, but for me and my team when something isn’t going quite right, knowing which machine this uninvited behavior is originating from is a crucial piece of information. My knee-jerk reaction was to place some kind of identifier in the page content. To this end, I opened up the master pages on each server, scrolled to the end and plopped in an HTML comment “&amp;lt;!-- A --&amp;gt;”, “&amp;lt;!-- B --&amp;gt;”, and so on. This certainly fit my immediate requirement, but had a few annoying downsides: first off, this certainly wasn’t a maintainable solution, since it would have to be re-applied (probably manually, on &lt;i&gt;every&lt;/i&gt; server) with every release and – if that weren’t enough by itself (which it was!) – it was just plain annoying having to right-click, View Source, scroll to the bottom, and search for this identifier. My immediate need was filled, but the geek in me was raging – there had to be a better way!&lt;/p&gt;  &lt;p&gt;&lt;b&gt;Take 2:&lt;/b&gt; After a bit of consideration, I thought taking advantage of the Footers feature in IIS might be a good idea. I’d never used them before, and didn’t know how well it would work for our goals, but decided to try it out anyway. “Open IIS Management console, right-click on my site, Properties… wait – the HTTP Headers tab!” Most any web developer who’s done a decent bit of AJAX has probably used – or at least seen usage of – custom HTTP Headers as a way of communicating meta-data about web responses (e.g. the “X-MicrosoftAjax” header used in ASP.NET AJAX to identify an AJAX request). Frustrated with myself that I hadn’t thought about this initially, I realized this is exactly where I’d wanted to put this info all along. My initial solution of putting the HTML comment in the text left a bad taste in my mouth for so many reasons, but at this point I realized that the worst part about it was that I was putting &lt;i&gt;response metadata&lt;/i&gt; in the &lt;i&gt;content&lt;/i&gt;, thus committing a blatant violation of Separating Concerns. After slapping my wrist with a ruler and vowing never to do that again (yeah, right!), I set forth to correct it, quickly adding a new custom HTTP Header called “X-ResponseOrigin” on each of my servers, and each with its own unique value. After going back and removing those silly HTML comments, I sat back, made a few requests and happily viewed the responses coming back in Firebug, knowing exactly which server had produced each one.&lt;/p&gt;  &lt;p&gt;So at this point I’m pretty pleased with the way things are going. With Firebug open, I could see everything I needed to in order to troubleshoot server-specific issues. But, after a short time I started getting annoyed again. With every new request, I’d have to scroll down to the bottom of the request history in Firebug, find my request, expand it out, and scroll down, all the while scanning for my new special header. Trying to find this new piece of metadata I added – while arguably better than the previous “View Source, Scroll ‘n Scan” method – was still pretty darn annoying… oh, and what about the guys on my team who &lt;i&gt;didn’t&lt;/i&gt; &lt;i&gt;have&lt;/i&gt; Firebug?? (NOTE: this is really a hypothetical situation, since it is a well-known team rule that not having Firebug on your machine - even if you’re a non-developer – is punishable by 30 push-ups and having to buy everyone donuts the following morning.) It’s at this point that I remembered what Firebug was to begin with – a Firefox Addon – and realized what I must do next…&lt;/p&gt;  &lt;h4&gt;Enter the Firefox Addon&lt;/h4&gt;  &lt;p&gt;I needed to make a custom Firefox Addon to show me what server I was on, right there in my Firefox statusbar. No, it wasn’t a requirement for this project – it was utterly imperative to fulfilling my role of “Lead Code Monkey”; it was my destiny.&lt;/p&gt;  &lt;p&gt;A quick Googling brought me to the Mozilla Developer portal, with its wealth of knowledge of all things Mozilla. Come to find out, writing a Firefox Addon is as simple as some XHTML/XML-ish markup and accompanying JavaScript – what could be easier!? The markup was quick – I just had to declare that I wanted a custom &lt;b&gt;statusbarpanel&lt;/b&gt; that I could put my content in. The resulting code looked like this: &lt;/p&gt;  &lt;div class=&quot;wlWriterEditableSmartContent&quot; id=&quot;scid:812469c5-0cb0-4c63-8c15-c81123a09de7:9851f8ee-99b6-417e-8501-4239f85e4490&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;&lt;pre name=&quot;code&quot; class=&quot;xml&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;br /&gt;&amp;lt;?xml-stylesheet href=&quot;chrome://whereami/skin/overlay.css&quot; type=&quot;text/css&quot;?&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE overlay SYSTEM &quot;chrome://whereami/locale/whereami.dtd&quot;&amp;gt;&lt;br /&gt;&amp;lt;overlay id=&quot;whereami-overlay&quot;&lt;br /&gt;         xmlns=&quot;http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul&quot;&amp;gt;&lt;br /&gt;  &amp;lt;script src=&quot;overlay.js&quot;/&amp;gt;&lt;br /&gt;  &amp;lt;stringbundleset id=&quot;stringbundleset&quot;&amp;gt;&lt;br /&gt;    &amp;lt;stringbundle id=&quot;whereami-strings&quot; src=&quot;chrome://whereami/locale/whereami.properties&quot;/&amp;gt;&lt;br /&gt;  &amp;lt;/stringbundleset&amp;gt;&lt;br /&gt;  &amp;lt;statusbar id=&quot;status-bar&quot;&amp;gt;&lt;br /&gt;     &amp;lt;statusbarpanel id=&quot;whereami.location&quot; label=&quot;&quot; /&amp;gt;&lt;br /&gt;  &amp;lt;/statusbar&amp;gt;&lt;br /&gt;&amp;lt;/overlay&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;As you can see, it’s pretty straightforward. We’ve got our standard XML cruft, followed by what looks like a typical JavaScript reference tag, pointing to our script file (which we’ll get to in just a minute). This is followed by our &lt;i&gt;&amp;lt;statusbar&amp;gt;&lt;/i&gt; and &lt;i&gt;&amp;lt;statusbarpanel&amp;gt;&lt;/i&gt; element, letting Firefox know that all we’re going to need for our UI is a little piece of the existing status bar. We also gave that statusbarpanel an ID so we can easily reference it from our scripts later on. Actually, forget “later on” – let’s go see what those scripts look like!&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Before we see the code behind all this, let’s revisit the requirements. Basically, we’re look for this add-on to do two things: get our custom HTTP header from requests that come in, and (if we find one) display it in the browser’s status bar. Initially, I had expected the latter to be the difficult part, but much to my surprise it turned out to be as simple as this one line:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;i&gt;document.getElementById(‘whereami.location’).label = responseOrigin;&lt;/i&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The cool part here is the usage of the “document.getElementById()” DOM searching that you’re already used to from your normal JavaScript forays. And, there’s that element ID “whereami.location” that we set earlier in our overlay.xul file. Now that we’ve got the statusbar update figured out, let’s populate the value of &lt;i&gt;responseOrigin&lt;/i&gt;…&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h5&gt;Quick Intro to the XPCOM API&lt;/h5&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;In order to get a chance to look at what the user is browsing, you’ve got to create a class that you can register with Firefox as a listener. From that point, you’ll be notified whenever a browsing event happens – say, when a new response has been received. Before we look at the actual implementation, let’s look at a basic implementation of a Firefox listener class (as taken from the &lt;a href=&quot;https://developer.mozilla.org/En/NsIObserver&quot; target=&quot;_blank&quot;&gt;Mozilla Developer Center&lt;/a&gt;): &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;wlWriterEditableSmartContent&quot; id=&quot;scid:812469c5-0cb0-4c63-8c15-c81123a09de7:d7be77a6-8dbf-417b-83e6-16c4961ced4a&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;&lt;pre name=&quot;code&quot; class=&quot;js&quot;&gt;function myObserver()&lt;br /&gt;{&lt;br /&gt;  this.register();&lt;br /&gt;}&lt;br /&gt;myObserver.prototype = {&lt;br /&gt;  observe: function(subject, topic, data) {&lt;br /&gt;     // Do your stuff here.&lt;br /&gt;  },&lt;br /&gt;  register: function() {&lt;br /&gt;    var observerService = Components.classes[&quot;@mozilla.org/observer-service;1&quot;]&lt;br /&gt;                          .getService(Components.interfaces.nsIObserverService);&lt;br /&gt;    observerService.addObserver(this, &quot;myTopicID&quot;, false);&lt;br /&gt;  },&lt;br /&gt;  unregister: function() {&lt;br /&gt;    var observerService = Components.classes[&quot;@mozilla.org/observer-service;1&quot;]&lt;br /&gt;                            .getService(Components.interfaces.nsIObserverService);&lt;br /&gt;    observerService.removeObserver(this, &quot;myTopicID&quot;);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;You’ll see, all the magic happens in the &lt;i&gt;observe&lt;/i&gt;() method, which gets fired whenever a browser event happens. For the purposes of this app, we’re looking out for any time an &lt;i&gt;http-on-examine-response&lt;/i&gt; event is fired, indicating a new response has been received. That’s pretty easy, we’ll just check the value of &lt;i&gt;eventName&lt;/i&gt; parameter:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;i&gt;if (topic == &amp;quot;http-on-examine-response&amp;quot;) { /* Grab the Response Origin */ }&lt;/i&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Now let’s take a look at my implementation: &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;wlWriterEditableSmartContent&quot; id=&quot;scid:812469c5-0cb0-4c63-8c15-c81123a09de7:d8a7cb2c-7f69-4067-be74-f9d1391386fe&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;&lt;pre name=&quot;code&quot; class=&quot;js&quot;&gt;var whereami = {&lt;br /&gt;	requestObserver:&lt;br /&gt;	{&lt;br /&gt;		isRegistered: false,&lt;br /&gt;&lt;br /&gt;	  observe: function(subject, topic, data)&lt;br /&gt;	  {&lt;br /&gt;	    if (topic == &quot;http-on-examine-response&quot;) {&lt;br /&gt;		  var statusBar = document.getElementById(&#39;whereami.location&#39;);&lt;br /&gt;		  statusBar.label = &quot;&quot;;&lt;br /&gt;	      var httpChannel = subject.QueryInterface(Components.interfaces.nsIHttpChannel);&lt;br /&gt;	      var origin = httpChannel.getResponseHeader(&quot;X-ResponseOrigin&quot;);&lt;br /&gt;		  if(origin &amp;amp;&amp;amp; origin.length &amp;gt; 0)&lt;br /&gt;			origin = &quot;Server: &quot; + origin;&lt;br /&gt;		  statusBar.label = origin;&lt;br /&gt;	    }&lt;br /&gt;	  },&lt;br /&gt;&lt;br /&gt;	  get observerService() {&lt;br /&gt;	    return Components.classes[&quot;@mozilla.org/observer-service;1&quot;]&lt;br /&gt;	                     .getService(Components.interfaces.nsIObserverService);&lt;br /&gt;	  },&lt;br /&gt;&lt;br /&gt;	  register: function()&lt;br /&gt;	  {&lt;br /&gt;	    if(this.isRegistered) return;&lt;br /&gt;		&lt;br /&gt;	    this.observerService.addObserver(this, &quot;http-on-examine-response&quot;, false);&lt;br /&gt;		this.isRegistered = true;&lt;br /&gt;	  },&lt;br /&gt;&lt;br /&gt;	  unregister: function()&lt;br /&gt;	  {&lt;br /&gt;	    if(!this.isRegistered) return;&lt;br /&gt;		&lt;br /&gt;	    this.observerService.removeObserver(this, &quot;http-on-examine-response&quot;);&lt;br /&gt;		this.isRegistered = false;&lt;br /&gt;	  }&lt;br /&gt;	}&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;window.addEventListener(&quot;load&quot;, function(e) { whereami.requestObserver.register(); }, false);&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;You can see this is basically the same as the snippet from Mozilla, but I’ve added my logic right into the &lt;em&gt;observe()&lt;/em&gt; method (lines 8-16).&amp;#160; Let’s see what we’re doing here:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;First, we have to get a reference to our little section of the statusbar that we reserved via the ID that I gave it earlier in the overlay.xul markup, clearing any existing (stale) data (lines 9 &amp;amp; 10) &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Then, we examine the HTTP headers that got sent back in our response, looking for the value of the “X-ResponseOrigin” that was sent from the server.&amp;#160; (lines 11-13) &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Finally, we’ll update the statusbar label with the value we got from Step 2&amp;#160; (line 15) &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;  </description><link>http://jesschadwick.blogspot.com/2009/04/of-http-headers-and-firefox-add-ons.html</link><author>noreply@blogger.com (Jess Chadwick)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-3042413449366530124</guid><pubDate>Sun, 19 Apr 2009 04:37:00 +0000</pubDate><atom:updated>2011-06-07T13:29:57.181-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ASP.NET MVC</category><title>Cleaner Validation with ASP.NET MVC Model Binders &amp;amp; the Enterprise Library Validation Application Block</title><description>&lt;p&gt;I accidentally stumbled across an awesome combination the other day:&amp;#160; using the Enterprise Library Validation Block with ASP.NET MVC.&amp;#160; Though I’ve played around with them a few times in the past, this is the first time I’ve &lt;i&gt;really&lt;/i&gt; started to apply the Validation block in a serious application, and it just so happened to have an ASP.NET MVC website as its client.&amp;#160; My jaw dropped more and more as I started to realize the awesomeness that was unfolding before me…&amp;#160; hopefully this blog post will do the same (or as close as possible) to you!&lt;/p&gt;&lt;h3&gt;Using the Enterprise Library Validation Block&lt;/h3&gt;&lt;p&gt;It all started with an innocent enough Model requiring a wee bit of validation that I didn’t feel like hand-writing, so (as usual) I turned to the EntLib library to do it for me.&amp;#160; Applying the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/cc309320.aspx&quot; target=&quot;_blank&quot;&gt;Enterprise Library Validation Block&lt;/a&gt; was surprisingly simple.&amp;#160; &lt;/p&gt;&lt;p&gt;It all started with a simple enough class (the names have been changed to protect the innocent):    &lt;div class=&quot;wlWriterEditableSmartContent&quot; id=&quot;scid:812469c5-0cb0-4c63-8c15-c81123a09de7:5ec7780d-89aa-4f7d-8883-e7136fbd5d73&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;&lt;pre name=&quot;code&quot; class=&quot;c#:nocontrols&quot;&gt;public class Product
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public double Price { get; set; }
public int Quantity { get; set; }
}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;This is basically just a DTO (data transfer object), but this ain’t the Wild West – there are rules, and they need to be followed!&amp;#160; After a few minutes, I’d come up with something like this: &lt;br /&gt;
&lt;div class=&quot;wlWriterEditableSmartContent&quot; id=&quot;scid:812469c5-0cb0-4c63-8c15-c81123a09de7:47998da8-bce5-44ff-a1b8-9485ae5753a2&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;&lt;pre name=&quot;code&quot; class=&quot;c#:nocontrols&quot;&gt;using Microsoft.Practices.EnterpriseLibrary.Validation;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;

public class Product
{
[RangeValidator(
1, RangeBoundaryType.Inclusive,             /* Lower Bound */
int.MaxValue, RangeBoundaryType.Inclusive   /* Upper Bound */
)]
public int ID { get; set; }

// Let&#39;s assume that we&#39;ve got a field length limitation in
// our database of 500 characters, which we&#39;ll check for here
[StringLengthValidator(
1, RangeBoundaryType.Inclusive,             /* Lower Bound */
500, RangeBoundaryType.Inclusive            /* Upper Bound */
)]
public string Name { get; set; }

// No rules for the description - anything goes!
public string Description { get; set; }

// The Price can be whatever we want, as long as it&#39;s positive
[RangeValidator(0, RangeBoundaryType.Inclusive, double.MaxValue, RangeBoundaryType.Inclusive)]
public double Price { get; set; }

// Same deal with the Quantity - we can never have a negative quantity
[RangeValidator(0, RangeBoundaryType.Inclusive, int.MaxValue, RangeBoundaryType.Inclusive)]
public int Quantity { get; set; }


public bool IsValid()
{
return Validate().IsValid;
}

public ValidationResults Validate()
{
return Validation.Validate&amp;lt;Product&amp;gt;(this);
}
}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;There are a couple of cool things I like about this setup:&lt;/p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;&lt;b&gt;Declarative validation rules&lt;/b&gt;:&amp;#160; These rules are very explicit expression of business logic - there is no “if-else-then”, mumbo-jumbo.&amp;#160; In other words, there isn’t any code to worry about… and no code means no bugs (well, less bugs at least :).&amp;#160; Moreover, if any of these business rules change, it’s very easy to update these attributes without hunting around for that stray line of “if-else” code somewhere.&amp;#160; Lastly, I’ve heard talk of these mystical “business people” who are also able to read and understand simple code; and, if you run into one of these guys/gals they’ll easily be able to verify that you have the rules set properly as well. &lt;/li&gt;


&lt;li&gt;&lt;b&gt;All of the validation logic is in one place&lt;/b&gt;:&amp;#160; all consumers of this class need to do is set its properties and &lt;i&gt;ask the object&lt;/i&gt; whether or not it is valid.&amp;#160; There are no stray “if(string.IsNullOrEmpty(product.Name)” scattered through your code, just “if(product.IsValid())”.&amp;#160; I feel like this approach has a decent amount of cohesion.&amp;#160; Granted, it could be a bit more cohesive if we had, say, a separate “ProductValidator”, but this seems like overkill.&amp;#160; Regardless, it was bugging me enough that I actually created a super-class to encapsulate this logic further of the chain of inheritance and that made me feel a bit more comfortable: &lt;/li&gt;


&lt;div class=&quot;wlWriterEditableSmartContent&quot; id=&quot;scid:812469c5-0cb0-4c63-8c15-c81123a09de7:c84976a4-c0ea-4d9e-bb45-9a86217ce7e9&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;&lt;pre name=&quot;code&quot; class=&quot;c#&quot;&gt;public class SelfValidatingBase
{
public bool IsValid()
{
return Validate().IsValid;
}

public ValidationResults Validate()
{
return ValidationFactory.CreateValidator(this.GetType())
.Validate(this);
}
}

public class Product : SelfValidatingBase
{
// ...
}&lt;/pre&gt;&lt;/div&gt;
&lt;/ol&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;As with pretty much anything, there is at least one glaring drawback to this approach:&amp;#160; there is no “real-time” checking.&amp;#160; That is, this approach allows consumers to set invalid values on these validated properties at any time – possibly overwriting valid values without any checks prior to the update.&amp;#160; I think that as long as your application (i.e. developers) know about this limitation, it’s not so much of an issue, at least not for the scenarios I’ve used it in, so this drawback doesn’t really bother me.&lt;/p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;Now, let’s see how this applies to ASP.NET MVC…&lt;/p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;The Awesomeness that is ASP.NET MVC’s Model Binders&lt;/h3&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;When it comes to me and &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd410405.aspx&quot; target=&quot;_blank&quot;&gt;ASP.NET MVC’s Model Binders&lt;/a&gt; it was love at first site – and I haven’t stopped using them since.&amp;#160; In case you’re not sure what I’m talking about, here’s an example.&amp;#160; Instead of an Action with individual parameters and populating a new instance ourselves like this: &lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;wlWriterEditableSmartContent&quot; id=&quot;scid:812469c5-0cb0-4c63-8c15-c81123a09de7:4e40d84f-cd93-4ff2-8e70-990dd6697595&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;&lt;pre name=&quot;code&quot; class=&quot;c#:nocontrols&quot;&gt;[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(string username, string message, string userUrl)
{
var comment = new Comment
{
Message = message,
Username = username,
UserUrl = userUrl,
PostedDate = DateTime.Now
};
commentsRepository.Add(comment);
return RedirectToAction(&quot;Index&quot;);
}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;We let the MVC framework populate a new instance for us, like this: &lt;br /&gt;
&lt;div class=&quot;wlWriterEditableSmartContent&quot; id=&quot;scid:812469c5-0cb0-4c63-8c15-c81123a09de7:3c4f99e9-05b5-4fb3-ae77-1ab7bf034225&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;&lt;pre name=&quot;code&quot; class=&quot;c#:nocontrols&quot;&gt;[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Comment comment)
{
commentsRepository.Add(comment);
return RedirectToAction(&quot;Index&quot;);
}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;I just think that’s beautiful, and so I’ve come to (over?)use Model Binders on my Controller Actions almost exclusively.&amp;#160; &lt;/p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;ASP.NET MVC Model Binders + Enterprise Library Validation Block = BFF&lt;/h3&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;The magic that I refer to at the beginning of this post first exposed itself when I inadvertently used one of my Model objects like the one I showed earlier as an Action parameter (which was really only a matter of time given the fact that I’d taken to using them so much!) using MVC’s Model Binding, and then created some validation logic for it (if you’re not sure what I’m referring to in regards to “creating validation logic”, you’ll want to check out &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd410404.aspx&quot; target=&quot;_blank&quot;&gt;this article on MSDN&lt;/a&gt; before continuing).&amp;#160; As I started writing my validation logic in my Action and populating the ModelState with my validation errors like so: &lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;wlWriterEditableSmartContent&quot; id=&quot;scid:812469c5-0cb0-4c63-8c15-c81123a09de7:31533d34-4b98-40fe-9c0b-be4658c5c924&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;&lt;pre name=&quot;code&quot; class=&quot;c#:nocontrols&quot;&gt;[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Product product)
{
if (!product.IsValid())
{
if(string.IsNullOrEmpty(product.Name))
this.ModelState.AddModelError(&quot;name&quot;, &quot;Please enter a product name&quot;);
if(product.Price &amp;lt; 0)
this.ModelState.AddModelError(&quot;price&quot;, &quot;Price must be greater than 0&quot;);
if(product.Quantity &amp;lt; 0)
this.ModelState.AddModelError(&quot;quantity&quot;, &quot;Quantity must be greater than 0&quot;);

return View(product);
}

productRepository.Add(product);
return View(&quot;Index&quot;);
}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;Now, even if I moved this code outside of my Action, I’d still be pretty embarrassed of it…&amp;#160; but after looking at it for a while I realized that I don’t have to do this after all – the EntLib ValidationResult (usually) maps perfectly to MVC’s Model Binding…&amp;#160; and ModelState errors!&amp;#160; Check out the same code, taking advantage of the EntLib validation results: &lt;br /&gt;
&lt;div class=&quot;wlWriterEditableSmartContent&quot; id=&quot;scid:812469c5-0cb0-4c63-8c15-c81123a09de7:60723655-c705-4ab8-9d7e-23db69cf9837&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;&lt;pre name=&quot;code&quot; class=&quot;c#&quot;&gt;[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Product product)
{
var validationResult = product.Validate();
if (!validationResult.IsValid)
{
foreach (var result in validationResult)
this.ModelState.AddModelError(result.Key, result.Message);

return View(product);
}

productRepository.Add(product);
return View(&quot;Index&quot;);
}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;I added this and awesomeness ensued.&amp;#160; The magic comes from the fact that the &lt;i&gt;Key&lt;/i&gt; field of the EntLib &lt;i&gt;ValidationResult&lt;/i&gt; is the name of the property which is causing the validation error.&amp;#160; This leads to what I can do in line 8 above, which is just iterate through all of the validation errors and add their message to the ModelState using their &lt;i&gt;Key&lt;/i&gt; property, which corresponds to the form id’s that we’re using to populate the model.&amp;#160; Just so you don’t think I’m lying, here’s what the form would look like: &lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;wlWriterEditableSmartContent&quot; id=&quot;scid:812469c5-0cb0-4c63-8c15-c81123a09de7:77a2dcff-0e86-4551-977b-4be35ad6d950&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;&lt;pre name=&quot;code&quot; class=&quot;c#:nocontrols&quot;&gt;&amp;lt;%= Html.ValidationSummary(
&quot;Create was unsuccessful. 
Please correct the errors and try again.&quot;) %&amp;gt;
&amp;lt;% using (Html.BeginForm()) {%&amp;gt;
&amp;lt;fieldset&amp;gt;
&amp;lt;legend&amp;gt;Add New Product&amp;lt;/legend&amp;gt;
&amp;lt;p&amp;gt;
&amp;lt;label for=&quot;Name&quot;&amp;gt;Name:&amp;lt;/label&amp;gt;
&amp;lt;%= Html.TextBox(&quot;Name&quot;) %&amp;gt;
&amp;lt;%= Html.ValidationMessage(&quot;Name&quot;, &quot;*&quot;) %&amp;gt;
&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;
&amp;lt;label for=&quot;Description&quot;&amp;gt;Description:&amp;lt;/label&amp;gt;
&amp;lt;%= Html.TextBox(&quot;Description&quot;) %&amp;gt;
&amp;lt;%= Html.ValidationMessage(&quot;Description&quot;, &quot;*&quot;) %&amp;gt;
&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;
&amp;lt;label for=&quot;Price&quot;&amp;gt;Price:&amp;lt;/label&amp;gt;
&amp;lt;%= Html.TextBox(&quot;Price&quot;) %&amp;gt;
&amp;lt;%= Html.ValidationMessage(&quot;Price&quot;, &quot;*&quot;) %&amp;gt;
&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;
&amp;lt;label for=&quot;Quantity&quot;&amp;gt;Quantity:&amp;lt;/label&amp;gt;
&amp;lt;%= Html.TextBox(&quot;Quantity&quot;) %&amp;gt;
&amp;lt;%= Html.ValidationMessage(&quot;Quantity&quot;, &quot;*&quot;) %&amp;gt;
&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;
&amp;lt;input type=&quot;submit&quot; value=&quot;Create&quot; /&amp;gt;
&amp;lt;/p&amp;gt;
&amp;lt;/fieldset&amp;gt;
&amp;lt;% } %&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;I Think We Can Do Just a Bit Better…&lt;/h3&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;So, there you have it – easy validation using ASP.NET MVC Model Binders, MVC’s Validation components, and Enterprise Library’s Validation block.&amp;#160; The preceeding should work like a charm, but me being the perpetual perfectionist and idealist saw one more piece of duplication that I wanted to remove.&amp;#160; Namely, the &lt;i&gt;foreach&lt;/i&gt; loop used to map the &lt;i&gt;ValidationResults&lt;/i&gt; to the &lt;i&gt;ModelState&lt;/i&gt;.&amp;#160; Using an extension method to extend the &lt;i&gt;ValidationResults&lt;/i&gt; class, this duplication can easily be removed like so: &lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;wlWriterEditableSmartContent&quot; id=&quot;scid:812469c5-0cb0-4c63-8c15-c81123a09de7:477976d8-c7bd-401a-b2ef-ae2e1626d779&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;&lt;pre name=&quot;code&quot; class=&quot;c#&quot;&gt;using System.Web.Mvc;
using Microsoft.Practices.EnterpriseLibrary.Validation;

public static class EntLibValidationExtensions
{
public static void CopyToModelState(this ValidationResults results, ModelStateDictionary modelState)
{
foreach (var result in results)
modelState.AddModelError(result.Key ?? &quot;_FORM&quot;, result.Message);
}
}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;Now the previous Action looks just a bit cleaner: &lt;br /&gt;
&lt;div class=&quot;wlWriterEditableSmartContent&quot; id=&quot;scid:812469c5-0cb0-4c63-8c15-c81123a09de7:db573bfc-5e79-4ee7-b993-20721a89be8b&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;&lt;pre name=&quot;code&quot; class=&quot;c#&quot;&gt;[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Product product)
{
var validationResult = product.Validate();
if (!validationResult.IsValid)
{
validationResult.CopyToModelState(this.ModelState);
return View(product);
}

productRepository.Add(product);
return View(&quot;Index&quot;);
}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;And with that, I’m happy…&amp;#160; What do you think??&lt;/p&gt;</description><link>http://jesschadwick.blogspot.com/2009/04/cleaner-validation-with-aspnet-mvc.html</link><author>noreply@blogger.com (Jess Chadwick)</author><thr:total>3</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-1712842956731739626</guid><pubDate>Tue, 10 Mar 2009 18:28:00 +0000</pubDate><atom:updated>2009-03-10T14:28:34.146-04:00</atom:updated><title>Come Learn Silverlight 2 From a Master!</title><description>&lt;p&gt;Hey all - if you&#39;re in the Princeton, NJ area this coming Thursday (March 12th, 2009), be sure to stop by our monthly NJDOTNET User Group meeting because this month we will be hosting Jason Beres - international conference speaker, Microsoft MVP, and an author of the &lt;strong&gt;two&lt;/strong&gt; Silverlight Programmers References from WROX Press!&amp;#160; Jason is an incredible speaker and I strongly encourage you to do everything you can to attend this meeting!&amp;#160; Here are the details:&lt;/p&gt;  &lt;p&gt;&lt;i&gt;&lt;/i&gt;&lt;/p&gt;  &lt;p&gt;&lt;i&gt;What:&amp;#160; &lt;/i&gt;NJDOTNET March Meeting &amp;#8211; Understanding RIA&amp;#8217;s with Silverlight 2&lt;/p&gt;  &lt;p&gt;&lt;i&gt;When:&lt;/i&gt; &lt;b&gt;THIS Thursday&lt;/b&gt;, March 10, 2009&amp;#160; 6:15 PM &amp;#8211; 8:30 PM&lt;/p&gt;  &lt;p&gt;&lt;i&gt;Where:&amp;#160; &lt;/i&gt;Infragistics Corporate HQ&amp;#160; (&lt;a href=&quot;http://maps.live.com/default.aspx?v=2&amp;amp;FORM=LMLTCC&amp;amp;cp=40.288385~-74.557498&amp;amp;style=h&amp;amp;lvl=18&amp;amp;tilt=-90&amp;amp;dir=0&amp;amp;alt=-1000&amp;amp;scene=9105189&amp;amp;phx=0&amp;amp;phy=0&amp;amp;phscl=1&amp;amp;sp=Point.qqf6r38sm5db_Infragistics%20HQ____&amp;amp;encType=1&quot; target=&quot;_blank&quot;&gt;Click here for directions&lt;/a&gt;)&lt;/p&gt;  &lt;p&gt;&lt;i&gt;Who:&lt;/i&gt;     &lt;br /&gt;Jason Beres is the Director of Product Management for Infragistics, the world&amp;#8217;s leading publisher of presentation layer tools.&amp;#160; Jason is one of the founders of Florida .NET User Groups, he is the founder of the Central New Jersey .NET User Group, he is a Visual Basic .NET MVP, and he is on the INETA Speakers Bureau.&amp;#160; Jason is the author of several books on .NET development, including the recently published Silverlight 2 Programmers Reference from Wrox Press.&amp;#160; Jason is a national and international conference speaker; he is a frequent columnist for several .NET publications, and keeps very active in the .NET community.&lt;/p&gt;  &lt;p&gt;&lt;i&gt;Abstract:     &lt;br /&gt;&lt;/i&gt;&lt;strong&gt;Understanding RIA&amp;#8217;s with Silverlight 2     &lt;br /&gt;&lt;/strong&gt;In this code-focused talk, we&amp;#8217;ll look at the features in Silverlight 2 and how they can help you build better RIA (Rich Internet Application) experiences.&amp;#160; We&amp;#8217;ll look at the Silverlight development experience, how to build a Silverlight application with the new Silverlight 3 features, and how this will help you build rich line-of-business experiences using data binding, animations and media.&lt;/p&gt;  </description><link>http://jesschadwick.blogspot.com/2009/03/come-learn-silverlight-2-from-master.html</link><author>noreply@blogger.com (Jess Chadwick)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-1401965474492767499</guid><pubDate>Tue, 17 Feb 2009 08:10:00 +0000</pubDate><atom:updated>2009-04-19T00:47:55.034-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ASP.NET</category><category domain="http://www.blogger.com/atom/ns#">Tips and Tricks</category><title>Tag Mappings to the Rescue!</title><description>&lt;p&gt;Our recent project at work lately (and the main reason for my previous two months of blog silence) has been upgrading and re-theming our installation of Community Server.&amp;#160; I’ve written a few posts in the past on the couple of modules and customizations I’ve done for our current site, and this upgrade is no different.&amp;#160; In fact, I’ve had to do more!&amp;#160; The most recent one I did just a few minutes ago just happens to be &lt;strong&gt;not&lt;/strong&gt; Community Server-specific at all, but a regular ol’ ASP.NET trick, so I wanted to write about it first.&amp;#160; You’ll see more about the Community Server-specific customizations I’ve had to do following this post.&lt;/p&gt;  &lt;p&gt;Community Server sites are really just the “Community Server Platform” (which encompasses a whole lotta stuff!), and a customizable theme on top of that platform.&amp;#160; Like any well-made site, CS themes are plain ol’ ASPX pages with a mixture of user and server controls.&amp;#160; This leaves us with themes that have got somewhere between a dozen and a million pages with the following mark-up:&lt;/p&gt; &lt;div class=&quot;wlWriterEditableSmartContent&quot; id=&quot;scid:812469c5-0cb0-4c63-8c15-c81123a09de7:227dfd42-2175-45a8-8fec-120f5b78f8a9&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;&lt;pre name=&quot;code&quot; class=&quot;xml:nocontrols&quot;&gt;&amp;lt;CSForum:BreadCrumb runat=&quot;server&quot; Tag=&quot;Div&quot; /&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;… but I don’t like what it’s outputting and I want to override some of its behavior.&amp;#160; Overriding the control’s behavior is easy enough, of course – you just extend the class and throw in an &lt;strong&gt;override&lt;/strong&gt; here and there and you’re all good.&amp;#160; Now we’ve got our new control – &lt;em&gt;Infragistics.CommunityServer.Controls.ForumsBreadCrumb&lt;/em&gt; – and the trick is getting this nice shiny control in place.&amp;#160; Your first thought might be that we’re up for a massive global search n’ replace, right?&amp;#160; Wrong!&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I know I kinda ruined the surprise in the title of this post, but for those of you who skipped over that part, forget the global replace – it’s &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms164641.aspx&quot;&gt;tag mappings&lt;/a&gt; to the rescue!&amp;#160; Tag mappings allow you to substitute (or &lt;em&gt;map&lt;/em&gt; if you want to get technical) one control for another using a simple &lt;em&gt;web.config&lt;/em&gt; change!&amp;#160; In our case, we’ll do this:&lt;/p&gt;&lt;br /&gt;&lt;div class=&quot;wlWriterEditableSmartContent&quot; id=&quot;scid:812469c5-0cb0-4c63-8c15-c81123a09de7:9cfd485c-68eb-4e4e-8b89-efbb1878c694&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;&lt;pre name=&quot;code&quot; class=&quot;xml:nocontrols&quot;&gt;&amp;lt;pages&amp;gt;&lt;br /&gt;  &amp;lt;tagMapping&amp;gt;&lt;br /&gt;    &amp;lt;add &lt;br /&gt;  tagType=&quot;CommunityServer.Discussions.Controls.BreadCrumb&quot; &lt;br /&gt;  mappedTagType=&quot;Infragistics.CommunityServer.Controls.ForumsBreadCrumb&quot;/&amp;gt;&lt;br /&gt;  &amp;lt;/tagMapping&amp;gt;&lt;br /&gt;&amp;lt;/pages&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;It’s pretty straight-forward – you’re telling ASP.NET that everywhere you’ve used a tag in your markup (&lt;em&gt;tagType&lt;/em&gt;) you want to use another type instead (&lt;em&gt;mappedTagType&lt;/em&gt;).&amp;#160; This makes it really easy to override and/or extend the functionality of a control and use your custom version instead of the original, &lt;em&gt;without changing any of your code&lt;/em&gt;!&amp;#160; &lt;/p&gt;&lt;br /&gt;&lt;p&gt;This tactic can really help you reduce the risk of such a major change, since - I don’t know about you - but my history with global replacements in markup pages have more often than not cost me more problems (and time spent fixing those problems) than if I had just manually made all the replacements to begin with.&amp;#160; Next time you’re tempted to do a global replace on a control, take a couple of seconds to think about whether or not this tactic will work for you.&amp;#160; It might end up saving you quite a bit of time!&lt;/p&gt;&lt;br /&gt;&lt;p&gt;And, as always, happy coding!&lt;/p&gt;</description><link>http://jesschadwick.blogspot.com/2009/02/tag-mappings-to-rescue.html</link><author>noreply@blogger.com (Jess Chadwick)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3016850660716023308.post-695650976246415543</guid><pubDate>Fri, 19 Dec 2008 17:17:00 +0000</pubDate><atom:updated>2008-12-19T12:17:09.089-05:00</atom:updated><title>ASP.NET MVC Release: So close you can FEEL it!</title><description>&lt;p&gt;I had a great time reading &lt;a href=&quot;http://weblogs.asp.net/scottgu/archive/2008/12/19/asp-net-mvc-design-gallery-and-upcoming-view-improvements-with-the-asp-net-mvc-release-candidate.aspx&quot;&gt;ScottGu&#39;s blog post today&lt;/a&gt; discussing all of the cool new features coming in the RC. Some of them (like the View page template &lt;strong&gt;not &lt;/strong&gt;including a code-behind file) really got me excited, but I nearly freaked out when I got to the end and read this: &lt;/p&gt;  &lt;blockquote&gt;We&#39;ll be releasing the ASP.NET MVC Release Candidate in January. Our plan is to have that build be ASP.NET MVC V1 API and feature-complete and have zero known bugs. We&#39;ll give people a short period to upgrade to it, give it a good tire-kicking, and report any last minute issues they find. We&#39;ll then ship the official V1 release shortly after that (so not far off now). &lt;/blockquote&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;ASP.NET MVC v1 is SOOO close! I really feel like this framework has come a long way in its relatively short development lifetime and with all of the recent candy that&#39;s been added in the past few releases, I can just tell that it will be a &lt;em&gt;wonderful&lt;/em&gt; platform to develop on for years to come. &lt;/p&gt;  &lt;p&gt;Microsoft... ScottGu (and the rest of the MVC team)... You ROCK. I can not wait to be working in this framework on a daily basis.&lt;/p&gt;  </description><link>http://jesschadwick.blogspot.com/2008/12/aspnet-mvc-release-so-close-you-can.html</link><author>noreply@blogger.com (Jess Chadwick)</author><thr:total>0</thr:total></item></channel></rss>