<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-667519048881938478</id><updated>2012-02-16T03:16:03.955-06:00</updated><category term='Reviews'/><category term='Code'/><category term='Troubleshoot'/><category term='Technology'/><title type='text'>Obishawn</title><subtitle type='html'>Help me Obishawn Kenobi! You're my only hope!</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>31</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-8736664626729013111</id><published>2009-12-01T14:01:00.001-06:00</published><updated>2009-12-01T14:01:54.056-06:00</updated><title type='text'>Hiring a Programmer</title><content type='html'>&lt;p&gt;Next time I need to find and hire a new programmer (which I hope won't be for a long time), I think I'm going to follow&amp;#160; &lt;a href="http://www.aaronsw.com/weblog/hiring" target="_blank"&gt;Aaron Swartz's hiring process&lt;/a&gt;.&amp;#160; Thanks for the tweet on this &lt;a href="http://twitter.com/brandonmartinez/statuses/6201648007" target="_blank"&gt;Brandon&lt;/a&gt;!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-8736664626729013111?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/8736664626729013111/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=8736664626729013111' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/8736664626729013111'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/8736664626729013111'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2009/12/hiring-programmer.html' title='Hiring a Programmer'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-5606913321213339398</id><published>2009-12-01T09:50:00.002-06:00</published><updated>2009-12-01T12:18:20.968-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Code'/><title type='text'>LINQ Success Story</title><content type='html'>&lt;p&gt;While processing some order data that comes in via a SOAP web service, I needed to check to make sure that user would not exceed the maximum allowable quantity for that product for the month.&amp;#160; Easy enough, I started looping through the products and checked the quantity against how much they've ordered that month.&amp;#160; It then occurred to me that I needed to make sure that if they ordered the product twice in the same order (placed the item in the shopping cart twice resulting in two line items on the order), then I total the quantity.&amp;#160; Think about how I would do this in the past, I'd be looping through all of the line items in the list multiple times.&lt;/p&gt;  &lt;p&gt;With LINQ, it was simple to code up:&lt;/p&gt;  &lt;pre name="code" class="c-sharp"&gt;var products = from i in request.LineItems
               group i by i.ProductID
               into p
                select new {ProductID = p.Key, Quantity = p.Sum(i =&amp;gt; i.Quantity)};&lt;/pre&gt;

&lt;p&gt;I could then loop through products and once and leave LINQ take care of the ugliness of grouping the products and totaling their quantities.&lt;/p&gt;

&lt;p&gt;While this is a very simple example of LINQ and doesn't show it's full power or potential, it does demonstrate how it can be used in normal code using standard collection objects to simplify your code and still get the job done.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:f5916790-0c8b-4829-840c-8bc5472e651a" class="wlWriterSmartContent"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/.NET" rel="tag"&gt;.NET&lt;/a&gt;,&lt;a href="http://technorati.com/tags/LINQ" rel="tag"&gt;LINQ&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-5606913321213339398?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/5606913321213339398/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=5606913321213339398' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/5606913321213339398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/5606913321213339398'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2009/12/linq-success-story.html' title='LINQ Success Story'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-8286070569201805963</id><published>2008-11-01T05:00:00.000-05:00</published><updated>2008-11-01T05:00:00.581-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><title type='text'>"Software Tools You Should Be Using and Blogs You Should Be Reading"</title><content type='html'>&lt;p&gt;I've read so many &lt;a href="http://www.digg.com" target="_blank" rel="nofollow"&gt;Dugg&lt;/a&gt; and &lt;a href="http://www.dotnetkicks.com/" target="_blank" rel="nofollow"&gt;Kicked&lt;/a&gt; articles about &amp;quot;Top 10 Tools&amp;quot; or &amp;quot;Top 10 Blogs&amp;quot;, etc. that you should be using and probably aren't.&amp;#160; Every time I read one I think, what makes that person the authority on this topic and what research did they do to determine that yes, in fact these &lt;em&gt;are&lt;/em&gt; the top 10 tools or blogs?&amp;#160; But ultimately it's just a title that is meant to draw your attention to tell you what tools that person or team is using or blogs they read.&amp;#160; And who knows, you may even find a tool or blog that you've never heard of but is just the one you've been looking for.&lt;/p&gt;  &lt;p&gt;However, there's a problem with these articles.&amp;#160; There's a huge portion (&amp;quot;huge&amp;quot; added for dramatic effect, I have no research showing exactly how much) of the target audience that isn't even reading that article.&amp;#160; There are developers out there, probably working for a small company on a team of 5 or less that simply will never end up reading that article or hearing about those tools.&amp;#160; They may even be ignorant to the fact that such things exist.&amp;#160; These people are the ones who need to be reading these articles the most.&amp;#160; They are the ones positioned to gain the most benefit from it.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; margin: 0px 30px 25px 0px; border-right-width: 0px" height="240" alt="Toolbox" src="http://lh3.ggpht.com/_G-EaCXQWtBw/SQtnKwdM5QI/AAAAAAAAAhw/iZ1UVi4vMBA/iStock_000003814755XSmall%5B5%5D.jpg?imgmax=800" width="160" align="left" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;I'm not saying that anyone that works for a small company on a team of 5 or less fits in that category.&amp;#160; I work for just such a company yet I do not fit in that category.&amp;#160; In fact, I and a colleague brought a toolset to the company I currently work for and the other developers didn't realize that there were such tools out there or maybe just never bothered to really try to find them.&amp;#160; We've recently brought a new developer onboard and even in his experience working for several companies, including software development contracting companies, had never seen a toolset as large as the one we had constructed at this company.&amp;#160; We're talking the basics: source control, build processes, development aids such as &lt;a href="notepad-plus.sourceforge.net" target="_blank" rel="nofollow"&gt;Notepad++&lt;/a&gt; and &lt;a href="http://www.regexbuddy.com/" target="_blank" rel="nofollow"&gt;RegexBuddy&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;So what makes us different from the developers that don't have an extensive toolset?&amp;#160; Much of the suggestions I'm about to make extend beyond the tools you use and into the improvement within your field in general. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Read the best blogs and technology sites&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This one has been preached several times over.&amp;#160; I'm guilty not doing this one well though.&amp;#160; I read a couple, but I don't read the best ones and I tend to gloss over too many articles without actually paying attention to them.&lt;/p&gt;  &lt;p&gt;This also requires changing your habits from time to time.&amp;#160; Blogs and technology sites go stale or become polluted with bad information.&amp;#160; Sometimes you have to give up on a site and move on to the next one.&amp;#160; Don't be afraid to abandon one of your favorite sites after it has gone bad or lost the lead.&amp;#160; Don't let their falling behind let you fall behind.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Strive for improvement&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;It's not just a matter of reading news on technology sites or reading popular blogs to try to stay on top of your field.&amp;#160; You have to be constantly on the lookout for better ways to do what you're doing.&amp;#160; You're not going to be spoon-fed every new tool, better process, better techniques or new technology.&amp;#160; Sometimes you have to go hunt for a better way by yourself.&lt;/p&gt;  &lt;p&gt;Don't be satisfied with Notepad to record your notes or edit your text files.&amp;#160; There's Notepad++ and it's free!&amp;#160; Better yet, there's &lt;a href="http://office.microsoft.com/onenote" target="_blank" rel="nofollow"&gt;Microsoft OneNote&lt;/a&gt; for keeping track of your notes.&amp;#160; Don't want to pay for OneNote?&amp;#160; How about &lt;a href="http://notebook.zoho.com/" target="_blank" rel="nofollow"&gt;Zoho Notebook&lt;/a&gt; or &lt;a href="http://notebook.google.com/" target="_blank" rel="nofollow"&gt;Google Notebook&lt;/a&gt;?&amp;#160; Software constantly breaking because you and another developer deploy from your local working copy and end up ultimately overwriting each other's changes?&amp;#160; Set up a build server and build process.&amp;#160; It's what all the big boys do and maybe it's time you do too even if you're working for a Mom and Pop shop.&amp;#160; As long as it can improve your process, why not consider it?&amp;#160; &lt;a href="http://nant.sourceforge.net/" target="_blank" rel="nofollow"&gt;NAnt&lt;/a&gt; does wonders for creating a build process and &lt;a href="http://cruisecontrol.sourceforge.net/" target="_blank" rel="nofollow"&gt;CruiseControl.NET&lt;/a&gt; is great for setting up the build server.&amp;#160; Both are free and XML based so they're fairly easy to work with.&amp;#160; Don't like those?&amp;#160; Search for more.&amp;#160; Search for better.&lt;/p&gt;  &lt;p&gt;Also, when reading technology articles about the 'Top 10 Blabity Blah', don't be satisfied with what the author is telling you.&amp;#160; Look for better.&amp;#160; You may stumble upon a whole new slew of tools and blogs and ways of doing things that you've never heard of.&lt;/p&gt;  &lt;p&gt;The same can be said for developing and testing software.&amp;#160; Don't be satisfied writing code the same way you used to.&amp;#160; Learn about design patterns, development methodologies, software testing techniques.&lt;/p&gt;  &lt;p&gt;You have to be constantly hungry for knowledge.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Be curious&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Don't shy away from the unknown.&amp;#160; Take a look at the ads on your favorite blogs or the technology site that you just discovered searching for a solution to your problem.&amp;#160; Hear something you've never heard of?&amp;#160; Google it.&amp;#160; Learn more about it.&amp;#160; It may not be as complicated as you think or it could help you in ways you've never dreamed.&lt;/p&gt;  &lt;p&gt;A colleague once asked me if I had ever heard of 'Inversion of Control' (IoC).&amp;#160; I hadn't.&amp;#160; I read about it on Wikipedia and kind of got it.&amp;#160; But I was curious so I kept digging.&amp;#160; I found out about 'Dependency Injection' (DI) and 'Aspect Oriented Programming' (AOP).&amp;#160; All of which I was never taught about in college.&amp;#160; Never anything even remotely similar to these.&amp;#160; This also led me to the Spring.NET framework.&amp;#160; I started playing around with Spring.NET and within a month had employed IoC/DI and AOP and it greatly reduced the complexity of my code, decreased the development time and increased the unit testability and the system testability of the application.&lt;/p&gt;  &lt;p&gt;On another day, I had been searching for the solution to a problem and saw an ad for &lt;a href="http://www.xhtmlit.com" target="_blank" rel="nofollow"&gt;XHTMLiT&lt;/a&gt;.&amp;#160; This company claimed to take any design file (of the popular file types such as PSD, PNG and AI) and generate valid XHTML and CCS.&amp;#160; They also said all the right things such as 'table-less' design (if you want), hand-coded and more.&amp;#160; All this in 8 business hours and for an extremely low price!&amp;#160; I was curious and decided on an upcoming web site revamp to try them out.&amp;#160; The price fit well within the budget and if they could get it taken care of in 8 hours, then they'd save me a bunch of time.&amp;#160; Sure enough, they delivered and got it done in far less time than it would have taken me.&amp;#160; If I hadn't taken the time to click that ad, I would have added probably a week or more to the schedule for that project.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Listen to others and more than that, &lt;em&gt;talk&lt;/em&gt; to others&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Don't wait for your friends or colleagues to tell you what they are doing or what they are using.&amp;#160; Ask them.&amp;#160; A vast portion of my knowledge and tools I use have been conveyed to me from one of my colleagues.&amp;#160; He does a lot of the footwork for gathering the information and I basically leech off of his knowledge.&amp;#160; Ok, I don't leech.&amp;#160; I do reciprocate.&amp;#160; I educated him on Spring.NET, AOP, IoC and DI.&amp;#160; So when I say 'talk' to others, I also mean that you should volunteer your knowledge.&amp;#160; They may be one of the people waiting to be spoon-fed.&amp;#160; So spoon-feed them once in a while and then educate them on how you learn about everything.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Don't be afraid to experiment&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;You have to experiment and play with new tools, technology and techniques before you can become familiar with them.&amp;#160; It's a rare breed that can simply read about something and put it into play the next day.&amp;#160; The first couple tries at using something may not be pretty.&amp;#160; But you learn more from your mistakes than you do from your successes.&amp;#160; Edison himself learned 2000 ways not to make a light bulb.&lt;/p&gt;  &lt;p&gt;The toughest part about this one is that you either have to experiment on your company's time or your time.&amp;#160; The choice is yours, but either way, you have to do it.&amp;#160; Sometimes just monkeying with something helps you figure it out easier than reading about it or being taught about it and you can learn things about it that may not have been obvious or documented or taught.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Don't accept the world the way it is&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Just because a set of processes, tools, etc. are already in place does not mean that they are the best.&amp;#160; Be the butterfly flapping its wings off the coast of India that causes a tornado in Kansas.&amp;#160; Speak up.&amp;#160; Suggest the new stuff.&amp;#160; Even if they don't change to what you suggest, it may be the catalyst for other change.&amp;#160; And sometimes you have to be more forceful.&amp;#160; Sometimes you have to implement a new tool without anyone knowing just so you can prove to them that it works.&amp;#160; Be smart when choosing to do this, but don't be afraid to do it if you think it will work.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Don't be afraid to throw the old stuff out&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Things change all the time.&amp;#160; Tools, processes, methodologies, none of these live in a bubble.&amp;#160; They are subject to the same rules as everything else and thus they change as well.&amp;#160; When a tool just doesn't cut it anymore, get rid of it.&amp;#160; You may love it, have a long history with it and are an expert with it, but if it doesn't get the job done, then what good is it?&amp;#160; Throw it away and get a new one.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;You must unlearn that which you have learned.&lt;/p&gt;    &lt;p&gt;When you have a hammer, everything looks like a nail.&amp;#160; When you have a better hammer, everything still looks like a nail, but the nails are easier to pound.&lt;/p&gt;    &lt;p&gt;I've got a million of these... Ok, I don't.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;strong&gt;Keep your eyes open&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;One of things I have seen done as part of Lean is to observe your day-to-day tasks.&amp;#160; Even go as far as video tape your day.&amp;#160; Then analyze it.&amp;#160; Really scrutinize it for waste.&amp;#160; If you find waste, try to figure out if there's a tool that would be helpful in reducing or eliminating that waste.&amp;#160; Be mindful of what you are doing.&amp;#160; Things that are repetitive that we've done day in and day out are often glossed over and not seen as waste because we do them all the time and don't think twice of why we do it the way we do.&amp;#160; Find these tasks and ask why you do them that way and if there's a better way to do it or if there is something that will help you do it better or faster. &lt;/p&gt;  &lt;p&gt;Not everything I suggested here is always feasible within a company because you are dealing with their money and time.&amp;#160; I can't go learn a new tool if my company doesn't allow me or I don't have the time.&amp;#160; Just be smart and you can sometimes find ways.&amp;#160; Explain to your manager how it could benefit the company and in the long run save them money.&amp;#160; But just because it may be difficult to follow these suggestions does not mean that they are any less valid of points.&lt;/p&gt;  &lt;p&gt;Got any other suggestions?&amp;#160; Leave a comment.&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:fa9c2138-3e86-46f1-a66d-d6017de00abc" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Development%20Tools" rel="tag"&gt;Development Tools&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-8286070569201805963?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/8286070569201805963/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=8286070569201805963' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/8286070569201805963'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/8286070569201805963'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2008/11/tools-you-should-be-using-and-blogs-you.html' title='&amp;quot;Software Tools You Should Be Using and Blogs You Should Be Reading&amp;quot;'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_G-EaCXQWtBw/SQtnKwdM5QI/AAAAAAAAAhw/iZ1UVi4vMBA/s72-c/iStock_000003814755XSmall%5B5%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-3491165710871336535</id><published>2008-09-10T16:52:00.001-05:00</published><updated>2008-09-10T16:52:42.861-05:00</updated><title type='text'>One Scary Judge Of Talent</title><content type='html'>&lt;p&gt;How does a programmer judge how talented he or she is?&lt;/p&gt;  &lt;p&gt;I got to thinking today about one of my major projects.&amp;#160; It's a vital piece of our daily business and would cost the company a &lt;strong&gt;large&lt;/strong&gt; amount of money if it came grinding to a halt for a day.&lt;/p&gt;  &lt;p&gt;There are two new branches of this application that were recently rolled out and while I was rolling the first out I worked extensively with the team that would be benefiting from this branch to get this developed to meet their needs.&amp;#160; After I rolled it out, it was modified slightly to become the second branch that was rolled out.&amp;#160; I haven't heard much from the team that is using that second branch but I know it gets used heavily and they benefit dramatically from it.&amp;#160; In fact, as I thought about it, I hadn't heard from the first team in a while either.&amp;#160; I called someone up from the second team to find out how things were going and she said things were going great! and thanked me for checking in.&lt;/p&gt;  &lt;p&gt;I'm not saying I'm talented (I'll leave that up to my peers to decide), but I did take a large amount of pride in my work today.&amp;#160; If I were to try to judge how talented I was, I would take the fact that this &lt;em&gt;major&lt;/em&gt; piece of software that is used so heavily and has had no complaints against it or feature requests for it to assist in that judgement.&lt;/p&gt;  &lt;p&gt;I admit this could also mean that people have come to live with it, deal with the problems and have been too lazy to request new features or think the feature requests will fall on deaf ears.&amp;#160; However, this software hasn't been out long enough for people to &amp;quot;learn to deal with it&amp;quot; and the second team sounded very pleased with it making me believe they truly have no feature requests at this time.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-3491165710871336535?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/3491165710871336535/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=3491165710871336535' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/3491165710871336535'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/3491165710871336535'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2008/09/one-scary-judge-of-talent.html' title='One Scary Judge Of Talent'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-8916007646093126294</id><published>2008-07-10T15:02:00.001-05:00</published><updated>2008-07-10T15:17:18.414-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Code'/><title type='text'>Development vs. Production Web.config</title><content type='html'>&lt;p&gt;One of the big pains that I've run into creating a build process for a web site is the web.config.&amp;#160; &lt;strong&gt;When running in development, the web.config needs a certain set of development-only settings that get changed for production.&lt;/strong&gt;&amp;#160; For example connection strings.&amp;#160; When developing, the web.config points to the development database but in production, it should point to the production database.&lt;/p&gt;  &lt;p&gt;In the past I've kept two configuration files.&amp;#160; Web.config and Release.config.&amp;#160; At build time, the web.config was overwritten with a copy of the release.config.&amp;#160; Horrible you say?&amp;#160; Yeah, I know.&amp;#160; For those that it's not obvious to, the release.config and web.config will contain a lot of duplicate information.&amp;#160; Especially if you extend the web.config with your own custom configuration sections.&amp;#160; Let the synchronization issues ensue!&lt;/p&gt;  &lt;p&gt;The ideal solution to handling the web.config is simply to change those values that you want changed.&amp;#160; But how to do this without writing some kind of script to find and replace these values?&lt;/p&gt;  &lt;p&gt;Thankfully, the configuration file is just XML.&amp;#160; &lt;strong&gt;XML can be easily modified using XSLT.&lt;/strong&gt;&amp;#160; And guess what!&amp;#160; &lt;a href="http://nant.sourceforge.net/" target="_blank" rel="nofollow"&gt;NAnt&lt;/a&gt; (our build script language of choice) has a &amp;lt;style&amp;gt; step that allows you to perform an XML transformation with XSLT.&amp;#160; Ok, the only thing I needed now was time to get back up to speed on XSLT.&amp;#160; As you may have guessed it, I'm writing this post because I found that time.&amp;#160; Below is the code needed to make those changes.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;XSLT:&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:9553a754-639b-4e3f-b1ff-09ad7a395c84" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;
&amp;lt;xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
&amp;gt;
	&amp;lt;xsl:output method="xml" indent="yes"/&amp;gt;

	&amp;lt;!--Copy every node from the web.config applying templates when possible--&amp;gt;
	&amp;lt;xsl:template match="@* | node()"&amp;gt;
		&amp;lt;xsl:copy&amp;gt;
			&amp;lt;xsl:apply-templates select="@* | node()"/&amp;gt;
		&amp;lt;/xsl:copy&amp;gt;
	&amp;lt;/xsl:template&amp;gt;

	&amp;lt;!--Remove custom debugging app settings--&amp;gt;
	&amp;lt;xsl:template match="/configuration/appSettings/add[@key='CreditCardTestMode']" /&amp;gt;

	&amp;lt;!--Remove Conditional Compilation Symbols - Removes the 'compilerOptions' attribute--&amp;gt;
	&amp;lt;!--If you use the DEBUG conditional compilation symbol, you will have to transform your web.config before compiling your website.--&amp;gt;
	&amp;lt;xsl:template match="/configuration/system.codedom/compilers/compiler/@compilerOptions" /&amp;gt;

	&amp;lt;!--Remove Debug Trust--&amp;gt; 
	&amp;lt;xsl:template match="/configuration/system.web/compilation/@debug"&amp;gt;
		&amp;lt;xsl:attribute name="debug"&amp;gt;false&amp;lt;/xsl:attribute&amp;gt;
	&amp;lt;/xsl:template&amp;gt;

	&amp;lt;!--Switch to production database--&amp;gt;
	&amp;lt;xsl:template match="/configuration/connectionStrings/add[@name='myDB']/@connectionString"&amp;gt;
		&amp;lt;xsl:attribute name="connectionString"&amp;gt;Data Source=SERVER; Initial Catalog=MYDB; User ID=DBO; Password=REALLYSTRONGPASSWORD;Application Name=APPLICATION;&amp;lt;/xsl:attribute&amp;gt;
	&amp;lt;/xsl:template&amp;gt;

&amp;lt;/xsl:stylesheet&amp;gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NAnt Step:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:98f0ed1a-e954-4d2f-a69b-49ecfc144a8c" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;!--Build website using the aspnet compiler--&amp;gt;
...

&amp;lt;!--Modify web.config for production--&amp;gt;
&amp;lt;style style="${buildfiles.path}webconfig.xslt" in="web.config" out="${website.output.path}web.config" /&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;One of the other big hurdles is the DEBUG conditional compilation symbol.&amp;#160; Most of our web projects depend on that symbol so things happen a little different while in development (such as exception handling).&amp;#160; Because of this, our web.config would have to be transformed &lt;em&gt;before&lt;/em&gt; we compiled.&amp;#160; Thankfully, that code should be able to be removed from the web project and moved into the supporting project.&amp;#160; Yay!&amp;#160; Less code in the web project!&amp;#160; I'm all for less code in the web project.&amp;#160; That's the way it should be.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:e33ccb15-d458-421c-950c-25e5b0d6b960" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/XML" rel="tag"&gt;XML&lt;/a&gt;,&lt;a href="http://technorati.com/tags/ASP.NET" rel="tag"&gt;ASP.NET&lt;/a&gt;,&lt;a href="http://technorati.com/tags/web.config" rel="tag"&gt;web.config&lt;/a&gt;,&lt;a href="http://technorati.com/tags/.NET" rel="tag"&gt;.NET&lt;/a&gt;,&lt;a href="http://technorati.com/tags/XSLT" rel="tag"&gt;XSLT&lt;/a&gt;,&lt;a href="http://technorati.com/tags/NAnt" rel="tag"&gt;NAnt&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-8916007646093126294?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/8916007646093126294/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=8916007646093126294' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/8916007646093126294'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/8916007646093126294'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2008/07/development-vs-production-webconfig.html' title='Development vs. Production Web.config'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-6691332129376324890</id><published>2008-06-12T05:00:00.000-05:00</published><updated>2008-06-12T05:00:03.657-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Code'/><title type='text'>Why You SHOULD Have 100% Code Test Coverage</title><content type='html'>&lt;p&gt;I recently wrote a post about the level of &lt;a href="http://blog.obishawn.com/2008/05/ninja-level-code-coverage.html" target="_blank"&gt;code coverage&lt;/a&gt; that I achieved on a project that I was working on.&amp;#160; Then I started seeing articles about how 100% code coverage is a fallacy, or how code coverage tools are &amp;quot;evil&amp;quot;.&amp;#160; I disagree.&lt;/p&gt;  &lt;p align="center"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="240" alt="iStock_000003827645XSmall" src="http://lh3.ggpht.com/blog.obishawn/SFAm-VBdWdI/AAAAAAAAAhs/A7mv8O3D0zQ/iStock_000003827645XSmall%5B4%5D.jpg?imgmax=800" width="160" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;Ok, before everyone kills me, let me explain.&amp;#160; I do agree to the following:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Code coverage numbers can be abused (just like a defect/bug count) &lt;/li&gt;    &lt;li&gt;Code coverage is &lt;strong&gt;NOT&lt;/strong&gt; and indicator of how well tested your code is &lt;/li&gt;    &lt;li&gt;Code coverage number should never be used by themselves to draw any sort of conclusion about the code &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;strong&gt;Argument 1: It's Waste of Time&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;The first argument that I saw was that testing simple pieces of code such as simple getter/setter properties is a waste of time that can better used writing a unit test for a more complex piece of code.&amp;#160; So more bang for your buck.&lt;/p&gt;  &lt;p&gt;You don't have to waste your time writing tests for simple getter/setter properties.&amp;#160; &lt;strong&gt;A good testing framework can take care of this for you with little or no work on your part.&lt;/strong&gt;&amp;#160; &lt;a href="http://james.newtonking.com/projects/utilities-net.aspx" target="_blank" rel="nofollow"&gt;NewtonSoft Utilities.NET&lt;/a&gt; contains a class that will dynamically test all of your properties.&amp;#160; Using this utility, you can write a single unit test that tests all of your properties on a class.&amp;#160; And this unit test can copied and pasted with one or two minor modifications to test the next class.&amp;#160; Elapsed time: 30 seconds to create class, write function and run test.&lt;/p&gt;  &lt;p&gt;In addition, &lt;strong&gt;no unit test should ever be considered a waste of time&lt;/strong&gt;.&amp;#160; A single unit test is meant to test a single scenario and that unit test will also ensure that chunk of code will always behave as expected in that scenario.&amp;#160; What starts as a simple getter/setter property may evolve to a more complex one and the unit tests written for that property will ensure that the evolution of that property does not sacrifice functionality without you know about it.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Argument 2: Trust Your Programming Language/Framework&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Another argument against testing things such as simple getter/setter properties is that why would you not trust your programming language/framework/environment to perform a simple get or set operation?&lt;/p&gt;  &lt;p&gt;Why &lt;em&gt;would&lt;/em&gt; you trust your programming language/framework/environment?&amp;#160; &lt;strong&gt;Programming languages are software and thus can contain bugs too&lt;/strong&gt;.&amp;#160; Now the likelihood that you will ever encounter such a bug is low, but why take the risk?&amp;#160; As long as you have a good testing framework as I stated above and unit testing your properties takes little or no time, then it is far better to catch the bug in unit tests than in production code.&lt;/p&gt;  &lt;p&gt;More importantly, &lt;strong&gt;unit testing the simple pieces of code is not about not trusting your programming language but rather not trusting yourself.&lt;/strong&gt;&amp;#160; I, and I'm sure most of you, have at one time or another fat-fingered something in code.&amp;#160; There are numerous ways to screw up on a simple property.&amp;#160; How about having the following?&amp;#160; It is very easy to do the following, especially with code-completion.&amp;#160; This is not really a bug you want making it into production code, especially if a single unit test would have exposed this.&amp;#160; And if the problem doesn't immediately stand out at you, then you've proved my point.&amp;#160; And now imagine this property inside of a class with other code and documentation.&amp;#160; Suddenly this bug because camouflaged and less easy to see with the naked eye.&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:fbc5781c-1209-4aae-9d49-bffa5d04546e" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public int Width
{
	get { return Width; }
	set { _width = value;}
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Argument 3: Code Coverage Is Not An Indicator Of Code Quality&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This argument is half true.&amp;#160; The true reason that code coverage can not be used as an indicator of how well the code is written is because code coverage only indicates that the individual lines were executed.&amp;#160; It does not indicate what combination of individual lines were executed.&amp;#160; In other words, it says nothing about code execution paths.&lt;/p&gt;

&lt;p&gt;However, &lt;strong&gt;code coverage can help indicate how modularized the code is&lt;/strong&gt;.&amp;#160; What?!&amp;#160; I said it &lt;em&gt;helps&lt;/em&gt; indicate that.&amp;#160; If you have complex code, the quicker you are able to achieve 100% code coverage (or a high level of code coverage), the more modularized your code possibly is.&amp;#160; Very modular code means that the individual pieces of your code are smaller and less dependent on other pieces of code.&amp;#160; This in turn means that your unit tests will be smaller, more focused and require less setup.&amp;#160; Given all of that, the unit tests should be quicker to write. &lt;/p&gt;

&lt;p&gt;In my previous post about code coverage, I stated that I employed IoC/DI and AOP and was able to achieve a high level of code coverage very quickly and every class was either 100% covered or 0% covered and the 0% covered classes were very small and contained &amp;quot;untestable&amp;quot; code.&amp;#160; The application had its complexities, yet I was able to achieve this code coverage scenario relatively quickly.&amp;#160; Analyzing the code showed that it was very modular.&amp;#160; TDD yields the same results.&amp;#160; Modular code with high code coverage.&lt;/p&gt;

&lt;p&gt;Having modular code means that you should be able to write more unit tests quicker and more effective unit tests because they are more focused on smaller pieces of code.&amp;#160; This could lead to more quality code.&amp;#160; It is important to note that highly tested modular code does not guarantee quality.&amp;#160; But the chances of it are higher.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While it does not give you the world, &lt;strong&gt;aiming for 100% code coverage does help you write better software&lt;/strong&gt; depending on the steps you take to achieve this high code coverage.&amp;#160; Code coverage in and of itself is not evil and the code coverage percentage does provide some useful insight when used in conjunction with other pieces of data about your code.&lt;/p&gt;

&lt;p&gt;Just as with everything else, &lt;strong&gt;the quality of your code depends on the methodologies, techniques and technology that you use coupled with your development skill level&lt;/strong&gt;.&amp;#160; Aiming for 100% code coverage is just another technique.&lt;/p&gt;

&lt;p&gt;Aim high.&amp;#160; Never let your grasp outreach your goals.&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:427831f6-4c8b-4995-80f7-e202e88876d8" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Code%20Coverage" rel="tag"&gt;Code Coverage&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Inversion%20of%20Control" rel="tag"&gt;Inversion of Control&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Dependency%20Injection" rel="tag"&gt;Dependency Injection&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Aspect%20Oriented%20Programming" rel="tag"&gt;Aspect Oriented Programming&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Test%20Driven%20Development" rel="tag"&gt;Test Driven Development&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-6691332129376324890?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/6691332129376324890/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=6691332129376324890' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/6691332129376324890'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/6691332129376324890'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2008/06/why-you-should-have-100-code-test.html' title='Why You SHOULD Have 100% Code Test Coverage'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/blog.obishawn/SFAm-VBdWdI/AAAAAAAAAhs/A7mv8O3D0zQ/s72-c/iStock_000003827645XSmall%5B4%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-2745801049335277405</id><published>2008-06-05T05:00:00.000-05:00</published><updated>2008-06-05T05:00:03.168-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Code'/><title type='text'>FeedBurner 404 Error</title><content type='html'>&lt;p&gt;I recently encountered a 404 error when attempting to fetch one of my RSS feeds from &lt;a href="http://www.feedburner.com/" target="_blank" rel="nofollow"&gt;FeedBurner&lt;/a&gt;.&amp;#160; I have a web application that requests the feed using an HttpWebRequest in .NET and then formats it and displays it on the page.&amp;#160; I could navigate to the feed just fine, but my web application stated that the connection could not be established because the server returned a 404-Not Found error.&amp;#160; This was working all the while, so something had to have changed somewhere (and it wasn't in the code since the code hasn't changed in a month according to source control).&amp;#160; Stepping through the code, I discovered that the URL that it was claiming it couldn't find was http://feedproxy.feedburner.com/....&amp;#160; The URL I was originally requesting was http://feeds.feedburner.com/..., so FeedBurner was redirecting my request for some reason.&amp;#160; Using &lt;a href="http://addons.mozilla.org/en-US/firefox/addon/3829" target="_blank" rel="nofollow"&gt;Live HTTP Headers&lt;/a&gt; in Firefox, I could see that my browser was not receiving this redirect.&lt;/p&gt;  &lt;p&gt;Turns out that when I make the HttpWebRequest, if I supplied a UserAgent, then I didn't get redirected to that feedproxy.feedburner.com address.&amp;#160; I've been meaning to go back in and supply a UserAgent anyway.&amp;#160; I'm not sure what the feedproxy.feedburner.com URL does or why it went down, but supplying a UserAgent seems to avoid the redirect.&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:9102517e-2d56-40c6-9089-30fa0e81e4e5" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/.NET" rel="tag"&gt;.NET&lt;/a&gt;,&lt;a href="http://technorati.com/tags/FeedBurner" rel="tag"&gt;FeedBurner&lt;/a&gt;,&lt;a href="http://technorati.com/tags/RSS" rel="tag"&gt;RSS&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-2745801049335277405?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/2745801049335277405/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=2745801049335277405' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/2745801049335277405'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/2745801049335277405'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2008/06/feedburner-404-error.html' title='FeedBurner 404 Error'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-181339651437497515</id><published>2008-06-04T05:00:00.000-05:00</published><updated>2008-06-04T05:00:02.848-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Code'/><title type='text'>Empty EventArgs</title><content type='html'>&lt;p&gt;How many times have you written an event whose event handler just takes in a generic EventArgs object and when you raise that event you pass in &lt;strong&gt;new EventArgs()&lt;/strong&gt;?&amp;#160; Turns out the EventArgs class has a static read-only instance field &lt;strong&gt;EventArgs.Empty&lt;/strong&gt; that you can use so you don't have to instantiate a new copy of this class for no reason.&amp;#160; &lt;a href="http://msdn.microsoft.com/en-us/library/system.eventargs.empty.aspx" target="_blank" rel="nofollow"&gt;Microsoft's documentation&lt;/a&gt; says that this instance is the equivalent of calling the constructor.&amp;#160; Again the benefit is that this instance is already created.&lt;/p&gt;  &lt;p&gt;To quote &lt;a title="YTechie.com" href="http://www.ytechie.com/" target="_blank" rel="nofollow"&gt;a colleague&lt;/a&gt;, &amp;quot;Think of the performance boost we&amp;#8217;ll get!&amp;quot;&amp;#160; I'm fairly certain he was being sarcastic.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:d8433cbf-cfda-4b29-9efc-eaac1c097815" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public event EventHandler&amp;lt;EventArgs&amp;gt; MyEvent;

protected void OnMyEvent(EventArgs e)
{
	EventHandler&amp;lt;EventArgs&amp;gt; hnd = MyEvent;
	if (hnd != null) hnd(this, e);
}

public void DoSomething()
{
	OnMyEvent(EventArgs.Empty);
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:102949cd-0c8e-40e7-ad4e-4f19b92c073f" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/.NET" rel="tag"&gt;.NET&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-181339651437497515?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/181339651437497515/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=181339651437497515' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/181339651437497515'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/181339651437497515'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2008/06/empty-eventargs.html' title='Empty EventArgs'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-8827830363405094447</id><published>2008-06-03T05:00:00.000-05:00</published><updated>2008-06-03T05:00:02.395-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Code'/><title type='text'>Unit Testing Enum Value Support</title><content type='html'>&lt;p&gt;Let's say you have a function that takes in an enum value or uses an enum value fetched from some other source (a private class field, a property of an object passed in, etc.).&amp;#160; If a value is added to that enum, how do you write a unit test for that function so that it catches that something has to be added to your function to support that enum (or at minimum, you need to check to see if you have to add anything to the function to support it).&lt;/p&gt;  &lt;p&gt;I've already discussed how to put in a check for making sure that your function will bomb if an unsupported enum value is passed in in my &amp;quot;&lt;a href="http://blog.obishawn.com/2008/05/unit-testing-switch-statements.html" target="_blank"&gt;Unit Testing Switch Statements&lt;/a&gt;&amp;quot; post.&amp;#160; This takes it one step further to ensure that your unit tests catch the bombing of this function if a new enum value is added so that this bombing doesn't occur in production or even in QA's testing.&lt;/p&gt;  &lt;p&gt;Below I have an example of this situation.&amp;#160; I apologize for the crude example but it gets the point across on how to test this situation.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:d7b2bde3-e052-4571-af04-d52f279498da" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public enum CalculatorOperations
{
	Add,
	Subtract
}

public static class Calculator
{
	public static int PerformOperation(CalculatorOperations operation, int a, int b)
	{
		Check.Invariant(operation == CalculatorOperations.Add ||
		                operation == CalculatorOperations.Subtract,
		                string.Format("{0} is not a supported CalculatorOperations value.", operation));

		int result = 0;
		switch(operation)
		{
			case CalculatorOperations.Add:
				result = a + b;
				break;
			case CalculatorOperations.Subtract:
				result = a - b;
				break;
		}

		return result;
	}
}

[TestFixture]
public class Calculator_Tester
{
	[Test(Description = "Tests for unsupported CalculatorOptions values.")]
	public void Test01()
	{
		Type enumType = typeof (CalculatorOperations);
		foreach (FieldInfo field in enumType.GetFields(BindingFlags.Static | BindingFlags.Public))
		{
			CalculatorOperations operation = (CalculatorOperations) field.GetValue(null);
			Calculator.PerformOperation(operation, 1, 1);
		}
	}
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Now if I add Multiply and Divide to the CalculatorOperations enum, my unit test will fail because Calculator.PerformOperation will throw an exception on the unsupported value.&lt;/p&gt;

&lt;p&gt;Remember, &amp;quot;do nothing&amp;quot; is still an intended behavior.&amp;#160; So even if you don't explicitly use an enum value in a function, you need to have it in your &amp;quot;supported enum values&amp;quot; list to ensure that that value allows the function to perform the way it is intended to.&amp;#160; The added benefit of this technique is that it also catches scenarios that you haven't tested for.&amp;#160; Even if PerformOperation is going to return 0 (do nothing in the switch statement) when Multiply or Divide are passed in, then you need to write unit tests for those values and then add those enum values to the function's &amp;quot;supported enum values&amp;quot; list.&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:ba09ad56-9577-4b3a-8cd7-9c9cf91d8fde" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/.NET" rel="tag"&gt;.NET&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Unit%20Test" rel="tag"&gt;Unit Test&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-8827830363405094447?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/8827830363405094447/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=8827830363405094447' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/8827830363405094447'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/8827830363405094447'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2008/06/unit-testing-enum-value-support.html' title='Unit Testing Enum Value Support'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-1070071084639853198</id><published>2008-05-29T05:00:00.000-05:00</published><updated>2008-05-29T05:00:04.738-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Code'/><title type='text'>Workflow Runtime Manager - Streamlined Launching</title><content type='html'>&lt;p&gt;If you've read &lt;a href="http://www.amazon.com/Pro-WF-Windows-Workflow-Experts/dp/1590597788/ref=pd_bbs_sr_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1211995620&amp;amp;sr=8-1" target="_blank" rel="nofollow"&gt;Bruce Bukavics's &amp;quot;Pro WF - Windows Workflow in .NET 3.0&amp;quot;&lt;/a&gt;, you may have seen some code for a Workflow Runtime Manager that wraps common steps to managing your Workflow Runtime such as launching workflows, adding services, retrieving output parameters and capturing exceptions from a workflow instance.&lt;/p&gt;  &lt;p&gt;I expanded upon Bruce's implementation in two simple yet useful ways.&amp;#160; First, I created an interface from it.&amp;#160; I know, that's revolutionary! and nobody else would have ever though of that!&amp;#160; *cough*&amp;#160; *cough*&amp;#160; Anyway, that's not the point of this post.&amp;#160; I just needed to state that because I'm about to show you a clipping of the interface derived from Bruce's implementation.&lt;/p&gt;  &lt;p&gt;   &lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:1ab1037c-92c0-4434-b0aa-bceb80d635e1" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public interface IWorkflowRuntimeManager
{
	...
	WorkflowInstanceWrapper StartWorkflow(Type workflowType, Dictionary&amp;lt;string, object&amp;gt; parameters);
	...
}&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;The problem with this is that I still have to set up that dictionary of parameters.&amp;#160; And what if I want to launch this workflow from multiple locations in my code?&amp;#160; I have to reinvent the wheel each time.&amp;#160; And how do I ensure that everyone is supplying the correct set of input parameters and they're named the same?&amp;#160; That's easy!&amp;#160; With the addition of another interface.&lt;/p&gt;

&lt;p&gt;
  &lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:4bd2eca7-af83-46d2-8d0f-ba3d0558c60f" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;using System;
using System.Collections.Generic;

namespace Ipc.Framework.Workflow.Hosting
{
	/// &amp;lt;summary&amp;gt;
	///		Provides an interface for starting a workflow using
	///		&amp;lt;see cref="IWorkflowRuntimeManager"/&amp;gt;
	/// &amp;lt;/summary&amp;gt;
	public interface IWorkflowStartInfo
	{
		/// &amp;lt;summary&amp;gt;
		///		The type of workflow that the &amp;lt;see cref="IWorkflowRuntimeManager"/&amp;gt;
		///		implementation should create and launch.
		/// &amp;lt;/summary&amp;gt;
		Type WorkflowType { get; }

		/// &amp;lt;summary&amp;gt;
		///		The dictionary of parameters to feed to the new workflow instance.
		/// &amp;lt;/summary&amp;gt;
		Dictionary&amp;lt;string, object&amp;gt; Parameters { get; }
	}
}&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;This interface basically describes how to build a key to start the car.&amp;#160; I simply write a class that implements this interface for each workflow defined in my project.&amp;#160; See an example implementation below.&lt;/p&gt;

&lt;p&gt;
  &lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:a3947815-b98b-4dd0-bdd8-28efda7363ed" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public class HelpDeskCaseWorkflowStartInfo : IWorkflowStartInfo
{
	private const string PARAM_CASEID = "CaseId";

	private readonly Dictionary&amp;lt;string, object&amp;gt; _parameters;

	public HelpDeskCaseWorkflowStartInfo(int caseId)
	{
		_parameters = new Dictionary&amp;lt;string, object&amp;gt;();

		_parameters.Add(PARAM_CASEID, caseId);
	}

	#region IWorkflowStartInfo Members

	public Type WorkflowType
	{
		get { return typeof (HelpDeskCaseWorkflow); }
	}

	public Dictionary&amp;lt;string, object&amp;gt; Parameters
	{
		get { return _parameters; }
	}

	#endregion
}&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;And for the final step, let's expand the IWorkflowRuntimeManager interface as shown below.&amp;#160; The two functions accomplish the same task, but the second method allows compile-time binding of parameters wherever it is used (you just have to do the work to make sure that the parameter names you use in the implementation are correct).&lt;/p&gt;

&lt;p&gt;
  &lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:7100956c-3bf1-4c23-b67b-ac6a94397c3c" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public interface IWorkflowRuntimeManager
{
	...
	WorkflowInstanceWrapper StartWorkflow(Type workflowType, Dictionary&amp;lt;string, object&amp;gt; parameters);

	WorkflowInstanceWrapper StartWorkflow(IWorkflowStartInfo startInfo);
	...
}&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:41a35a89-36c2-41f3-af49-eafa5b72fe8d" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/.NET" rel="tag"&gt;.NET&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Windows%20Workflow%20Foundation" rel="tag"&gt;Windows Workflow Foundation&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-1070071084639853198?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/1070071084639853198/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=1070071084639853198' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/1070071084639853198'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/1070071084639853198'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2008/05/workflow-runtime-manager-streamlined.html' title='Workflow Runtime Manager - Streamlined Launching'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-8447047031855425489</id><published>2008-05-23T15:01:00.001-05:00</published><updated>2008-05-23T15:49:29.059-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Code'/><title type='text'>Workflow Foundation Anatomy</title><content type='html'>&lt;p&gt;One of my confusions that I ran into when I first started working with Microsoft's &lt;a href="http://msdn.microsoft.com/en-us/netframework/aa663328.aspx" target="_blank" rel="nofollow"&gt;Windows Workflow Foundation&lt;/a&gt; (WF) was how the WF was structured.&amp;#160; A lot of words were being thrown at me such as Workflow Runtime, Workflow Instance, Core Services, Local Services, and Host Application.&amp;#160; The book that I was reading to learn WF did a piss-poor job explaining these.&amp;#160; Hopefully I can explain them in a way that may help you if you've run into the same problem.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Host Application&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This one is fairly straight forward.&amp;#160; This is the application (Windows application, web application, web service, Windows service, etc) that creates and launches the workflow instances.&amp;#160; This is the guy that winds up the robot and lets it go.&lt;/p&gt;  &lt;p align="center"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="180" alt="iStock_000005521539XSmall" src="http://lh4.ggpht.com/blog.obishawn/SDct17NRrEI/AAAAAAAAAhk/bN8c8eOrlyg/iStock_000005521539XSmall%5B1%5D.jpg?imgmax=800" width="240" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Workflow Runtime&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This one is a little more tricky to describe, but the name basically does say it all again.&amp;#160; This is the runtime environment that the workflow instances run in.&amp;#160; The instances are created using the Workflow Runtime and the Workflow Runtime is the guy doing all of the work executing the instances.&amp;#160; The Workflow Runtime is the box that the robot operates in.&amp;#160; The Host Application will use the same box for all the robots doing similar tasks.&lt;/p&gt;  &lt;p&gt;The Runtime does a good job isolating the Host Application from the Workflow Instances.&amp;#160; If any Workflow Instance bombs, the Runtime reports it to the Host Application through an event.&amp;#160; Anything that happens to an instance gets reported through events.&amp;#160; So if an instance completes, terminates, aborts, etc., it is reported to the Host Application via an event.&amp;#160; So the robots in the box can't hurt you when they explode because the box is pretty strong and contain the blast.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Workflow Instance&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Ok, I've already been throwing this one around a bit, but I'm sure that you get this one already.&amp;#160; If I have a Workflow defined that takes in a set of input A and does an action B, when I need to fire off an execution of this workflow, I create an instance and give him to the Workflow Runtime to execute.&amp;#160; This instance of the workflow is the Workflow Instance (complicated isn't it?).&amp;#160; The Workflow Instance is the robot.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Core and Local Services&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Ok, this is where my robot analogy begins to get a little more complicated.&amp;#160; It is important to note here that the Core Services and Local Services are actually an &lt;a href="http://en.wikipedia.org/wiki/Inversion_of_Control" target="_blank" rel="nofollow"&gt;Inversion of Control&lt;/a&gt;.&amp;#160; Figuring this out helped me understand the Core and Local Services.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Local Services&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Local Services are kind of like the code behind a web service.&amp;#160; A Local Service is nothing more than a class that implements an interface that has the 'ExternalDataExchangeAttribute' applied to it.&amp;#160; A Workflow can call a method on a Local Service using the 'CallExternalMethodActivity'.&amp;#160; The Local Services are loaded into the Workflow Runtime when the Runtime is first being initialized.&amp;#160; The WF provides a way to configure a Workflow Runtime via the application configuration file, so these Local Services can be swapped out after the application has been deployed and thus change how the application can function.&amp;#160; To use the robot analogy, Local Services are basically port holes in the box that the robots can put items in and possibly get items back.&amp;#160; Maybe there is one port hole that the robot can put a chunk of gold in and get gold coins back.&amp;#160; Or maybe the robots just deposit the gold in a port hole and don't get anything back.&lt;/p&gt;  &lt;p&gt;For a real-life example, take a banking system.&amp;#160; I may have a Local Service that has functions defined for it such as CreateAccount, CloseAccount, DepositMoney, WithDrawMoney and GetBalance.&amp;#160; My Workflow can now use that Local Service via the interface that it implements (remember, the interface must have the 'ExternalDataExchangeAttribute' applied to it).&amp;#160; And after I've compiled and deployed my application to my test environment, I may want to switch out that Local Service with another one for testing (so that it doesn't hit against live data).&amp;#160; All I have to do is change my application configuration file and run the application again.&amp;#160; So instead of using MyCompany.MyApp.BankingSystem, I'm using MyCompany.MyApp.Testing.BankingSystem.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Core Services&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Core Services are even more tricky.&amp;#160; Core Services are software components for the Workflow Runtime written into WF.&amp;#160; They provide functionality such as Workflow Persistence and Tracking (among others).&amp;#160; These are add-on functionality components that you can use to enhance your Workflow experience.&amp;#160; The persistence service gives the Workflow Runtime the ability to save it's running state, including the running state of the Workflow Instances, to a SQL Server database in order to suspend and resume the Workflow Runtime and its Workflow Instances.&amp;#160; The tracking service allows you to track a Workflow Instances so you can watch its progress.&amp;#160; In the robot analogy, since the box (the Workflow Runtime) is basically a black box and I can't actually see the robots, I use the Tracking service to watch what they are doing.&amp;#160; I can hook that up to my Host Application and it's basically a monitor on the side of the box that I can watch any given robot and what it is working on.&amp;#160; Or maybe, it's a unit that records all of the robot's activities (the Persistence service) so if I need to power down the box for the night, the robots can pick up tomorrow where they left off.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Note: In order to use the Core and Local Services, any input or output in those service or Workflow parameters must use Serializable objects.&lt;/p&gt;  &lt;p&gt;Another Note: When using Local Services, objects are serialized, passed to the Local Service and passed back as a serialized object.&amp;#160; This means that the object going in is not going to be the same instance as the one coming back.&amp;#160; So if you have a Local Service that modifies an object, you're going to need to pass that object back.&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:fa293d24-08d5-4608-a037-5511f7abf94d" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Microsoft" rel="tag"&gt;Microsoft&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Windows%20Workflow%20Foundation" rel="tag"&gt;Windows Workflow Foundation&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Inversion%20of%20Control" rel="tag"&gt;Inversion of Control&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-8447047031855425489?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/8447047031855425489/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=8447047031855425489' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/8447047031855425489'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/8447047031855425489'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2008/05/workflow-foundation-anatomy.html' title='Workflow Foundation Anatomy'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/blog.obishawn/SDct17NRrEI/AAAAAAAAAhk/bN8c8eOrlyg/s72-c/iStock_000005521539XSmall%5B1%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-5004174870117452229</id><published>2008-05-22T05:00:00.000-05:00</published><updated>2008-05-22T05:00:03.901-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Code'/><title type='text'>Unit Testing Switch Statements</title><content type='html'>&lt;p&gt;A standard practice of mine when using switch statements with enum values is to throw a NotImplementedException on the default case.&amp;#160; This is so that when I add a new enum value, the function will bomb if I didn't account for that value in one of the switch statements.&lt;/p&gt;  &lt;p&gt;Take the following example.&amp;#160; I have an enum called MyValues.&amp;#160; I've recently added Value3.&amp;#160; All the unit tests that I've written for my method MyClass.DoSomething pass, so I'm done... Right?&amp;#160; Wrong!&amp;#160; My switch statement doesn't explicitly use the new value and it should.&amp;#160; The unit test technically passes because no exception is thrown, but I wanted it to do something with that value, but instead it did nothing.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:9369975b-013f-461a-b6f8-fa96e32c7f46" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public enum MyValues
{
	Value1,
	Value2,
	Value3 //	Added to support feature #123
}

public static class MyClass
{
	public static void DoSomething(MyValues myValue)
	{
		switch (myValue)
		{
			case MyValues.Value1:
				System.Console.WriteLine("Did first action.");
				break;
			case MyValues.Value2:
				System.Console.WriteLine("Did second action.");
				break;
		}
	}
}

[NUnit.Framework.TestFixture]
public class MyClass_Tester
{
	[NUnit.Framework.Test]
	public void DoSomething_Test01()
	{
		MyClass.DoSomething(MyValues.Value1);
	}

	[NUnit.Framework.Test]
	public void DoSomething_Test02()
	{
		MyClass.DoSomething(MyValues.Value2);
	}

	[NUnit.Framework.Test]
	public void DoSomething_Test03()
	{
		MyClass.DoSomething(MyValues.Value3);
	}
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Ok, let's go ahead and change that switch statement to now throw an exception on the default case.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:5b093ea2-2d67-49e0-b2a1-66c805ed92ae" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;switch (myValue)
{
	case MyValues.Value1:
		System.Console.WriteLine("Did first action.");
		break;
	case MyValues.Value2:
		System.Console.WriteLine("Did second action.");
		break;
	default:
		throw new System.NotImplementedException(
			string.Format("The switch statement does not have an implementation for the MyValues value {0}.", myValue));
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Now my unit test DoSomething_Test03() fails and I realize that I haven't accounted for MyValues.Value3 in MyClass.DoSomething.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:255709bd-32ae-478c-9b60-0ead04da0b29" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;switch (myValue)
{
	case MyValues.Value1:
		System.Console.WriteLine("Did first action.");
		break;
	case MyValues.Value2:
		System.Console.WriteLine("Did second action.");
		break;
	case MyValues.Value3:
		System.Console.WriteLine("Did third action.");
		break;
	default:
		throw new System.NotImplementedException(
			string.Format("The switch statement does not have an implementation for the MyValues value {0}.", myValue));
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;But I still haven't figured out how to test the default case in unit tests.&amp;#160; This means I do not have 100% code coverage.&amp;#160; It's a moot point as the default case is a simple throw statement, but I really want to achieve 100% code coverage on this class.&amp;#160; For this, I'm modifying the DoSomething method to employ a Design-By-Contract class (find the code &lt;a href="http://www.codeproject.com/KB/cs/designbycontract.aspx" target="_blank" rel="nofollow"&gt;here&lt;/a&gt;) to check the enum values&amp;#160; So now my code looks like this.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:a7fd78d4-a16f-4990-93a2-2ac5bca3178e" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public static class MyClass
{
	public static void DoSomething(MyValues myValue)
	{
		Check.Require(myValue == MyValues.Value1 || 
			myValue == MyValues.Value2 || 
			myValue == MyValues.Value3);

		switch (myValue)
		{
			case MyValues.Value1:
				System.Console.WriteLine("Did first action.");
				break;
			case MyValues.Value2:
				System.Console.WriteLine("Did second action.");
				break;
			case MyValues.Value3:
				System.Console.WriteLine("Did third action.");
				break;
		}
	}
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Now I can achieve 100% code coverage.&amp;#160; And you'll notice, I no longer need the default case since I've already listed the enum values that I support in the function at the very top of the function.&amp;#160; If I wrote my unit test better to automatically just test every value of that enum without me having to explicitly define a test for each enum value, then I could switch that Check.Require to Check.Invariant and then that check won't even occur during production execution (as long as you don't have the &lt;code&gt;DBC_CHECK_INVARIANT&lt;/code&gt; conditional compilation symbol defined in your Release configuration).&amp;#160; I can do this because I know that the unit tests will catch any enum values I don't support.&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:fa802e4f-2253-40f9-b37e-118d0b2c9ba6" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Unit%20Test" rel="tag"&gt;Unit Test&lt;/a&gt;,&lt;a href="http://technorati.com/tags/.NET" rel="tag"&gt;.NET&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Design%20By%20Contract" rel="tag"&gt;Design By Contract&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-5004174870117452229?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/5004174870117452229/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=5004174870117452229' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/5004174870117452229'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/5004174870117452229'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2008/05/unit-testing-switch-statements.html' title='Unit Testing Switch Statements'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-8087049112625046635</id><published>2008-05-21T10:29:00.001-05:00</published><updated>2008-05-21T10:32:05.319-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Code'/><title type='text'>Ninja Level Code Coverage</title><content type='html'>&lt;p&gt;At my old job, I and another developer embarked on writing a .NET assembly that offered low level functions into the system that our company developed.&amp;#160; One of our goals was to unit test the heck out of the assembly since it was so low level.&amp;#160; That assembly had to be as bug free as possible and when a change was made, we needed a way to try to ensure, without a huge effort on QA's side, that nothing would break.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right: 0px; border-top: 0px; margin: 0px 10px 0px 0px; border-left: 0px; border-bottom: 0px" height="163" alt="iStock_000005249766XSmall" src="http://lh5.ggpht.com/blog.obishawn/SDRAcG4QNyI/AAAAAAAAAhM/ff4yWmlPODM/iStock_000005249766XSmall%5B13%5D.jpg?imgmax=800" width="244" align="left" border="0" /&gt; We therefore needed to make sure that we had as much code coverage as possible.&amp;#160; Code coverage is simply the lines of code actually executed during the unit tests.&amp;#160; Now 100% code coverage, while it means that every single line of code has been executed, does not by any means mean your code is bug-free.&amp;#160; Code coverage does not take into account code you didn't write.&amp;#160; For example if I have a function Add(int a, int b) that returns an integer and my method just does 'return a+b;', I've got a huge bug if a+b &amp;gt; Int.MaxValue.&amp;#160; I could have had 100% code coverage and still missed that bug.&lt;/p&gt;  &lt;p&gt;So while having 100% code coverage does not mean a great deal towards the quality of your unit testing, having 10% code coverage is a horrible level of code coverage.&amp;#160; In the past, we had unit tested some projects and eventually fallen behind on testing certain classes, or didn't employ &lt;a href="http://en.wikipedia.org/wiki/Test-driven_development" target="_blank" rel="nofollow"&gt;test-driven development&lt;/a&gt; (TDD), etc. and we found we had about 20-30% coverage.&amp;#160; If you do not employ TDD, 20-30% is probably the best you're going to do (unless you are an amazing developer and can write completely testable code without even thinking about it).&amp;#160; With this project though, we did employ TDD and we achieved about 80% code coverage.&amp;#160; Most of that remaining 20% was untestable code because it interacted with the database through SQL command objects or with system APIs.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Let me clarify my definition of &amp;quot;untestable&amp;quot;.&amp;#160; When I write unit tests, anything that interacts with another system or the environment is considered untestable.&amp;#160; Unit tests should really be environment independent.&amp;#160; Anything that requires a specific setup on the environment or a specific system could mean that the next developer is not able to run the unit tests on their system.&amp;#160; For example, if code interacts with SQL Server, what happens when the next developer does not have access to that server or the server is down?&amp;#160; Then the tests fail.&amp;#160; If possible, we will substitute one dependency for an equivalent, move versatile dependency.&amp;#160; When testing our &lt;a href="http://www.hibernate.org/" target="_blank" rel="nofollow"&gt;nHibernate&lt;/a&gt; mapping files, we use &lt;a href="http://www.sqlite.org/" target="_blank" rel="nofollow"&gt;SQLite&lt;/a&gt; because nothing needs to be installed and this unit test can run on any environment.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;With a project I am working on right now, web services that our customers use to interact with our system, we need a heavy amount of unit testing as well.&amp;#160; We do not want a change on our side to force our customers to change on their side as well.&amp;#160; This requires them to spend money and until they change their code, there is a potential for their application to either break or cause invalid in our system (depending on the change and how it is implemented).&lt;/p&gt;  &lt;p&gt;So I've been working hard on writing the library assembly for these web services using TDD and employing any techniques I can to streamline development, increase testability, leave the code easy to read and develop, etc.&amp;#160; I am using &lt;a href="http://www.springframework.net/" target="_blank" rel="nofollow"&gt;Spring.NET&lt;/a&gt; to help me do this.&amp;#160; I am using their Dependency Injection (DI) functionality of their Inversion of Control (IoC) container as well as their Aspect-Oriented Programming (AOP) components.&amp;#160; Lastly, I used a &lt;a href="http://en.wikipedia.org/wiki/Design_by_contract" target="_blank" rel="nofollow"&gt;Design-By-Contract&lt;/a&gt; to assist in validating parameter arguments.&lt;/p&gt;  &lt;p&gt;Using the DI, my classes already are stripped of their hard dependencies making them easier to test.&amp;#160; Using the AOP, I've simplified the code in my services classes by removing things such as authentication, logging and exception handling.&amp;#160; Each one of these aspects can be tested independently of the service class.&amp;#160; By not having them mixed in with the actual service execution code, the unit tests for the service code have less paths to test so less unit tests that need to be written.&amp;#160; In addition to this, as I was developing the library assembly, I stayed mindful of what code would be untestable and coded around that pulling those pieces of code out into their own classes.&lt;/p&gt;  &lt;p&gt;The result?&amp;#160; I have about 75% code coverage already (the remaining 25% is a combination of untestable code, code that will eventually be removed as it is no longer needed and method stubs that haven't been developed yet and for now just return generic data for UI testing).&amp;#160; The interesting effect of my development process I noticed is that&amp;#160; every single class had either 0% code coverage or 100% code coverage..&amp;#160; So the 0% tested classes were classes that were not developed yet or were untestable code.&amp;#160; A quick glance at those classes and I noticed that all of the untestable classes were very minimalistic (about 3 - 10 lines of actual code per class).&amp;#160; These classes can easily be checked by two developers to determine if there are any bug potentials in them and most likely will be fully tested in a simple, manual QA test.&lt;/p&gt;  &lt;p&gt;I have to admit, I thought that was really cool.&amp;#160; I used to think just having high code coverage was exciting.&amp;#160; But then seeing that every single class has either 0% or 100% code coverage, that definitely tops the cake (at least until I can achieve 100% code coverage on an entire assembly).&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:6cfc3c09-6f84-4b21-a146-d91d63eda8f0" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Spring.NET" rel="tag"&gt;Spring.NET&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Inversion%20of%20Control" rel="tag"&gt;Inversion of Control&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Dependency%20Injection" rel="tag"&gt;Dependency Injection&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Aspect%20Oriented%20Programming" rel="tag"&gt;Aspect Oriented Programming&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Design%20By%20Contract" rel="tag"&gt;Design By Contract&lt;/a&gt;,&lt;a href="http://technorati.com/tags/.NET" rel="tag"&gt;.NET&lt;/a&gt;,&lt;a href="http://technorati.com/tags/nCover" rel="tag"&gt;nCover&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Unit%20Test" rel="tag"&gt;Unit Test&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Test%20Driven%20Development" rel="tag"&gt;Test Driven Development&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-8087049112625046635?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/8087049112625046635/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=8087049112625046635' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/8087049112625046635'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/8087049112625046635'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2008/05/ninja-level-code-coverage.html' title='Ninja Level Code Coverage'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/blog.obishawn/SDRAcG4QNyI/AAAAAAAAAhM/ff4yWmlPODM/s72-c/iStock_000005249766XSmall%5B13%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-7710774249771068372</id><published>2008-05-20T13:54:00.001-05:00</published><updated>2008-05-20T15:37:35.568-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Code'/><title type='text'>Dependency Injection</title><content type='html'>&lt;p&gt;A while back a &lt;a title="YTechie.com" href="http://www.ytechie.com/" target="_blank"&gt;colleague&lt;/a&gt; of mine sent me a link to a Wikipedia article about a design pattern called &lt;a href="http://en.wikipedia.org/wiki/Inversion_of_Control" target="_blank" rel="nofollow"&gt;Inversion of Control&lt;/a&gt; (IoC).&amp;#160; He also told me about a framework called &lt;a href="http://www.springframework.net/" target="_blank" rel="nofollow"&gt;Spring.NET&lt;/a&gt; that is apparently very popular (as well as other similar frameworks that extend the .NET Framework in an attempt to make building enterprise level applications easier).&amp;#160; In reading up on Spring.NET, I also came across a methodology called &lt;a href="http://www.google.com/url?sa=t&amp;amp;ct=res&amp;amp;cd=1&amp;amp;url=http%3A%2F%2Fen.wikipedia.org%2Fwiki%2FAspect-oriented_programming&amp;amp;ei=bA8zSI7gOKeyiwGu5rXiAQ&amp;amp;usg=AFQjCNF-xkiz6hlVk9vPN6mx16a5DdsOow&amp;amp;sig2=YrmlwtW1hoXiA0ZxApS1Bw" target="_blank" rel="nofollow"&gt;Aspect Oriented Programming&lt;/a&gt; (AOP) and a technique called &lt;a href="http://en.wikipedia.org/wiki/Dependency_injection" target="_blank" rel="nofollow"&gt;Dependency Injection&lt;/a&gt; (DI).&amp;#160; After getting to fully know these design patterns, techniques and methodologies (oh my!), I feel like I've been living under a rock not knowing about them.&lt;/p&gt;  &lt;p&gt;Let's talk about Dependency Injection first.&amp;#160; This is a specific form of IoC.&amp;#160; This technique allows the user application to swap out functional pieces of the application thus changing how the application runs.&amp;#160; Instead of a software component creating or retrieving it's own dependencies, it asks the user layer for it's dependencies.&lt;/p&gt;  &lt;p&gt;Quick example: I have an AccountManager class in a banking program.&amp;#160; The AccountManager class interacts with the persistent data via the BankDb class.&amp;#160; Pretty typical.&amp;#160; The AccountManager class depends on the BankDb class and knows how to instantiate this class on it's own.&amp;#160; However, if we employ DI, we would modify the AccountManager class to take in a IBankDb class on instantiation.&amp;#160; Then when we instantiate the AccountManager class in the interface layer, we can supply the BankDb (which implements IBankDb) and the AccountManager no longer needs to know how to create that instance on it's own because it will be spoon-fed this object.&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="196" alt="iStock_000004289321XSmall" src="http://lh6.ggpht.com/blog.obishawn/SDMxem4QNwI/AAAAAAAAAg8/4ZcODXau6Yw/iStock_000004289321XSmall%5B1%5D.jpg?imgmax=800" width="240" align="right" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;But wait!&amp;#160; We're not done.&amp;#160; Now we employ the help of the Spring.NET framework to do the DI for us.&amp;#160; We can now define in XML configuration files (such as the application configuration file) what class should be passed in to the AccountManager class when we instantiate the AccountManager.&amp;#160; Instead of hard-coding a BankDb object into the constructor, we retrieve the IBankDb object to use from the Spring.NET IoC container.&amp;#160; The Spring.NET IoC container is configured using the XML configuration files.&lt;/p&gt;  &lt;p&gt;Ok, so what exactly do we have?&lt;/p&gt;  &lt;p&gt;We have an AccountManager who doesn't care what object it uses to interact with the persistent data as long as it's an object that implements IBankDb.&amp;#160; And we also have an application that is able to dynamically load which object to pass into the AccountManager via the application configuration file.&lt;/p&gt;  &lt;p&gt;How does this benefit us?&lt;/p&gt;  &lt;p&gt;Well first, you can now fully unit test the AccountManager class (as long as IBankDb is it's only dependency).&amp;#160; You can use a framework such as &lt;a href="http://www.ayende.com/" target="_blank" rel="nofollow"&gt;Rhino Mocks&lt;/a&gt; or &lt;a href="http://www.nmock.org/" target="_blank" rel="nofollow"&gt;NMock&lt;/a&gt; to mock the IBankDb in order to help you fully unit test the AccountManager class.&lt;/p&gt;  &lt;p&gt;Second, what if the person that needs to write the actual BankDb hasn't written it yet and you're not able to write it yourself because you don't have the appropriate access to write that code?&amp;#160; Well, you can write your own mock BankDb class that does enough for you to test your interface and when the actual BankDb class is created, you simply change a configuration file instead of your code.&lt;/p&gt;  &lt;p&gt;Another example of the second benefit is in a web service.&amp;#160; Say you now have a web service that uses the AccountManager class.&amp;#160; You now want to create a development set of web services that allow consumers of the web services to develop their applications without hitting the live data but acts the same in all other aspects.&amp;#160; You can use the same exact AccountManager class, but now supply it a different BankDb class using just a configuration file change.&amp;#160; (By the way, Spring.NET has a way of dynamically generating .NET web services, so you don't even need to actually create another .asmx file - it's all done through the web.config).&lt;/p&gt;  &lt;p&gt;Can't we accomplish the same thing by swapping the BankDb object via code?&lt;/p&gt;  &lt;p&gt;Yes.&amp;#160; Using Spring.NET to do your DI vs. code is really your call.&amp;#160; This call is roughly equivalent to choosing C# over VB.NET, or Pepsi over Coca Cola.&amp;#160; There are arguments for either choice but at the end of the day, they both accomplish the same thing.&amp;#160; The only advice I can offer there is to go with what your comfortable with.&amp;#160; Spring.NET configuration files do have their headaches involved, but being able to change the functionality of the application without recompiling your application is pretty cool and sometimes handy.&lt;/p&gt;  &lt;p&gt;Another example before I let you go.&amp;#160; I recently developed some web services.&amp;#160; I made three projects: The web service project, a .NET library and a Windows application to test the web service.&amp;#160; I relied on Spring.NET to do all of my DI.&amp;#160; The web services consume local services (code run directly from the library - not Windows services) to accomplish their tasks.&amp;#160; The tester application is written such that by commenting out one line and un-commenting another in the application configuration file, I can switch the tester application between using the production web services, using the development web services and using the local services without recompiling the application.&amp;#160; When the Windows app is using the local services, it is using the same exact Spring.NET configuration files that the web services do (thus injecting the dependencies the exact same way the web services would).&amp;#160; So I can test the local services and work out the bugs, then switch over to the web services (confident that the local services will work the same for them as it did for the Windows app) and do a great deal less testing on the web services.&lt;/p&gt;  &lt;p&gt;If you've never looked at IoC, DI or Spring.NET (or equivalent frameworks), I encourage you to do so.&amp;#160; There can be a learning curve involved in figuring out when to and when not to use these, but I'm sure that you'll be able to figure out when those times are.&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:9c157154-fb7e-41ec-9f55-52f48c4246b6" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Inversion%20of%20Control" rel="tag"&gt;Inversion of Control&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Aspect%20Oriented%20Programming" rel="tag"&gt;Aspect Oriented Programming&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Dependency%20Injection" rel="tag"&gt;Dependency Injection&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Spring.NET" rel="tag"&gt;Spring.NET&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Rhino%20Mocks" rel="tag"&gt;Rhino Mocks&lt;/a&gt;,&lt;a href="http://technorati.com/tags/NMock" rel="tag"&gt;NMock&lt;/a&gt;,&lt;a href="http://technorati.com/tags/.NET" rel="tag"&gt;.NET&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-7710774249771068372?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/7710774249771068372/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=7710774249771068372' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/7710774249771068372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/7710774249771068372'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2008/05/dependency-injection.html' title='Dependency Injection'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/blog.obishawn/SDMxem4QNwI/AAAAAAAAAg8/4ZcODXau6Yw/s72-c/iStock_000004289321XSmall%5B1%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-7111411740004874736</id><published>2008-04-15T13:37:00.000-05:00</published><updated>2008-04-15T13:38:18.955-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><title type='text'>URL Rewriting and Postbacks</title><content type='html'>&lt;p&gt;Where I work, we use a heavy amount of URL rewriting for a couple goals.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;SEO (Search Engine Optimization) - We use 301-redirects to correct URLs that are not in a format that we want indexed.&amp;#160; For example, with my domain, http://obishawn.com would cause a 301-redirect to http://www.obishawn.com/ ensuring that the search engines do not index http://obishawn.com separately from http://www.obishawn.com/ (unfortunately, my blog software does not employ these techniques). &lt;/li&gt;    &lt;li&gt;Legacy URLs - Pages from the old version of a site need to be 301-redirected to a new page due to a site reorganization.&amp;#160; From an SEO standpoint, you should never rename a page, but sometimes it's necessary.&amp;#160; So we have a URL rewriter that redirects a certain list of URLs to new URLs. &lt;/li&gt;    &lt;li&gt;Virtual URLs - Dynamic pages that are loaded from a virtual URL.&amp;#160; For example, http://www.mydomain.com/products/a12345/ would actually be hosted by http://www.mydomain.com/product.aspx?sku=a12345. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The framework that we wrote for the URL rewriters works great, are very efficient (well as efficient as processing the URL of every single request can be) and we can turn certain rewriters on or off via the web.config in case we need to do some testing or bug hunting.&amp;#160; The problem lies with the Virtual URLs and specifically when those pages do postbacks to the server.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="176" alt="iStock_000005067784XSmall" src="http://lh5.ggpht.com/blog.obishawn/SAT2GqJuVDI/AAAAAAAAAfY/qK8LAsDEEG0/iStock_000005067784XSmall%5B4%5D.jpg?imgmax=800" width="244" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;The rewriters for SEO and the legacy URLs perform 301-redirects.&amp;#160; This means that a response is sent back to the client when it requests a URL informing the client that URL does not exist and that file has been permanently moved to a new URL and then supplies the client with the new URL.&amp;#160; The client can then request the new URL.&amp;#160; In your browser, this will cause the URL in your address bar to change.&amp;#160; The virtual URLs however are a different story.&amp;#160; This is a server side transfer of the request on to a page other than the one that you would expect based on the URL.&lt;/p&gt;  &lt;p&gt;Take my example from above (http://www.mydomain.com/products/a12345/).&amp;#160; I would expect the page '/products/a12345/default.aspx' (or some other default page based on the type of web application - PHP, ASP, HTML, etc.) to process that request.&amp;#160; Little do I know from a client machine that the directory 'products' doesn't even exist on the server let alone the page '/products/a12345/default.aspx'.&amp;#160; Instead, the server sees that request and realizes that it should be processed by a different URL, namely http://www.mydomain.com/product.aspx?sku=a12345.&amp;#160; Product.aspx can then render the response that should be sent to the user.&amp;#160; All without changing the URL in the client browser's address bar.&amp;#160; The virtual URL looks a little nicer than the product.aspx URL with a query string.&lt;/p&gt;  &lt;p&gt;The issue is that if product.aspx has to postback to the server for whatever reason (maybe you have a pricing table that updates based on an option in a dropdown box).&amp;#160; Because of how the request was transferred to product.aspx, the postback URL is 'product.aspx?sku=a12345'.&amp;#160; So the URL looks really nice and can hide what programming language the server is using, but as soon as you postback, all that niceness and hiding goes out the window as the URL in the address bar changes to the product.aspx?sku=a12345 URL.&amp;#160; The source of this problem is the 'action' attribute on the 'form' element of the rendered page.&amp;#160; This attribute is automatically set to the URL servicing the request and not the URL in the address bar.&amp;#160; So how do you get around this?&lt;/p&gt;  &lt;p&gt;Easy!&amp;#160; With the ActionlessForm!&lt;/p&gt;  &lt;p&gt;The trick is to have a custom form control that does not render the 'action' attribute.&amp;#160; If there's no 'action' attribute, the page just posts back to the URL in the address bar.&amp;#160; Here's the &lt;a href="http://msdn2.microsoft.com/en-us/library/ms972974.aspx" target="_blank"&gt;ActionlessForm solution&lt;/a&gt; from straight from Microsoft.&amp;#160; There are many problems with this solution.&amp;#160; The biggest that I ran into is the 'onsubmit' attribute and the fact that in Microsoft's solution, this attribute does not get rendered, ever.&amp;#160; This attribute holds the JavaScript postback scripts that have to run in order for client-side validation to be done on a form.&amp;#160; That's kind of a big problem.&amp;#160; If you take a look at the source code for the HtmlForm control's RenderAttributes function, there's a lot that this solution is missing.&amp;#160; I've come up with a better solution.&amp;#160; Two classes are needed.&amp;#160; MyHtmlTextWriter which inherits from HtmlTextWriter and the ActionlessForm class which inherits from HtmlForm.&lt;/p&gt;  &lt;p&gt;Simply put, the ActionlessForm creates his own custom HtmlTextWriter from the one passed into it's RenderAttributes function.&amp;#160; The custom HtmlTextWriter then ignores the action attribute as long as it does not begin with default.aspx.&amp;#160; The reason for the default.aspx exclusion is I ran into issues when http://www.mydomain.com/ tried to postback to the server without an action attribute on the form element.&amp;#160; This will have to be modified if you use other default pages such as index.aspx.&lt;/p&gt;  &lt;p&gt;public class ActionlessForm : HtmlForm    &lt;br /&gt;{     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; private class MyHtmlTextWriter : HtmlTextWriter     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; public MyHtmlTextWriter(TextWriter writer)     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : base(writer)     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; } &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; public override void WriteAttribute(string name, string value)    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (name != &amp;quot;action&amp;quot; || value.StartsWith(&amp;quot;default.aspx&amp;quot;))     &lt;br /&gt;&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; base.WriteAttribute(name, value);     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; } &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; public override void WriteAttribute(string name, string value, bool fEncode)    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (name != &amp;quot;action&amp;quot; || value.StartsWith(&amp;quot;default.aspx&amp;quot;))     &lt;br /&gt;&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; base.WriteAttribute(name, value, fEncode);     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; } &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; protected override void RenderAttributes(HtmlTextWriter writer)    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; base.RenderAttributes(new MyHtmlTextWriter(writer));     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }     &lt;br /&gt;}&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:0616e15b-942f-4674-96e1-3d9fe630ca9a" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Microsoft" rel="tag"&gt;Microsoft&lt;/a&gt;,&lt;a href="http://technorati.com/tags/.NET" rel="tag"&gt;.NET&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SEO" rel="tag"&gt;SEO&lt;/a&gt;,&lt;a href="http://technorati.com/tags/ASP.NET" rel="tag"&gt;ASP.NET&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-7111411740004874736?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/7111411740004874736/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=7111411740004874736' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/7111411740004874736'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/7111411740004874736'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2008/04/url-rewriting-and-postbacks.html' title='URL Rewriting and Postbacks'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/blog.obishawn/SAT2GqJuVDI/AAAAAAAAAfY/qK8LAsDEEG0/s72-c/iStock_000005067784XSmall%5B4%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-4882116308160460677</id><published>2007-12-07T11:42:00.000-06:00</published><updated>2008-04-09T14:20:56.084-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Troubleshoot'/><title type='text'>Windows Welcome Screen Override</title><content type='html'>Here's a little known fact about the Windows Welcome Screen: If you need to log in to Windows with an account that is not displayed on the Welcome Screen (e.g. the Administrator account), there is a way to switch out of the Welcome Screen while at the Welcome Screen.&amp;#160; Simply log out of all accounts on the computer and when you're sitting at the Welcome Screen, press Ctrl+Alt+Delete,Delete (hold down Ctrl+Alt and press Delete twice in quick succession).&amp;#160; This should bring up the regular Log On window that allows you to enter a username and password.   &lt;br /&gt;  &lt;br /&gt;I know this works on Windows XP, but I have never tried it on Windows Vista.&amp;#160; Again, all accounts must be logged out for this to work.   &lt;p&gt;&lt;small&gt;Tags: &lt;a href="http://technorati.com/tag/microsoft" rel="tag"&gt;microsoft&lt;/a&gt;, &lt;a href="http://technorati.com/tag/windows" rel="tag"&gt;windows&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-4882116308160460677?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/4882116308160460677/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=4882116308160460677' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/4882116308160460677'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/4882116308160460677'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2007/12/windows-welcome-screen-override.html' title='Windows Welcome Screen Override'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-2889335891314433776</id><published>2007-11-01T12:42:00.000-05:00</published><updated>2008-04-09T14:16:33.213-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><title type='text'>Development Machine Virtualization</title><content type='html'>&lt;p&gt;&lt;strong&gt;Computer:&lt;/strong&gt; Dell D630 (laptop)     &lt;br /&gt;&lt;strong&gt;Processor:&lt;/strong&gt; 2.40GHz Intel(R) Core(TM) 2 Duo - &lt;span style="color: green"&gt;Excellent&lt;/span&gt;     &lt;br /&gt;&lt;strong&gt;Memory:&lt;/strong&gt; 4GB - &lt;span style="color: green"&gt;Excellent&lt;/span&gt;     &lt;br /&gt;&lt;strong&gt;Hard&lt;/strong&gt; &lt;strong&gt;Drive:&lt;/strong&gt; 120GB 7200RPM - &lt;span style="color: green"&gt;Excellent&lt;/span&gt;     &lt;br /&gt;&lt;strong&gt;Media Bay Hard Drive:&lt;/strong&gt; 80GB 7200RPM - &lt;span style="color: green"&gt;Good      &lt;br /&gt;&lt;strong&gt;&lt;span style="color: black"&gt;Screen:&lt;/span&gt;&lt;/strong&gt; &lt;span style="color: black"&gt;14.1WXGA+ (1440x900) - &lt;span style="color: green"&gt;Good&lt;/span&gt;&lt;/span&gt;       &lt;br /&gt;&lt;span style="color: black"&gt;&lt;strong&gt;Operating System:&lt;/strong&gt; Windows XP sp2 (&lt;span style="color: green"&gt;Excellent&lt;/span&gt;) Company Core Load (&lt;/span&gt;&lt;span style="color: rgb(153,153,0)"&gt;Ok&lt;/span&gt;&lt;span style="color: black"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;So the good news is that the laptop is a great laptop.&amp;#160; The screen is a bit smaller than I'm used to with my personal HP Pavilion, but I've become accustom to is with my MacBook Pro with the exception that the MBP is a 15.4 inch screen instead of 14.1.&amp;#160; The downside is that the laptop came with the company's core load.&amp;#160; Now, I understand the purpose of having a core load for leased machines from the support, standardization and security standpoints.&amp;#160; The problem is that no one image is ever perfect for everyone.&amp;#160; Even having machines on the company's domain with your own setup can cause problems when they push down a standard change.&amp;#160; For example, if the company cracks down on ActiveX controls in IE for security, but you develop ActiveX controls for IE, you're going to run into problems.&amp;#160; So from the company's standpoint, core load images are a wonderful thing.&amp;#160; For the user's standpoint, that's not always the case.&amp;#160; Being in software development, it's usually not the case.&lt;/p&gt;  &lt;p&gt;My machines at minimum are usually wiped clean (formatted) and I install Windows from scratch.&amp;#160; This way I know every setting that is set within Windows and I hopefully won't be find out that my software doesn't work because of something being locked down by the domain or core load image.&amp;#160; This helps me develop much faster and reliably.&amp;#160; IT is fairly lenient with us because we have special needs compared to the rest of the company.&amp;#160; However, there are a few things that they still require such as anti-virus, machines staying up-to-date with Windows updates, etc.&amp;#160; Any machine that can not go on the domain is supposed to be on an air gapped network.&amp;#160; So I keep my eyes open for ways to get my work done and yet comply with IT's standards, rules and regulations.&amp;#160; I've worked in IT before and so I've seen it from their side.&lt;/p&gt;  &lt;p&gt;My goal with this new laptop was to run the core load and not wipe it clean.&amp;#160; To do this, I determined that I would have to rely heavily on virtual machines.&amp;#160; Thankfully I knew that the Intel(R) Core(TM) 2 Duo is a screaming processor that it handles virtual machines beautifully and the 4GB of RAM means that I will not have to skimp on the memory for each virtual machine.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Host Environment&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;A couple things to note about my host system.&amp;#160; All I have installed on it is the company's core load which contains the operating system, remote dial-up/VPN software, security software, anti-virus software, Office and the company's instant message client.&amp;#160; In addition to this, I have installed the VMware products such as Workstation, Converter, Server Console and Infrastructure Client.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Partitions      &lt;br /&gt;&lt;/em&gt;The laptop came with the primary hard drive partitioned with the C:\ drive at 20GB.&amp;#160; At first I did not like this as I don't like others determining how my hard drive is partitioned.&amp;#160; But this is actually large enough for the extra software (VMware products) that I had to install, so I'm okay with the size they chose.&amp;#160; The benefit of having it already partitioned like this is that I already have a partition for my virtual machines on the primary hard drive.&amp;#160; Virtual machines really should be stored on their own partition as this allows for better fragmentation on that drive.&amp;#160; VMware files are essentially all extremely tiny files or very large files, so when they become fragmented, they do so in larger chunks (at least in theory).&amp;#160; This also makes it easier to de-fragment the partition if the files are fragmented in larger chunks.&amp;#160; Unfortunately, this partition is not 100% going to be used for virtual machines as the company's core load moves the 'Documents and Settings' folder to this second partition (so as to not lose any data if the C:\ drive needs to be re-imaged) and I also have a few &lt;a href="http://www.portableapps.com"&gt;Portable Apps&lt;/a&gt; on this second partition.&amp;#160; However, this is not a large amount of data and should not cause too many issues in terms of fragmentation.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Anti-Virus&lt;/em&gt;     &lt;br /&gt;A big concern is the fact that this laptop is running anti-virus.&amp;#160; We all know anti-virus is meant to protect us, but as most of us know, this is a major performance killer as the anti-virus software constantly scans files as they are accessed.&amp;#160; So, the anti-virus software must be configured to not scan (real-time scan) the virtual machine directories.&amp;#160; This is not just a slight performance boost, but rather a life-or-death performance boost.&amp;#160; I've seen people struggling to get their virtual machines performing at a usable level only to find out that the anti-virus was what was killing them.&amp;#160; Night and day performance.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Development Virtual Machine&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Description: This virtual machine contains just the minimum tools that I need to do 80% of my work and is configured in a way to be the best performing of my virtual machines.&lt;/p&gt;  &lt;p&gt;Hardware: I decided to give this virtual machine 768MB of memory.&amp;#160; If need be, this virtual machine can be upped to 1GB, but so far it has been running fine with 768MB.&amp;#160; I only need about 20GB for the hard drive in this virtual machine as the source code does not take up much space and I'll be keeping the number of applications on this virtual machine to a minimum.&amp;#160; The key feature of this virtual machine is that this hard drive will be created with all of its space pre-allocated.&amp;#160; Pre-allocating the space for this hard drive means that it VMware will not have to dynamically increase the size of the hard drive as it needs it because the space is already there.&amp;#160; This gives the virtual machine a performance boost.&lt;/p&gt;  &lt;p&gt;Software: Again, I keep this virtual machine as small as possible.&amp;#160; Since the majority of my work will be with .NET 2.0 and 3.0 applications and SQL, I installed just Visual Studio 2005 with just the components that I need, SQL Server 2005 Tools (just the tools), TortoiseSVN and KDiff3 (my diff tool of choice).&amp;#160; I do not need full blown SQL Server on my development image as I have a test system that contains my development database(s).&amp;#160; Keeping the software to a minimum ensures stability and high performance within this virtual machine.&lt;/p&gt;  &lt;p&gt;Notes: I do not take snapshots with this image as I want the performance of this machine to be as high as possible and snapshots branch off the hard drive files defeating the purpose of my pre-allocated hard drive.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Test System Virtual Machine&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Description: This virtual machine is the system that I use to install the development builds on and contains the database(s) that I develop against.&lt;/p&gt;  &lt;p&gt;Hardware: The memory allocated for this system matches what we require for our software and can be adjusted as needed.&amp;#160; The hard drive(s) also are sized as needed and can be adjusted as needed.&amp;#160; I leave VMware dynamically allocate the space for these drives as I am not concerned too much with the performance of this image.&lt;/p&gt;  &lt;p&gt;Software: This is obviously whatever is needed for our software plus our software itself.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Full Development Virtual Machine&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Description: This virtual machine contains everything for the development of any piece of our product including previous versions of the software.&amp;#160; This image is actually a copy of our build box minus the software that I am not licensed for.&amp;#160; Essentially, I could almost run an entire build on this virtual machine.&amp;#160; This is actually the virtual machine that I use to edit our build process as well.&lt;/p&gt;  &lt;p&gt;Hardware:&amp;#160; This virtual machine is a beast and it needs the hardware to match.&amp;#160; I actually allocate 1GB of memory for this virtual machine and it contains 2 hard drives.&amp;#160; One for the operating system and software and one for the data/source code.&amp;#160; The second hard drive is a massive hard drive and can be deleted and recreated without destroying the virtual machine.&amp;#160; It makes for easy cleanup of the virtual machine.&lt;/p&gt;  &lt;p&gt;Software:&amp;#160; This has it all.&amp;#160; Visual Studio 6, 2003 and 2005, SQL Server 2000 and 2005 (full SQL Server), third party controls, etc.&amp;#160; Again, this is a copy of our build virtual machine with certain software uninstalled that I am not licensed for such as InstallShield.&amp;#160; With this virtual machine I can develop on the old Visual Basic 6 controls and applications plus the older versions of my pieces of the software that are still .NET 1.1.&lt;/p&gt;  &lt;p&gt;Notes:&amp;#160; This machine is easy to recover.&amp;#160; All I need to do is take another copy of the build machine and uninstall a couple items.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Benefits&lt;/strong&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Any one of these machines can be recreated without having downtime (assuming the original image is still usable).&amp;#160; Say my development image becomes unstable because I installed the wrong software (be it third party controls that I'm testing, etc.), I can easily start to set up a new image while still using the old one to continue developing until the new one is set up.&amp;#160; To reset up a physical system, your choices are to take down your main system or find a backup computer to continue developing on while your system is being reinstalled. &lt;/li&gt;    &lt;li&gt;If I find that the core load image is locked down in some way, my virtual machine will not be. &lt;/li&gt;    &lt;li&gt;Network isolation/security.&amp;#160; Using VMware Workstation's Host-Only or NAT network settings, I can either isolate my virtual machine from the network or secure it.&amp;#160; This also helps keep the network safe as my virtual machines that are not managed by the domain are secured as well. &lt;/li&gt;    &lt;li&gt;One benefit that I've found is that when I shut down my laptop for the night (which I typically put it in standby), I find it's best to suspend all virtual machines and close Outlook and instant messenger.&amp;#160; Within my virtual machines, I may leave stuff running, I may close everything, but on my host system, everything is shut down for the night.&amp;#160; So, when I get in in the morning, I am starting fresh.&amp;#160; And when I close down for the night, I make sure to check in my changes and find a good spot to leave off.&amp;#160; It is much easier to leave stuff open, not checked in, etc. when it's running on your host desktop machine that you leave up and running overnight.&amp;#160; But when I close stuff down for the night, I find I leave off in better spots.&amp;#160; This leaves me less stressed and better organized for the next day.&amp;#160; Because I'm less stress and am starting fresh each day, I also find I'm more productive. &lt;/li&gt;    &lt;li&gt;Task segregation - I've also found that my individual tasks are segregated by virtual machine so its easier to stay focused on one task at a time. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The setup that I've described above is not meant to be an fix-all, universal solution.&amp;#160; But hopefully you find that this gives you ideas how to improve your development machines or environments.&lt;/p&gt;  &lt;p&gt;&lt;small&gt;Tags: &lt;a href="http://technorati.com/tag/VMware" rel="tag"&gt;VMware&lt;/a&gt;, &lt;a href="http://technorati.com/tag/Visual+Studio" rel="tag"&gt;Visual Studio&lt;/a&gt;, &lt;a href="http://technorati.com/tag/Microsoft" rel="tag"&gt;Microsoft&lt;/a&gt;, &lt;a href="http://technorati.com/tag/Windows" rel="tag"&gt;Windows&lt;/a&gt;, &lt;a href="http://technorati.com/tag/SQL" rel="tag"&gt;SQL&lt;/a&gt;, &lt;a href="http://technorati.com/tag/SQL+Server" rel="tag"&gt;SQL Server&lt;/a&gt;, &lt;a href="http://technorati.com/tag/virtualization" rel="tag"&gt;virtualization&lt;/a&gt;, &lt;a href="http://technorati.com/tag/.NET" rel="tag"&gt;.NET&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-2889335891314433776?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/2889335891314433776/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=2889335891314433776' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/2889335891314433776'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/2889335891314433776'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2007/11/development-machine-virtualization.html' title='Development Machine Virtualization'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-6522864783172960991</id><published>2007-08-23T12:41:00.000-05:00</published><updated>2008-04-09T14:16:33.213-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><title type='text'>Smart Image Resizing</title><content type='html'>&lt;p&gt;I want to see this in the next version of iPhoto or Picasa.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt; &lt;embed src="http://www.youtube.com/v/qadw0BRKeMk" width="425" height="350" type="application/x-shockwave-flash" mce_src="http://www.youtube.com/v/qadw0BRKeMk" wmode="transparent" /&gt;   &lt;p&gt;&lt;a href="http://www.ohgizmo.com/2007/08/21/smart-image-resizing-cuts-the-useless-out-of-your-pics/" mce_href="http://www.ohgizmo.com/2007/08/21/smart-image-resizing-cuts-the-useless-out-of-your-pics/"&gt;Source&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-6522864783172960991?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/6522864783172960991/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=6522864783172960991' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/6522864783172960991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/6522864783172960991'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2007/08/smart-image-resizing.html' title='Smart Image Resizing'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-7138688171084468225</id><published>2007-06-06T12:36:00.000-05:00</published><updated>2008-04-15T13:45:37.246-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Reviews'/><title type='text'>I Want Picasa for the Mac</title><content type='html'>&lt;p&gt;One of my favorite programs is Google's Picasa.&amp;#160; However, as I recently posted, I made the switch to a MacBook Pro as my primary home computer.&amp;#160; I initially tried to use iPhoto to manage my photos as I've heard good things about it.&amp;#160; After using it a bit, I realized that the good things I heard about it must have been from people that never used Picasa.&lt;/p&gt;  &lt;p&gt;Picasa works so smoothly.&amp;#160; You just point it to the directories that you store your photos in and it automatically loads them into the program for you to view, edit and organize.&amp;#160; The program automatically displays all of your photo folders on the left hand side as your &amp;quot;albums&amp;quot;.&amp;#160; On the right side are all your thumbnails of your photos grouped by these albums.&amp;#160; You can scroll up and down through your entire library as thumbnails&amp;#160; You can also change the size of the thumbnails with a slider in the lower right-hand corner and watch the size change real time.&amp;#160; All of this is done ultra-fast.&lt;/p&gt;  &lt;p&gt;Picasa gives a number of really great enhancements for your photos.&amp;#160; These extend beyond your typical redeye-reduction and contrast adjustment.&amp;#160; It offers enhancements such as saturation, which intensifies the color, glow, black-and-white, sepia, blur, focal blur as well as others.&amp;#160; They also have a &amp;quot;I'm Feeling Lucky&amp;quot; button that automatically adjusts the photo to make it look better.&amp;#160; I would say with over half my photos, this really does make them look much cleaner and nicer looking (less washed out, more vibrant, realistic color, etc.)&amp;#160; Below is a photo that I took and, with Picasa, increased the saturation a bit, warmified it and added some glow.&amp;#160; I clicked the Saturation button, slid the slider to the intensity I wanted and hit Apply.&amp;#160; I then clicked the warmify button.&amp;#160; I then clicked the Glow button, slide the sliders to the intensity and radius that I wanted and hit Apply.&amp;#160; It was that easy.&amp;#160; All this while previewing the change live.&lt;/p&gt;  &lt;p&gt;A great feature of this is that it doesn't actually change the picture file itself until you tell it to or export it.&amp;#160; Instead it just remembers what changes you made and displays the changed picture to you within Picasa.&amp;#160; Again, this is all ultra fast.&amp;#160; You don't have to sit and watch it constantly apply these changes every time you access the picture.&amp;#160; It's as if it actually is changed, but opening the picture from Windows Explorer shows that it's not actually changed.&amp;#160; This also means that you can undo any change at any point even after you've closed Picasa, rebooted your computer, whatever.&amp;#160; So you can undo a couple changes, make others, then undo all the changes and make a whole new batch of enhancements.&lt;/p&gt;  &lt;p&gt;The first picture is the original.&amp;#160; The second picture is the Picasa enhanced picture.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/blog.obishawn/SAT3yKJuVII/AAAAAAAAAgY/JxNDNQ4CAyA/original_IMG_2014%5B11%5D%5B18%5D.jpg?imgmax=800"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="247" alt="Original" src="http://lh5.ggpht.com/blog.obishawn/SAT20qJuVFI/AAAAAAAAAgg/xDTojppoC9Q/original_IMG_2014%5B11%5D_thumb%5B16%5D.jpg?imgmax=800" width="328" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/blog.obishawn/SAT21qJuVGI/AAAAAAAAAgk/Fwl3XeYyjKA/enhanced_IMG_0214%5B4%5D%5B11%5D.jpg?imgmax=800"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="247" alt="Picasa Enhanced" src="http://lh6.ggpht.com/blog.obishawn/SAT216JuVHI/AAAAAAAAAgo/nS5rf8l0PMA/enhanced_IMG_0214%5B4%5D_thumb%5B9%5D.jpg?imgmax=800" width="328" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Personally, I think the enhanced picture is ready for the cover of a magazine.&lt;/p&gt;  &lt;p&gt;Picasa also allows you to bulk edit your keywords.&amp;#160; Though this feature could be improved upon some, it is nice that you can do it from the library view.&amp;#160; I would improve it by not having it as a popup window but rather a frame somewhere within the window.&amp;#160; I can never seem to maneuver the window to be in the best spot to bulk edit multiple groups of thumbnails.&amp;#160; You can also search by keywords.&amp;#160; As you type, it already starts filtering right before your eyes.&amp;#160; And again!, it's all very, very fast.&lt;/p&gt;  &lt;p&gt;I have a number of issues with iPhoto.&amp;#160; The first and foremost is that you have to import your photos into its library.&amp;#160; It doesn't just dynamically load the photos from where they are in the file sytem like Picasa does.&amp;#160; This irritates me because I don't like having all of my pictures stored in some database file.&amp;#160; If one file becomes corrupt, I'm ok with it because 1 out of 2000 pictures I can deal with.&amp;#160; One file of one corrupted means I lose everything in one swipe.&amp;#160; Yes I know that's what's backups are for, but that's beside the point.&amp;#160; I would still have to restore my entire library just to recover that one corrupted file whereas to recover one corrupted picture in my file system is just one picture.&amp;#160; Plus, I just don't think there is any good reason that I should have to put my files in a library.&amp;#160; Picasa has no problem loading the pictures from where they exist in the file system.&amp;#160; Yes this means there is a service running that constantly updates the library, but I'm willing to have a service running doing this if it makes my life easier.&lt;/p&gt;  &lt;p&gt;iPhoto is not organized as nice as Picasa.&amp;#160; In iPhoto, I have to specify my libraries and add the photos to it.&amp;#160; Even when I import a folder of pictures organized into folders, iPhoto isn't smart enough to load them into libraries for me.&amp;#160; You can view by the year they were taken.&amp;#160; I don't find that useful whatsoever.&amp;#160; Also, when viewing the library of thumbnails, as you scroll, it renders the thumbnails at low quality and then in the background reloads them in higher quality.&amp;#160; This feature, which is meant to speed things up, actually slows things down a bit when trying to scroll quickly up or down.&amp;#160; Also, when a thumbnail is scrolled off the screen, it is unloaded.&amp;#160; So if you scroll down and back up, it has to reload the thumbnail.&amp;#160; Now, I say slow, but honestly it's not that slow.&amp;#160; Not Windows Explorer slow.&amp;#160; But it definitely can not hold a candle to the speed of Picasa.&lt;/p&gt;  &lt;p&gt;Don't get me wrong.&amp;#160; iPhoto is a great program.&amp;#160; But if you've used Picasa, you may find yourself preferring Picasa as I do.&amp;#160; I debated for a while where to keep my photos, in iPhoto, in my Mac file structure or in my BootCamp partition.&amp;#160; I've decided that I'm willing to wait for my BootCamp Parallels VM to boot just so I can use Picasa.&lt;/p&gt;  &lt;p&gt;With that said, I tried desperately to find out if Google is planning on releasing Picasa for the Mac.&amp;#160; Unfortunately, all I found is that Google is aware that users are asking for Picasa for the Mac and that you can get a Picasa Web uploader for iPhoto.&amp;#160; Google, this is my plead to you, &amp;quot;Please, oh please!&amp;#160; Make a Mac version of Picasa.&amp;quot;&amp;#160; Until then, all I can hope is that the next version of iPhoto in Mac OS X Leopard has greatly improved.&lt;/p&gt;  &lt;p&gt;&lt;small&gt;Tags: &lt;a href="http://technorati.com/tag/Google" rel="tag"&gt;Google&lt;/a&gt;, &lt;a href="http://technorati.com/tag/Picasa" rel="tag"&gt;Picasa&lt;/a&gt;, &lt;a href="http://technorati.com/tag/iPhoto" rel="tag"&gt;iPhoto&lt;/a&gt;, &lt;a href="http://technorati.com/tag/Apple" rel="tag"&gt;Apple&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-7138688171084468225?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/7138688171084468225/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=7138688171084468225' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/7138688171084468225'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/7138688171084468225'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2007/06/i-want-picasa-for-mac.html' title='I Want Picasa for the Mac'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/blog.obishawn/SAT20qJuVFI/AAAAAAAAAgg/xDTojppoC9Q/s72-c/original_IMG_2014%5B11%5D_thumb%5B16%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-7310261197627780318</id><published>2007-04-26T12:34:00.000-05:00</published><updated>2008-04-09T14:20:56.085-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Troubleshoot'/><title type='text'>Visual Studio .NET Intellisense</title><content type='html'>&lt;p&gt;So today I needed to go work on a .NET project in Visual Studio 2003 and found that my intellisense was not working.&amp;#160; I tried typing even the simplest 'string.Format' and when I hit '.' no help popped up.&amp;#160; Figuring that it was ReSharper, I uninstalled it.&amp;#160; However, that did not solve the problem.&amp;#160; So I repaired VS 2003.&amp;#160; Nope.&amp;#160; So I continued to uninstall, repair, run CCleaner, etc.&amp;#160; Nothing seemed to fix it.&amp;#160; Then it occurred to me that it might be something in my profile.&amp;#160; Sure enough, I logged in as a different user and that user had intellisense.&lt;/p&gt;  &lt;p&gt;I proceeded to clean out my %UserProfile%\Application Data, %UserProfile%\Local Settings\Application Data and %UserProfile%\Local Settings\Temp directories for anything related to VS but that still didn't fix it.&amp;#160; Finally I came to terms with the fact that it was in the registry.&amp;#160; I deleted the HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\7.1 key (which unfortunately holds &lt;em&gt;all&lt;/em&gt; of my VS 2003 settings) and went back in.&amp;#160; Sure enough it was fixed.&lt;/p&gt;  &lt;p&gt;I'm not sure what specific key or value shut off the intellisense though.&amp;#160; One of these days I may try to narrow it down.&lt;/p&gt;  &lt;p&gt;&lt;small&gt;Tags: &lt;a href="http://technorati.com/tag/Microsoft" rel="tag"&gt;Microsoft&lt;/a&gt;, &lt;a href="http://technorati.com/tag/.NET" rel="tag"&gt;.NET&lt;/a&gt;, &lt;a href="http://technorati.com/tag/Visual+Studio" rel="tag"&gt;Visual Studio&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-7310261197627780318?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/7310261197627780318/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=7310261197627780318' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/7310261197627780318'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/7310261197627780318'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2007/04/visual-studio-net-intellisense.html' title='Visual Studio .NET Intellisense'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-7721334735182493063</id><published>2007-04-25T12:33:00.000-05:00</published><updated>2008-04-09T14:19:46.281-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Reviews'/><title type='text'>Rank Trending</title><content type='html'>&lt;p&gt;Did you ever wonder how each post you make to your blog affects your Google Rank?&amp;#160; Maybe you want to keep an eye on your Google search rank for a specific phrase because you want to make sure your site stays known for that topic.&amp;#160; Or maybe you have some other statistics from say a service like &lt;a href="http://awstats.sourceforge.net/" target="_blank"&gt;awstats&lt;/a&gt; that you want to overlay with your Google Adsense to see just how they relate.&lt;/p&gt;  &lt;p&gt;Then &lt;a href="http://www.RankTrend.com/" target="_blank"&gt;RankTrend&lt;/a&gt; is for you.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Datasources      &lt;br /&gt;&lt;/strong&gt;RankTrend tracks a number of datasources for you such as search engine rank (what position your website shows up in a search result list), Google PageRank, how many people link to you in &lt;a href="http://Del.icio.us" target="_blank"&gt;Del.icio.us&lt;/a&gt;, how many &lt;a href="http://www.Digg.com/" target="_blank"&gt;Diggs&lt;/a&gt; a post of yours gets and many more including a generic datasource so that you can upload your own custom data.&amp;#160; Here's the beauty: RankTrend keeps track of these over time so you can see how each change from day to day, week to week, etc.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Events      &lt;br /&gt;&lt;/strong&gt;RankTrend also allows you to enter events that you can overlay on top of your data.&amp;#160; For example, when you pay for an ad for your website in a magazine, you can add an event so that you can see at what point in the data that you got that ad.&amp;#160; It helps you visualize what kind of change that ad brought for your website.&amp;#160; Here's the cool part: you can give RankTrend RSS feeds too so that it automatically adds in an event for each new item in the RSS feed.&amp;#160; So if you have a blog, give RankTrend your RSS feed and watch how each post affects each of your datasources.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Charts      &lt;br /&gt;&lt;/strong&gt;So you have all this data, now what?&amp;#160; The heart of RankTrend isn't in the collecting of this data, it's in helping you visualize it and compare it.&amp;#160; RankTrend offers a charting system that allows you to plot your various datasources together and overlay whatever events you'd like.&amp;#160; The charts are powerful and the RankTrend team is working on even more trending options that will take it to the next level.&amp;#160; Below is an example of a chart that I made in which I imported some of my daily awstats into a generic datasource and charted it.&amp;#160; Now I know awstats gives you a basic chart to visualize this data, but RankTrend offers this kind of charting on &lt;em&gt;any&lt;/em&gt; of their datasources.&amp;#160; Plus you can't plot your events over top of your stats on the awstats site.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.obishawn.com/images/obishawnblog/WindowsLiveWriter/RankTrending_125EA/awstats_daily_chart%5B12%5D.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="150" alt="" src="http://www.obishawn.com/images/obishawnblog/WindowsLiveWriter/RankTrending_125EA/awstats_daily_chart_thumb%5B10%5D.jpg" width="472" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Reports&lt;/strong&gt;     &lt;br /&gt;RankTrend also offers the ability to build your own reports that can be emailed to you daily, weekly or monthly.&amp;#160; So say I built 7 charts and wanted those and a site summary emailed to me weekly so I can keep an eye on things, I can do that.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;RankTrend is in Beta      &lt;br /&gt;&lt;/strong&gt;As I mentioned before, RankTrend is in beta.&amp;#160; You'll need a special code for now in order to sign up.&amp;#160; This code is posted on certain forums, so if you can find it, you can take part in the beta testing.&amp;#160; Hopefully it will be out of beta soon.&amp;#160; The RankTrend team is committed to offering more and better ways to track and trend the data about your website that is important to you.&lt;/p&gt;  &lt;p&gt;I highly recommend you check it out and subscribe to their RSS feed to be notified when RankTrend comes out of beta.&lt;/p&gt;  &lt;p&gt;&lt;small&gt;Tags: &lt;a href="http://technorati.com/tag/RankTrend.com" rel="tag"&gt;RankTrend.com&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-7721334735182493063?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/7721334735182493063/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=7721334735182493063' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/7721334735182493063'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/7721334735182493063'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2007/04/rank-trending.html' title='Rank Trending'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-6402351447957489106</id><published>2007-01-12T11:27:00.000-06:00</published><updated>2008-04-09T14:20:56.085-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Troubleshoot'/><title type='text'>Office 2007 and OneNote 2007 Installation Crash</title><content type='html'>&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Office 2007 and OneNote 2007 crash right away when starting the install reporting: 'Error: ORegistryKey.GetSubKeyNames failure: Cannot get all sub key names for registry &amp;quot;HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall&amp;quot; HResult: 0x80070103.'&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; My work machine has been about 6 months overdue for a reinstall of Windows, so today I finally decided to do just that.&amp;#160; I decided this would be a good time to transition to Office 2007 and OneNote 2007.&amp;#160; I used a XP CD that had SP2 and all the latest updates slipstreamed into it as well as Internet Explorer 7, Windows Media Player 11, the latest DirectX 9 and the Windows Genuine Advantage add-in.&amp;#160; So after the OS was installed, all I had to do was update some drivers and start installing all of my software.&lt;/p&gt;  &lt;p&gt;I tried to install OneNote first and as soon as it started to install, it crashed.&amp;#160; I tried a couple times with no luck (shutting down various applications such as AV between tries).&amp;#160; So I moved on to Office.&amp;#160; Same thing happened.&amp;#160; Looking at the contents of what was going to be sent to Microsoft about the error, I discovered the problem: 'Error: ORegistryKey.GetSubKeyNames failure: Cannot get all sub key names for registry &amp;quot;HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall&amp;quot; HResult: 0x80070103.'&amp;#160; I checked, and sure enough, the key existed.&amp;#160; So that didn't help.&lt;/p&gt;  &lt;p&gt;I decided to make sure everyone had access to that key and the sub-keys.&amp;#160; After doing this, I was able to install OneNote.&amp;#160; So I figured I was good and Office would install.&amp;#160; Nope.&amp;#160; Same problem as before.&amp;#160; So I got drastic.&amp;#160; I exported that key, deleted all of its contents (well, I deleted that key and its contents and then recreated the key rather than deleting 50+ keys 1-by-1).&amp;#160; Hooray!&amp;#160; Office installed!&amp;#160; (I then blew the key that I backed up back into the registry.)&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="color: #ff0000"&gt;&lt;strong&gt;Warning!&amp;#160; Do not attempt this fix unless you have a clear understanding of registry and the risks of manually editing its contents.&amp;#160; You run the risk of corrupting your system by performing these steps!&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Reset permissions on that key and all of its children. &lt;/li&gt;    &lt;li&gt;If that doesn't work...      &lt;ol&gt;       &lt;li&gt;Export that key. &lt;/li&gt;        &lt;li&gt;Delete the contents of that key. &lt;/li&gt;        &lt;li&gt;Install Office, merge the exported key. &lt;/li&gt;     &lt;/ol&gt;   &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Update 2-14-2007&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Turns out this may be due to SVS.&amp;#160; If you are using SVS, deactivate all layers before installing Office or OneNote before trying the above solution(s).    &lt;br /&gt;&lt;a href="http://kb.altiris.com/article.asp?article=32661&amp;amp;p=3" target="_blank"&gt;Source&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;small&gt;Tags: &lt;a href="http://technorati.com/tag/Microsoft" rel="tag"&gt;Microsoft&lt;/a&gt;, &lt;a href="http://technorati.com/tag/Office" rel="tag"&gt;Office&lt;/a&gt;, &lt;a href="http://technorati.com/tag/OneNote" rel="tag"&gt;OneNote&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-6402351447957489106?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/6402351447957489106/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=6402351447957489106' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/6402351447957489106'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/6402351447957489106'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2007/01/office-2007-and-onenote-2007.html' title='Office 2007 and OneNote 2007 Installation Crash'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-8279222405741402618</id><published>2006-09-07T12:27:00.000-05:00</published><updated>2008-04-09T14:19:46.281-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Reviews'/><title type='text'>Windows Live Writer Part II</title><content type='html'>&lt;p&gt;I was looking around Windows Live Writer a little more.&amp;#160; This program has quickly become my preferred way of posting messages.&lt;/p&gt;  &lt;p&gt;In my previous &lt;a href="http://www.obishawn.com/archive/2006/08/22/Windows-Live-Writer.aspx"&gt;Windows Live Writer post&lt;/a&gt;, I mentioned that I had installed Tag4Writer in order to tag a post and that it doesn't work for Community Server.&amp;#160; It turns out Windows Live Writer actually has the tag support built in, it just appears to be unable to add new tags.&amp;#160; In the upper right-hand corner of the program is a drop down list that lists the categories.&amp;#160; Categories in CS 2.x have basically become tags and so the tags that I entered in CS show up there.&amp;#160; Simply checking these check boxes tags the post.&lt;/p&gt;  &lt;p&gt;Also in that post, I had mentioned that WLW removes my tags.&amp;#160; Those category choices would explain why.&amp;#160; If I repost a message after having entered tags on the web, then it re-posts the message with no categories.&amp;#160; Selecting the tags in this list would have kept the tags when the message was re-posted.&lt;/p&gt;  &lt;p&gt;&lt;small&gt;Tags: &lt;a href="http://technorati.com/tag/Windows+Live+Writer" rel="tag"&gt;Windows Live Writer&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-8279222405741402618?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/8279222405741402618/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=8279222405741402618' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/8279222405741402618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/8279222405741402618'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2006/09/windows-live-writer-part-ii.html' title='Windows Live Writer Part II'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-141843733453306814</id><published>2006-08-23T12:26:00.000-05:00</published><updated>2008-04-09T14:20:56.086-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Troubleshoot'/><title type='text'>InstallShield Exit Code -1073741819</title><content type='html'>&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; InstallShield IsCmdBuild.exe exit code -1073741819&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; A while back we ran into a problem with our build box at work.&amp;#160; One of our installers suddenly stopped building, giving back the error code -1073741819.&amp;#160; I immediately opened InstallShield's GUI and built the installer and it built with no problems.&amp;#160; I tried again to build it with the Visual Build step (calling the ISCmdBuild.exe - InstallShield's command line tool to build the installer) and it failed again.&amp;#160; So I made the Visual Build step output the command line it was calling.&amp;#160; I then copied that and ran that exact command in a command prompt.&amp;#160; It built successfully.&amp;#160; This led me to believe that it was a problem with Visual Build.&amp;#160; Posting a &lt;a href="http://www.kinook.com/Forum/showthread.php?threadid=1791" target="_blank"&gt;message&lt;/a&gt; on their forums proved useless as they said there was a workaround that had you just handle the error event, look for that Id and change the status of that step to good if it encountered that error.&amp;#160; The problem is that the installer did not build, so the step truly did fail.&amp;#160; So I went back to the idea that it was an InstallShield problem and so tried posting a &lt;a href="http://community.installshield.com/showthread.php?t=159732" target="_blank"&gt;message&lt;/a&gt; on InstallShield's forums and got no response whatsoever.&lt;/p&gt;  &lt;p&gt;During my investigation, I did determine that the only time that IsCmdBuild.exe would fail on this step was if the Visual Build project was launched by a Windows Scheduled Task.&lt;/p&gt;  &lt;p&gt;The first time we got this message, I had to restore an old version of the build box and work with that.&amp;#160; The second time I didn't have the luxury of doing that.&amp;#160; So I dug and dug into the InstallShield files and tested a couple theories.&amp;#160; I finally came across a solution that worked.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Uninstalled the InstallScript Objects. &lt;/li&gt;    &lt;li&gt;Deleted the .msm files in C:\Program Files\Common Files\Merge Modules. &lt;/li&gt;    &lt;li&gt;Deleted C:\Program Files\IS11.5\Objects\MDAC28.msm. &lt;/li&gt;    &lt;li&gt;Ran the IS11.5 install and ran a &amp;quot;Repair&amp;quot;. &lt;/li&gt;    &lt;li&gt;Reinstalled the InstallScript Objects. &lt;/li&gt;    &lt;li&gt;Downloaded MDAC 2.8 Merge Module from the Objects section in an InstallShield InstallScript project. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;I kicked off a new build and everything worked.&amp;#160; We haven't seen that problem resurface since.&lt;/p&gt;  &lt;p&gt;&lt;small&gt;Tags: &lt;a href="http://technorati.com/tag/InstallShield" rel="tag"&gt;InstallShield&lt;/a&gt;, &lt;a href="http://technorati.com/tag/VisualBuild" rel="tag"&gt;VisualBuild&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-141843733453306814?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/141843733453306814/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=141843733453306814' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/141843733453306814'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/141843733453306814'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2006/08/installshield-exit-code-1073741819.html' title='InstallShield Exit Code -1073741819'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-4501176561029070628</id><published>2006-08-22T12:24:00.000-05:00</published><updated>2008-04-09T14:19:46.282-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Reviews'/><title type='text'>Windows Live Writer</title><content type='html'>&lt;p&gt;I just came across the &lt;a href="http://windowslivewriter.spaces.live.com/" target="_blank"&gt;Windows Live Writer&lt;/a&gt; browsing &lt;a href="http://channel9.mdsn.com" target="_blank"&gt;Channel9&lt;/a&gt; and had to try it out.&amp;#160; I fired up &lt;a href="http://juice.altiris.com/node/86" target="_blank"&gt;SVS,&lt;/a&gt; created a new layer, installed Windows Live Writer, updated the layer to include the &lt;a href="http://www.codeplex.com/Wiki/View.aspx?ProjectName=tag4writer" target="_blank"&gt;Tag4Writer&lt;/a&gt; and here I am creating a new post on my blog using Windows Live Writer.&amp;#160; It seems pretty nice.&amp;#160; Nothing too bulky, simple, straight forward.&amp;#160; It even satisfied a co-worker of mine.&amp;#160; He was a user of &lt;a href="http://www.blogjet.com/" target="_blank"&gt;Blogjet&lt;/a&gt; but he said he wanted one that supported tags, allowed you to set the title of the page (Blogjet does not do this but Windows Live Writer uses the name of the post as the title of the page) and writes good HTML.&lt;/p&gt;  &lt;p&gt;A couple nice features: allows you to insert pictures and maps with the click of a button, gives you the ability to save drafts and has very simple style editing (if I'm going to write a fancy looking post, I'm going to write the HTML myself, not use a post creator).&amp;#160; It defaults to a Web Layout style, so as you type, your post already looks like what it will on your blog.&amp;#160; Then you can switch to the Web Preview and view the post as if you actually posted it (displays in the context of your actual blog).&lt;/p&gt;  &lt;p&gt;Windows Live Writer supports a number of different blogs from Windows Live Spaces to Community Server to Wordpress to Blogger.&amp;#160; Check it out.&amp;#160; You'll probably like it.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Tag4Writer does not actually fully support tagging in Community Server.&amp;#160; It simply puts in links in the post to specific tags.&amp;#160; As far as I am aware, CS does not parse these tag links in a post.&amp;#160; I actually had to manually put the tags in myself and then I had duplicate links on the post for each tag.&amp;#160; So I decided to not use Tag4Writer for now.&amp;#160; CS 2.1 added the ability to add tags via AJAX right when viewing a post (if you're logged in).&amp;#160; That's good enough for me for now.&amp;#160; Hopefully WLW adds tagging support or Tag4Writer adds that functionality to their software.&lt;/p&gt;  &lt;p&gt;Another thing I realized with WLW is that it allows you to update a post.&amp;#160; Tremendous!&amp;#160; However, I think it may be clearing the tags on my post when I post an update.&amp;#160; Hopefully it was just something I did.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Yep, the tags were removed.&lt;/p&gt;  &lt;p&gt;&lt;small&gt;Tags: &lt;a href="http://technorati.com/tag/Windows+Live+Writer" rel="tag"&gt;Windows Live Writer&lt;/a&gt;, &lt;a href="http://technorati.com/tag/Channel9" rel="tag"&gt;Channel9&lt;/a&gt;, &lt;a href="http://technorati.com/tag/SVS" rel="tag"&gt;SVS&lt;/a&gt;, &lt;a href="http://technorati.com/tag/Blogjet" rel="tag"&gt;Blogjet&lt;/a&gt;, &lt;a href="http://technorati.com/tag/Tag4Writer" rel="tag"&gt;Tag4Writer&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-4501176561029070628?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/4501176561029070628/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=4501176561029070628' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/4501176561029070628'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/4501176561029070628'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2006/08/windows-live-writer.html' title='Windows Live Writer'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-7680604356730576994</id><published>2006-05-01T12:24:00.000-05:00</published><updated>2008-04-09T14:19:46.282-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Reviews'/><title type='text'>Imaging Software</title><content type='html'>&lt;p class="MsoNormal"&gt;So I just realized that my last post was over a month ago.&amp;#160; April was a busy month for me.&amp;#160; Anyway, we just purchased a license for a new piece of imaging software at work that is fairly slick.    &lt;br /&gt;    &lt;br /&gt;Up until now we have been using Symantec Ghost and it has been working fairly well.&amp;#160; When I started working for the company that I am at right now, one of the first things I did was transitioned their imaging system from PowerQuest Drive Image to Symantec Ghost.&amp;#160; I had created some boot CDs that were specifically designed for our test machines and would boot in about 15 seconds.&amp;#160; These disks would establish a network connection, map a drive and then execute some batch files on that share in order to finish the boot.&amp;#160; About 75% of the boot process could be controlled by the files on the network share so modifying the boot process didn't always require me to re-burn the CDs.&amp;#160; This system has been adequate up until recently when we got a machine that is going to be used for the system test.     &lt;br /&gt;    &lt;br /&gt;This new machine contains 2GB of memory.&amp;#160; The RAMDisk that I was using for the boot CDs only supports up to 1GB of memory.&amp;#160; So I switched to using Bart's Boot Disk.&amp;#160; It takes a lot longer to boot but at least it supports 2GB.     &lt;br /&gt;    &lt;br /&gt;Then we decided to upgrade one of our performance servers from 1GB to 3GB of memory and we got a second performance server with 8GB.&amp;#160; Suffice to say, I think Ghost is now out of the question.&amp;#160; So we started looking into new software.&amp;#160; We came across &lt;a href="http://www.acronis.com/enterprise/products/choose-trueimage/"&gt;Acronis True Image&lt;/a&gt;.&amp;#160; This software is pretty nice.&amp;#160; You can even image the computer while running Windows.&amp;#160; Also they have a tool that can allow you to install an image taken on one set of hardware and deploy the image on another set of hardware.&amp;#160; VMware already implements this type of ability in their P2V software which I've used before and love.     &lt;br /&gt;    &lt;br /&gt;So I wanted to test the software out myself and see how it works.&amp;#160; I downloaded the evaluation version, installed it on my computer and started it taking an image within about 5-10 minutes.&amp;#160; 15 minutes later, I had taken an image of my C: drive which contained about 40GB of data.&amp;#160; The image, with their default compression was about 20GB in size.&amp;#160; I then deployed the image to a new virtual machine.&amp;#160; This took about 2 hours.&amp;#160; This is longer than I would have expected, but I'm sure there's some kind of setting that you could mess with to make this deploy faster.&amp;#160; I then used P2V to strip out the hardware specific drivers.&amp;#160; Then I fired up the virtual machine and had a copy of my physical box running as a virtual machine.&amp;#160; I didn't try Acronis's Universalization software because I already had P2V setup and I figured I'd just use that.&amp;#160; All this was done and I never had to interrupt my work because I was able to do it all without shutting down Windows (other than the reboot to finish installing the Acronis True Image software).&lt;/p&gt;  &lt;p&gt;&lt;small&gt;Tags: &lt;a href="http://technorati.com/tag/Symantec" rel="tag"&gt;Symantec&lt;/a&gt;, &lt;a href="http://technorati.com/tag/Ghost" rel="tag"&gt;Ghost&lt;/a&gt;, &lt;a href="http://technorati.com/tag/PowerQuest" rel="tag"&gt;PowerQuest&lt;/a&gt;, &lt;a href="http://technorati.com/tag/Drive+Image" rel="tag"&gt;Drive Image&lt;/a&gt;, &lt;a href="http://technorati.com/tag/VMware" rel="tag"&gt;VMware&lt;/a&gt;, &lt;a href="http://technorati.com/tag/Acronis" rel="tag"&gt;Acronis&lt;/a&gt;, &lt;a href="http://technorati.com/tag/True+Image" rel="tag"&gt;True Image&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-7680604356730576994?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/7680604356730576994/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=7680604356730576994' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/7680604356730576994'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/7680604356730576994'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2006/05/imaging-software.html' title='Imaging Software'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-8524711007419827554</id><published>2006-03-27T11:23:00.000-06:00</published><updated>2008-04-09T14:16:33.216-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><title type='text'>Build Machine Virtualization</title><content type='html'>So hopfully by now you've heard the term 'virtualization'.&amp;#160; There is a definate trend toward running production servers at virtual machines to fully utilize the capabilities of new servers, to help achieve 0 downtime, to reduce the amount of hardware needed, etc.&amp;#160; There's also a trend towards quality testing being performed more and more on virtual machines rather than physical machines where possible to reduce the number of physical test machines required which thus reduces price, to more easily facilitate reproducing problems, saving snapshot of problem environments, to help facilitate automated testing, etc.   &lt;br /&gt;  &lt;br /&gt;So why not go virtual with build environments?   &lt;br /&gt;  &lt;br /&gt;Where I work they have the concept of freezing build boxes with every release.&amp;#160; So at the end of a release, that build box is frozen and a new box is purchased for the next version.&amp;#160; This was a new concept to me.&amp;#160; However due to some events that unfolded when we did not freeze a build box and decided to build that version's two service packs on the same box.&amp;#160; Bad things unfolded.&amp;#160; Suffice to say, I now am all for the freezing of build boxes.&amp;#160; The problem is that process gets expensive and time consuming (setting up and maintaining those boxes and providing disaster recovery for all of them).   &lt;br /&gt;  &lt;br /&gt;So when we got close to the end of our last version, I proposed to our project manager that we go virtual with our build environment.&amp;#160; I recommended buying a beefy server capable of storing multple environments and running a number of them too.&amp;#160; So we got a dual Xeon, 4 GB Dell server with a good amount of storage and a license of &lt;a href="http://www.vmware.com"&gt;VMware&lt;/a&gt; GSX Server (only to find out shortly after purchasing the license that VMware is offering its Server software free in Q2 '06 - oh well, we still need a support contract).&amp;#160; Here are the benefits that running a build machine in a virtual environment:   &lt;br /&gt;  &lt;ul&gt;   &lt;li&gt;Multiple machines utilizing the same hardware - the hardware for a good VMware server may be expensive but if you freeze build boxes with each version or have multiple products, the cost can easily be made up. &lt;/li&gt;    &lt;li&gt;The build environment can be run on any VMware Server or Workstation (of compatible version).&amp;#160; This means that you don't need high-end hardware to run a virtual build environment.&amp;#160; Even a simple workstation computer would do.      &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;The build environment can easily be copied - for testing reasons, build machine redundancy, etc.&amp;#160; Obviously you'll need to worry about software licensing on the build machine if you copy it. &lt;/li&gt;    &lt;li&gt;Since the build machine can be run on any VMware Server or Workstation, if the physical machine dies, you can easily transfer it to another machine and be back up and running more quickely. &lt;/li&gt;    &lt;li&gt;Since you can just copy build machines, you can easily set up base build machine images or copy the build machine as a starting point for the next version. &lt;/li&gt;    &lt;li&gt;Here's my favorite: Easily archive the build machine at the end of a version.&amp;#160; Simply burn the image to DVDs (it is highly recommended that you have the virtualization software to span the hard disk files at 2GB - VMware definately has this functionality).&amp;#160; Then if you have a disaster were you lose the build machine somehow, just retrieve the DVDs, find a VMware Server or Workstation (or download VM Player) and you'll be back up in a short time.&amp;#160; No need to wrry about compaitble hardward.&amp;#160; The problem with images (such as Ghost images) is that you have to install on the same hardware or you're going to have major issues. &lt;/li&gt; &lt;/ul&gt; I highly recommend running a virtual build environment if you can.   &lt;p&gt;&lt;small&gt;Tags: &lt;a href="http://technorati.com/tag/VMware" rel="tag"&gt;VMware&lt;/a&gt;, &lt;a href="http://technorati.com/tag/virtualization" rel="tag"&gt;virtualization&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-8524711007419827554?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/8524711007419827554/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=8524711007419827554' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/8524711007419827554'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/8524711007419827554'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2006/03/build-machine-virtualization.html' title='Build Machine Virtualization'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-5714541118751741004</id><published>2006-03-19T11:22:00.000-06:00</published><updated>2008-04-09T14:16:33.216-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><title type='text'>Build Reproducibility</title><content type='html'>When designing a build process, you should design a way that the build process can be re-run for a particular build.&lt;span&gt;&amp;#160; &lt;/span&gt;The easiest way to do this is to divide each step into one of three categories:   &lt;br /&gt;  &lt;ol&gt;   &lt;li&gt;Master &lt;/li&gt;    &lt;li&gt;Build &lt;/li&gt;    &lt;li&gt;Test &lt;/li&gt; &lt;/ol&gt;  &lt;p class="MsoNormal"&gt;&lt;b&gt;Build category&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Any step that is required to build the software, documentation and installers are those that fall under this category.&lt;span&gt;&amp;#160; &lt;/span&gt;These steps are heart of the build process.&lt;span&gt;&amp;#160; &lt;/span&gt;The build steps should be unaware of source control, versioning, build output distribution, etc and should assume that everything it needs is on the box it is running on.&lt;span&gt;&amp;#160; &lt;/span&gt;These build steps should ideally also contain only relative paths making them location independent.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;If you had all of the build steps contained within its own build file or able to be executed by themselves, then someone who had all the build software installed on their computer should be able to fetch the source code himself, execute the build and have the same output that he would if he ran the same thing on the build computer.&lt;span&gt;&amp;#160; &lt;/span&gt;Also, in the event of a catastrophe where you lose a build, you simple restore the source code for that particular build number and run this file again, then when it is done running, you should have the same output as you did when that build was originally run.     &lt;br /&gt;&lt;o:p&gt;&amp;#160;&lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;b&gt;Test category&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Any step that tests the build belongs in this category.&lt;span&gt;&amp;#160; &lt;/span&gt;These steps should, like the those steps in the build category, be unaware of source control, versioning, build output distribution, etc and should assume that everything it needs is on the box it is running on.&lt;span&gt;&amp;#160; &lt;/span&gt;These build steps should also ideally contain only relative paths making them location independent.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;b&gt;     &lt;br /&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;b&gt;Master category&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;The steps contain in this category are those that fill in the gaps between the build and test category.&lt;span&gt;&amp;#160; &lt;/span&gt;These steps include maintaining and incrementing the version number, pre-build modification of the source code (for example updating resource files with the most recent translations), tagging or labeling the source code, fetching the source code (preferably from the tag or label), executing the build and test steps and distributing the output of the build (such as making the installers publicly available or at least available for QA).&amp;#160; The master build file should also be the one who actually updates any build status application such as a build status web page.&amp;#160; It is often beneficial to have notices on the individual steps of the building of the applications, so you may have to develope your build category steps to take in a flag as to whether it should output its status to an external source but should default to not update that external source.&amp;#160; This way, only when the Master build steps execute the Build steps will they actually notify others of its status.     &lt;br /&gt;&lt;/p&gt;  &lt;br /&gt;&lt;i&gt;&lt;b&gt;Example:&lt;/b&gt;&lt;/i&gt;   &lt;br /&gt;Here's a quick example of how this works.&amp;#160; Say I have a .NET project that I build 1 solution, generate 1 help file and make 1 installer.&amp;#160; This project has a database that the build process automatically generates the install scripts for.&amp;#160; This application also works for multiple languages so I have a database in which I keep all the translations for my software which the build process reads and updates all of the resource files in the project.&amp;#160; Below is how I would define the build process.   &lt;br /&gt;  &lt;br /&gt;&lt;b&gt;Master Build File&lt;/b&gt;   &lt;br /&gt;  &lt;ul&gt;   &lt;li&gt;Increment the build number &lt;/li&gt;    &lt;li&gt;Read the latest translation data from the database and update the resource files. &lt;/li&gt;    &lt;li&gt;Commit changes to build number and resource files to the database.&amp;#160; &lt;i&gt;Note: at this point, since I have truely consumed another build number, I can consider the build to actually have started.&lt;/i&gt; &lt;/li&gt;    &lt;li&gt;Tag/label the source code with the new build number. &lt;/li&gt;    &lt;li&gt;Fetch the source code from the tag/label. &lt;/li&gt;    &lt;li&gt;Execute the Build file      &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;Save the installers and binaries from the build to a public share for others to pick up &lt;/li&gt;    &lt;li&gt;Execute the Tests file &lt;/li&gt;    &lt;li&gt;Distribute the results of the tests. &lt;/li&gt; &lt;/ul&gt; &lt;b&gt;Build File&lt;/b&gt;   &lt;br /&gt;  &lt;ul&gt;   &lt;li&gt;Generate Database install scripts      &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;If executed by the Master build file, update status &lt;/li&gt;    &lt;li&gt;Build the .NET solution &lt;/li&gt;    &lt;li&gt;If executed by the Master build file, update status &lt;/li&gt;    &lt;li&gt;Build documentation &lt;/li&gt;    &lt;li&gt;If executed by the Master build file, update status &lt;/li&gt;    &lt;li&gt;Build installer &lt;/li&gt;    &lt;li&gt;If executed by the Master build file, update status &lt;/li&gt; &lt;/ul&gt; &lt;b&gt;Tests File    &lt;br /&gt;&lt;/b&gt;  &lt;ul&gt;   &lt;li&gt;Test Database install scripts      &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;If executed by the Master build file, update status &lt;/li&gt;    &lt;li&gt;Build and run unit tests on .NET solution &lt;/li&gt;    &lt;li&gt;If executed by the Master build file, update status &lt;/li&gt; &lt;/ul&gt; &lt;b&gt;Reproducibility&lt;/b&gt;   &lt;br /&gt;Now imagine that catastrophe strikes and our build machine dies.&amp;#160; Luckily we have instructions for setting up a new build environment to be the same as the old one.&amp;#160; The instructions contain all of the software and their versions along with the keys needed for them.&amp;#160; So within a day we have a new build environment up and running.&amp;#160; Now I need to recreate version 1.0 of our software so I create a revision for it.&amp;#160; I fetch the source from the tag that we made for v1.0.&amp;#160; If I've defined the build process properly, I can simply run the Build File and have output that is nearly the same exact output that we had for v1.0.&amp;#160; Hopefully the only difference will be dates of files.     &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-5714541118751741004?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/5714541118751741004/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=5714541118751741004' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/5714541118751741004'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/5714541118751741004'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2006/03/build-reproducibility.html' title='Build Reproducibility'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-6978424148721309105</id><published>2006-02-27T11:21:00.000-06:00</published><updated>2008-04-09T14:17:18.204-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Code'/><title type='text'>SQL Union Statements Implicitly Perform Distinct Selects</title><content type='html'>Ok, so I'm not sure if the title is worded correctly, but I needed something so here's what I'm getting at:   &lt;br /&gt;  &lt;br /&gt;I was working on a SQL stored procedure at work today and adding some more joins and columns to a Select statement that was part of a Union with another Select statement.&amp;#160; Everything was going good until I added a Text column to the columns to return.&amp;#160; At this point I started getting an error stating that Text columns can not be used with Distinct.&amp;#160; The odd thing was that the Distinct keyword didn't exists in the Select statement (or anywhere in that stored procedure for that fact).&amp;#160; I thought about it for a little bit, after messing around with the statment for a while, and realized something.&amp;#160; A Union will not insert duplicate rows into the resultant data, it basically does a Distinct Select.&amp;#160; Since I knew this particular Union statement would never return duplicate data, I modified it from being a standard 'Union' to a 'Union All'.&amp;#160; I was then able to add the Text column with no problem.   &lt;p&gt;&lt;small&gt;Tags: &lt;a href="http://technorati.com/tag/Microsoft" rel="tag"&gt;Microsoft&lt;/a&gt;, &lt;a href="http://technorati.com/tag/SQL+Server" rel="tag"&gt;SQL Server&lt;/a&gt;, &lt;a href="http://technorati.com/tag/SQL" rel="tag"&gt;SQL&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-6978424148721309105?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/6978424148721309105/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=6978424148721309105' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/6978424148721309105'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/6978424148721309105'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2006/02/sql-union-statements-implicitly-perform.html' title='SQL Union Statements Implicitly Perform Distinct Selects'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-2692289629226132238</id><published>2006-02-24T11:19:00.000-06:00</published><updated>2008-04-09T14:17:18.204-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Code'/><title type='text'>DataGridView Column Header Style</title><content type='html'>I was building a .NET 2.0 Windows application which contained a DataGridView object.&amp;#160; I was attempting to modify the column header styles to fit better in the application but none of the settings I was applying seemed to be taking effect.&amp;#160; So finally I posted a message on &lt;a href="http://channel9.msdn.com"&gt;Channel9&lt;/a&gt; and got a response with &lt;a href="http://channel9.msdn.com/ShowPost.aspx?PostID=137639#137639"&gt;the answer&lt;/a&gt; to my question.   &lt;br /&gt;  &lt;br /&gt;In order to use styles in your DataGridView control for your .NET 2.0 Windows application, you must specify dgvMyDataGridView.EnableHeadersVisualStyles = false.   &lt;br /&gt;  &lt;br /&gt;Example of the code:   &lt;br /&gt;&lt;code&gt;//Instantiate new DataGridViewCellStyle    &lt;br /&gt;System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 =     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; new System.Windows.Forms.DataGridViewCellStyle();     &lt;br /&gt;    &lt;br /&gt;//Define Header Style     &lt;br /&gt;dataGridViewCellStyle2.Alignment =     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; System.Windows.Forms.DataGridViewContentAlignment.BottomCenter;     &lt;br /&gt;dataGridViewCellStyle2.BackColor = System.Drawing.Color.Navy;     &lt;br /&gt;dataGridViewCellStyle2.Font = new System.Drawing.Font(&amp;quot;Microsoft Sans Serif&amp;quot;,     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));     &lt;br /&gt;dataGridViewCellStyle2.ForeColor = System.Drawing.Color.White;     &lt;br /&gt;dataGridViewCellStyle2.SelectionBackColor =     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; System.Drawing.SystemColors.Highlight;     &lt;br /&gt;dataGridViewCellStyle2.SelectionForeColor = System.Drawing.Color.Navy;     &lt;br /&gt;dataGridViewCellStyle2.WrapMode =     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; System.Windows.Forms.DataGridViewTriState.True;     &lt;br /&gt;    &lt;br /&gt;//Apply Header Style     &lt;br /&gt;this.dgvTransactions.ColumnHeadersDefaultCellStyle =     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; dataGridViewCellStyle2;     &lt;br /&gt;    &lt;br /&gt;//Disable Headers Visual Styles - apparently there is an &amp;quot;automatic&amp;quot;     &lt;br /&gt;// visual style that needs to be disabled     &lt;br /&gt;this.dgvTransactions.EnableHeadersVisualStyles = false;&lt;/code&gt;   &lt;p&gt;&lt;small&gt;Tags: &lt;a href="http://technorati.com/tag/Microsoft" rel="tag"&gt;Microsoft&lt;/a&gt;, &lt;a href="http://technorati.com/tag/.NET" rel="tag"&gt;.NET&lt;/a&gt;, &lt;a href="http://technorati.com/tag/Visual+Studio" rel="tag"&gt;Visual Studio&lt;/a&gt;, &lt;a href="http://technorati.com/tag/Channel9" rel="tag"&gt;Channel9&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-2692289629226132238?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/2692289629226132238/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=2692289629226132238' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/2692289629226132238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/2692289629226132238'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2006/02/datagridview-column-header-style.html' title='DataGridView Column Header Style'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-667519048881938478.post-8748639802174400950</id><published>2006-02-19T11:20:00.000-06:00</published><updated>2008-04-09T14:17:18.205-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Code'/><title type='text'>Conditional Compilation Symbols for ASP.NET 2.0 Projects</title><content type='html'>Conditional compilation symbols are those constants that you can define in order to include or exclude certain code in compilation of your solution.&amp;#160; The most common constant is DEBUG.&amp;#160; With DEBUG defined in your build configuration, you can define code that only gets compiled into the final binaries if compiled in the Debug build configuration.&amp;#160; Below is an example of using the DEBUG constant to include code only when in Debug configuration.   &lt;br /&gt;  &lt;br /&gt;&lt;font color="#0000ff"&gt;#if&lt;/font&gt; DEBUG   &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Response.Write(&lt;font color="#a52a2a"&gt;&amp;quot;The value of 'a' is &amp;quot;&lt;/font&gt; + a);   &lt;br /&gt;&lt;font color="#0000ff"&gt;#endif&lt;/font&gt;   &lt;br /&gt;  &lt;br /&gt;Since ASP.NET 2.0 projects do not have project files, there is no place in the Microsoft Visual Studio 2005 IDE to define the conditional compilation symbols like there is in DLL and Windows Executable projects.   &lt;br /&gt;  &lt;br /&gt;It turns out that you can define these constants in your web.config.&amp;#160; The downside to this is that they are not bound to a specific build configuration and so you will either have to manually add/edit these constants in your web.config or add something to your build process to handle these constants.&amp;#160; Just add the xml below to your configuration of your web.config to define the DEBUG constant and a custom SANDBOX constant.&amp;#160; (I like defining SANDBOX in order to hit against a developement/test database rather than the real/production database.)   &lt;br /&gt;&lt;font color="#0000ff"&gt;   &lt;br /&gt;&amp;lt;&lt;font color="#a52a2a"&gt;system.codedom&lt;/font&gt;&amp;gt;     &lt;br /&gt;&amp;#160; &amp;lt;&lt;font color="#a52a2a"&gt;compilers&lt;/font&gt;&amp;gt;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#a52a2a"&gt;compiler &lt;/font&gt;&lt;font color="#ff0000"&gt;language&lt;/font&gt;=&amp;quot;c#;cs;csharp&amp;quot; extension=&amp;quot;.cs&amp;quot;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#ff0000"&gt;type&lt;/font&gt;=&amp;quot;Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0,     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Culture=neutral, PublicKeyToken=b77a5c561934e089&amp;quot;     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#ff0000"&gt;compilerOptions&lt;/font&gt;=&amp;quot;/d:DEBUG,SANDBOX&amp;quot;/&amp;gt;     &lt;br /&gt;&amp;#160; &amp;lt;&lt;font color="#a52a2a"&gt;/compilers&lt;/font&gt;&amp;gt;     &lt;br /&gt;&amp;lt;&lt;font color="#a52a2a"&gt;/system.codedom&lt;/font&gt;&amp;gt;&lt;/font&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/667519048881938478-8748639802174400950?l=obishawn.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://obishawn.blogspot.com/feeds/8748639802174400950/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=667519048881938478&amp;postID=8748639802174400950' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/8748639802174400950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/667519048881938478/posts/default/8748639802174400950'/><link rel='alternate' type='text/html' href='http://obishawn.blogspot.com/2006/02/conditional-compilation-symbols-for.html' title='Conditional Compilation Symbols for ASP.NET 2.0 Projects'/><author><name>Shawn</name><uri>http://www.blogger.com/profile/10348702008778742387</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>
