<?xml version="1.0"?><?xml-stylesheet type="text/xsl" href="http://www.codeplex.com/rss.xsl"?><rss version="2.0"><channel><title>dropthings Wiki &amp; Documentation Rss Feed</title><link>http://www.codeplex.com/dropthings/Wiki/View.aspx?title=Home</link><description>dropthings Wiki Rss Description</description><item><title>Updated Wiki: Home</title><link>http://dropthings.codeplex.com/Wiki/View.aspx?title=Home&amp;version=30</link><description>&lt;div class="wikidoc"&gt;&lt;b&gt;Project Description&lt;/b&gt;&lt;br /&gt;Ajax Web Portal built on Linq, Workflow Foundation and ASP.NET AJAX. Code is in Visual Studio 2008 using .NET 3.0 and .NET 3.5.&lt;br /&gt;
&lt;h1&gt;Production site&lt;/h1&gt;&lt;a href="http://dropthings.omaralzabir.com" class="externalLink"&gt;http://dropthings.omaralzabir.com&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;For latest news and updates, visit my blog &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/omar/" class="externalLink"&gt;http://msmvps.com/blogs/omar/&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;
&lt;h1&gt;Source Code&lt;/h1&gt;Latest source code and releases:&lt;br /&gt;&lt;a href="http://code.google.com/p/dropthings/" class="externalLink"&gt;http://code.google.com/p/dropthings/&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://dropthings.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=16144" class="externalLink"&gt;Click here for the code that matches with the book&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Book about this project&lt;/b&gt;&lt;br /&gt;&lt;img src="http://i3.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=dropthings&amp;DownloadId=27511" alt="MyBook.jpg" title="MyBook.jpg" /&gt;&lt;br /&gt;This book explains how this project has been built step by step. It also explains many advance AJAX concepts, development and production challenges for building and maintaining a high volume production website.&lt;br /&gt;&lt;br /&gt;Get it from Amazon:&lt;br /&gt;&lt;a href="http://www.amazon.com/Building-Web-2-0-Portal-ASP-NET/dp/0596510500" class="externalLink"&gt;http://www.amazon.com/Building-Web-2-0-Portal-ASP-NET/dp/0596510500&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Technologies&lt;/b&gt;
&lt;ul&gt;&lt;li&gt;ASP.NET 2.0&lt;/li&gt;
&lt;li&gt;jQuery&lt;/li&gt;
&lt;li&gt;ASP.NET AJAX (.NET 3.5)&lt;/li&gt;
&lt;li&gt;Silverlight&lt;/li&gt;
&lt;li&gt;Linq to Sql&lt;/li&gt;
&lt;li&gt;Linq to Xml&lt;/li&gt;
&lt;li&gt;Workflow Foundation (.NET 3.0)&lt;/li&gt;
&lt;li&gt;Visual Studio 2008 and SQL Server 2005&lt;/li&gt;&lt;/ul&gt;
&lt;br /&gt;&lt;b&gt;Features&lt;/b&gt;
&lt;ul&gt;&lt;li&gt;Configure widgets for specific user roles.&lt;/li&gt;
&lt;li&gt;Configure different default page setup for different roles - Managers get some widgets, Employees get different widgets and so on.&lt;/li&gt;
&lt;li&gt;Ability to define page setup for anonymous users and different page setup for logged in users.&lt;/li&gt;
&lt;li&gt;Multiple Tabs.&lt;/li&gt;
&lt;li&gt;Customizable Widget Gallery.&lt;/li&gt;
&lt;li&gt;Different column setup.&lt;/li&gt;
&lt;li&gt;Build your own widgets using Silverlight, ASP.NET or plain Javascripts.&lt;/li&gt;
&lt;li&gt;Host widgets on any page of your website&lt;/li&gt;
&lt;li&gt;Easy to integrate Dropthings to your own website e.g. http://myoffice.bt.com is built on top of Dropthings.&lt;/li&gt;
&lt;li&gt;Business Layer is entirely Workflow Foundation driven - easy to plug-in your own business logic as Activities.&lt;/li&gt;&lt;/ul&gt;
&lt;br /&gt;&lt;b&gt;Join Us&lt;/b&gt;&lt;br /&gt;If you are a seasoned ASP.NET Developer and have ASP.NET AJAX skill, come and join us to make Dropthings a feature rich Ajax Web Portal. Please email me at &amp;quot;OmarALZabir&amp;quot; at gmail dot com.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;What is an AJAX Portal&lt;/b&gt;&lt;br /&gt;A &lt;i&gt;Portal&lt;/i&gt; refers to a page that allows users to customize their own homepage by dragging and dropping &lt;i&gt;widgets&lt;/i&gt; onto the page. This approach gives users complete control over what content they see on their page, where they want to see it, and how they want to interact with it. &lt;br /&gt;&lt;br /&gt;A widget is a discrete piece on a Web page that performs a particular function and comes with its own UI and set of features. Examples of widgets include a to-do-list, an address book, a contact list, an RSS feed, or even a clock, calendar, playlist, stock ticker, weather report, traffic report, dictionary, game, or almost anything you can imagine that can be packaged up and dropped on a Web page. In a corporate environment, widgets can connect to internal systems, such as an Expense Tracker widget that interacts directly with the internal Accounting System. If you are familiar with Sharepoint Portal, then you already know about Widgets. They are called Web parts in Sharepoint’s term and also in ASP.NET 2.0. &lt;br /&gt;&lt;br /&gt;Portals are powerful RSS aggregation platform. You can put as many RSS widgets as you like on your page and get fresh content delivered to you as soon as it is published. Some Portal like Pageflakes archives RSS for a long time and thus you can go back in time and read older posts, save posts, and forward interesting articles to your friends.&lt;br /&gt;&lt;br /&gt;An Ajax-powered portal is specifically a portal that uses Ajax technologies to create richer experiences for its users. It is one step ahead of previous generation portals like My Yahoo or MSN.com, because it gives you state-of-the-art UI that behaves more like a Windows client application -- with widgets, animations, popups, client side data grids, and other effects not usually found on a non-Ajax Web portal . &lt;br /&gt;&lt;br /&gt;&lt;b&gt;How to run the project&lt;/b&gt;
&lt;ol&gt;&lt;li&gt;Download the latest source code from Google Code site &lt;a href="http://code.google.com/p/dropthings/" class="externalLink"&gt;http://code.google.com/p/dropthings/&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Follow the Readme.txt&lt;/li&gt;&lt;/ol&gt;
&lt;br /&gt;&lt;b&gt;How is ASP.NET AJAX used in this project?&lt;/b&gt;&lt;br /&gt;It is an N-tier application, with a user interface (UI) layer, a business layer, and a data access layer. I have used ASP.NET AJAX to implement the UI layer of the portal application which includes the homepage and the widgets’ UI. ASP.NET AJAX provides the framework for loading widgets onto the home page, updating widgets without doing any postbacks (via UpdatePanel), and changing page layout by dragging and dropping widgets on the page. It also provides a rich collection of Control Extenders, that add cool effects like fade in/fade out, smooth transitions, and client side animations . You can add to the rich clientside experience by providing auto-completion behavior on text boxes, asynchronous data loading via webservice  calls, and client side paging, sorting and many more.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;How is .NET 3.5 used in this project&lt;/b&gt;&lt;br /&gt;The business layer of the application is built with the Workflow Foundation  in .NET 3.0 . Major operations like a first-time user visit, a subsequent user visit, adding a new widget, and creating a new page are all orchestrated using workflow . The workflows contain all the business rules and activities needed to complete each operation. For example, the &amp;quot;New User Visit&amp;quot; workflow creates the user account, populates the user profile with default values, creates some default pages, populates them with specific widgets, etc. Such compound operations are very easy to build with Workflows , which enables you to break the complete workflow operation into smaller chunks named Activities. Each Activity does a very small amount of work. It talks to the data access layer and performs the task. The data access layer is built with .NET 3.5 , utilizing LINQ to SQL .&lt;br /&gt;The web project and the widgets make good use of .NET 3.5 by utilizing lambda expressions , LINQ  to SQL, and LINQ to XML. You will use Linq queries to work with collections and database rows. Widgets make good use of Linq to Xml in order to consume XML from external data sources.&lt;br /&gt;&lt;br /&gt;Warning: Dropthings.com is a very simple, open-source example of what can be done with AJAX and Microsoft technologies.  It is intended for educational purposes only.  Dropthings.com has absolutely nothing to do with &lt;a href="http://www.pageflakes.com" class="externalLink"&gt;http://www.pageflakes.com&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;.  But this project does a good job to show you how all the new hot technologies work together in a working web application that's production ready.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;
&lt;h1&gt;My Blog&lt;/h1&gt;---&lt;br /&gt;&lt;div class="rss"&gt;&lt;div class="accentbar"&gt;&lt;span class="left"&gt;&amp;nbsp;&lt;/span&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5 News Feed&lt;span class="right"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/Lvjac5Wi3Bc/7-tips-for-for-loading-javascript-rich-web-2-0-like-sites-significantly-faster.aspx"&gt;7 tips for for loading Javascript rich Web 2.0-like sites significantly faster&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Friday, September 25, 2009&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;Introduction  &lt;br /&gt;When you create rich Ajax application, you use external JavaScript frameworks and you have your own homemade code that drives your application. The problem with well known JavaScript framework is, they offer rich set of features which are not always necessary in its entirety. You may end up using only 30% of jQuery but you still download the full jQuery framework. So, you are downloading 70% unnecessary scripts. Similarly, you might have written your own javascripts which are not always used. There might be features which are not used when the site loads for the first time, resulting in unnecessary download during initial load. Initial loading time is crucial – it can make or break your website. We did some analysis and found that every 500ms we added to initial loading, we lost approx 30% traffic who never wait for the whole page to load and just close browser or go away. So, saving initial loading time, even by couple of hundred milliseconds, is crucial for survival of a startup, especially if it’s a Rich AJAX website.  &lt;br /&gt;You must have noticed Microsoft’s new tool Doloto which helps solve the following problem:     &lt;br /&gt;Modern Web 2.0 applications, such as GMail, Live Maps, Facebook and many others, use a combination of Dynamic HTML, JavaScript and other Web browser technologies commonly referred as AJAX to push page generation and content manipulation to the client web browser. This improves the responsiveness of these network-bound applications, but the shift of application execution from a back-end server to the client also often dramatically increases the amount of code that must first be downloaded to the browser. This creates an unfortunate Catch-22: to create responsive distributed Web 2.0 applications developers move code to the client, but for an application to be responsive, the code must first be transferred there, which takes time.   &lt;br /&gt;Microsoft Research looked at this problem and published this research paper in 2008, where they showed how much improvement can be achieved on initial loading if there was a way to split the javascripts frameworks into two parts – one primary part which is absolutely essential for initial rendering of the page and one auxiliary part which is not essential for initial load and can be downloaded later or on-demand when user does some action. They looked at my earlier startup Pageflakes and reported:     &lt;br /&gt;2.2.2 Dynamic Loading: Pageflakes      &lt;br /&gt;A contrast to Bunny Hunt is the Pageflakes application, an       &lt;br /&gt;industrial-strength mashup page providing portal-like functionality.       &lt;br /&gt;While the download size for Pageflakes is over 1 MB, its initial       &lt;br /&gt;execution time appears to be quite fast. Examining network activity       &lt;br /&gt;reveals that Pageflakes downloads only a small stub of code       &lt;br /&gt;with the initial page, and loads the rest of its code dynamically in       &lt;br /&gt;the background. As illustrated by Pageflakes, developers today can       &lt;br /&gt;use dynamic code loading to improve their web...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=Lvjac5Wi3Bc:B37Y1w4CWCE:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?i=Lvjac5Wi3Bc:B37Y1w4CWCE:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=Lvjac5Wi3Bc:B37Y1w4CWCE:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=Lvjac5Wi3Bc:B37Y1w4CWCE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?i=Lvjac5Wi3Bc:B37Y1w4CWCE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=Lvjac5Wi3Bc:B37Y1w4CWCE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=Lvjac5Wi3Bc:B37Y1w4CWCE:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=Lvjac5Wi3Bc:B37Y1w4CWCE:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=Lvjac5Wi3Bc:B37Y1w4CWCE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?i=Lvjac5Wi3Bc:B37Y1w4CWCE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=Lvjac5Wi3Bc:B37Y1w4CWCE:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OmarAlZabirBlog/~4/Lvjac5Wi3Bc" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/G6IuWGFpYeM/windows-7-64bit-works.aspx"&gt;Windows 7 64bit works!&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Saturday, September 19, 2009&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;Windows 7 64bit finally works! This is the first 64bit OS I could really use in my daily acitvities. I tried Vista 64bit, it was unreliable. It would show blue screen right when I am about to make a presentation to the CEO. Until Microsoft released SP1, Vista 64 bit was not usable at all. Then came Windows 7 beta. I immediately tried the 64bit version of Windows 7 beta. It was even worse than Vista. It would crash every now and then – waking up from standby, trying to do livemeeting share, switching screens, plugging in external USB drives and what not. So, I patiently waited for the final version to come out before I get on installing it on all my laptops. Happy to say, the final version works perfectly on HP tx2000 Tablet PC, DELL Vostro 1500, DELL Inspiron 1520. Once you do a full windows update and install some drivers here and there, it all works perfectly. And let me say, Windows 7 is beautiful. I found back the joy of working on computers again!  &lt;br /&gt;Working on 64bit Operating System is challenging. You don’t always find the right printer driver. Your cool external USB speakers won’t work – even if it is made by Microsoft. And above all, there’s that C:\Windows\Winsxs folder which keeps increasing forever. By the time I was done with Vista 64bit (two years approx in business), my Winsxs folder was staggering 26 GB eating up every bit out of my C: partition. I had no choice but to format and start over. It seems like this folder keeps copy of every single DLL version it ever sees. The more windows update I do, the larger it gets. Now on a fresh new Windows 7 installation, after installing VS 2008, Office Applications, Windows Live applications and some handy tools, the Winsxs folder is 5.62 GB. Let’s see how it keeps growing over the year. A useful information for 64bit wannabes, make sure your C partition is at least 60 GB. I just installed Windows 7 64bit 3 days back and it has already taken 31 GB space.   &lt;br /&gt;   &lt;br /&gt;Since I am doing a totally useless post, let me sprinkle some productivity tips on it before you lose interest reading my blog.  &lt;br /&gt;I realized I do a lot of context swiching. I get over 200 mails per day, so I pretty much switch focus from Visual Studio/Browser to Outlook once every minute, which is big cencentration killer. So, I tried the above setup on my 25” screen and it works great!  &lt;br /&gt;The left half of the screen is visual studio and the right half screen shows Outlook and my todolist. As you see, I can see the emails coming up on Outlook without ever switching. The Visual Studio screen width is the right size to read code without horizontally scrolling. The right bottom half of the screen shows my toodlist so that I am always doing the right task from my todolist and not wondering around heedless. If I browse, I bring up the browser on top of the Visual Studio and keep the right half same so that while browsing I am not missing important mails and I still have an eye on my next actions.   &lt;br /&gt;I have been using Toodledo for a year. I...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=G6IuWGFpYeM:DDIFNn4xrQY:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?i=G6IuWGFpYeM:DDIFNn4xrQY:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=G6IuWGFpYeM:DDIFNn4xrQY:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=G6IuWGFpYeM:DDIFNn4xrQY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?i=G6IuWGFpYeM:DDIFNn4xrQY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=G6IuWGFpYeM:DDIFNn4xrQY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=G6IuWGFpYeM:DDIFNn4xrQY:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=G6IuWGFpYeM:DDIFNn4xrQY:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=G6IuWGFpYeM:DDIFNn4xrQY:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?i=G6IuWGFpYeM:DDIFNn4xrQY:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=G6IuWGFpYeM:DDIFNn4xrQY:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OmarAlZabirBlog/~4/G6IuWGFpYeM" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/6a2sxD7Mac8/aspectf-fluent-way-to-put-aspects-into-your-code-for-separation-of-concern.aspx"&gt;AspectF fluent way to put Aspects into your code for separation of concern&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Saturday, September 19, 2009&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;Aspects are common features that you write every now and then in different parts of your project. it can be some specific way of handling exceptions in your code, or logging method calls, or timing execution of methods, or retrying some methods and so on. If you are not doing it using any Aspect Oriented Programming framework, then you are repeating a lot of similar code throughout the project, which is making your code hard to maintain. For ex, say you have a business layer where methods need to be logged, errors need to be handled in a certain way, execution needs to be timed, database operations need to be retried and so on. So, you write code like this:   public bool InsertCustomer(string firstName, string lastName, int age, &lt;br /&gt;    Dictionary&amp;lt;string, string&amp;gt; attributes)&lt;br /&gt;{&lt;br /&gt;    if (string.IsNullOrEmpty(firstName)) &lt;br /&gt;        throw new ApplicationException(&amp;quot;first name cannot be empty&amp;quot;);&lt;br /&gt;&lt;br /&gt;    if (string.IsNullOrEmpty(lastName))&lt;br /&gt;        throw new ApplicationException(&amp;quot;last name cannot be empty&amp;quot;);&lt;br /&gt;&lt;br /&gt;    if (age &amp;lt; 0)&lt;br /&gt;        throw new ApplicationException(&amp;quot;Age must be non-zero&amp;quot;);&lt;br /&gt;&lt;br /&gt;    if (null == attributes)&lt;br /&gt;        throw new ApplicationException(&amp;quot;Attributes must not be null&amp;quot;);&lt;br /&gt;&lt;br /&gt;    // Log customer inserts and time the execution&lt;br /&gt;    Logger.Writer.WriteLine(&amp;quot;Inserting customer data...&amp;quot;);&lt;br /&gt;    DateTime start = DateTime.Now;&lt;br /&gt;&lt;br /&gt;    try&lt;br /&gt;    {&lt;br /&gt;        CustomerData data = new CustomerData();&lt;br /&gt;        bool result = data.Insert(firstName, lastName, age, attributes);&lt;br /&gt;        if (result == true)&lt;br /&gt;        {&lt;br /&gt;            Logger.Writer.Write(&amp;quot;Successfully inserted customer data in &amp;quot; &lt;br /&gt;                + (DateTime.Now-start).TotalSeconds + &amp;quot; seconds&amp;quot;);&lt;br /&gt;        }&lt;br /&gt;        return result;&lt;br /&gt;    }&lt;br /&gt;    catch (Exception x)&lt;br /&gt;    {&lt;br /&gt;        // Try once more, may be it was a network blip or some temporary downtime&lt;br /&gt;        try&lt;br /&gt;        {&lt;br /&gt;            CustomerData data = new CustomerData();&lt;br /&gt;            if (result == true)&lt;br /&gt;            {&lt;br /&gt;                Logger.Writer.Write(&amp;quot;Successfully inserted customer data in &amp;quot; &lt;br /&gt;                    + (DateTime.Now-start).TotalSeconds + &amp;quot; seconds&amp;quot;);&lt;br /&gt;            }&lt;br /&gt;            return result;&lt;br /&gt;        }&lt;br /&gt;        catch &lt;br /&gt;        {&lt;br /&gt;            // Failed on retry, safe to assume permanent failure.&lt;br /&gt;&lt;br /&gt;            // Log the exceptions produced&lt;br /&gt;            Exception current = x;&lt;br /&gt;            int indent = 0;&lt;br /&gt;            while (current != null)&lt;br /&gt;            {&lt;br /&gt;                string message = new string(Enumerable.Repeat(&amp;#39;\t&amp;#39;, indent).ToArray())&lt;br /&gt;                    + current.Message;&lt;br /&gt;                Debug.WriteLine(message);&lt;br /&gt;                Logger.Writer.WriteLine(message);&lt;br /&gt;                current = current.InnerException;&lt;br /&gt;                indent++;&lt;br /&gt;            }&lt;br /&gt;            Debug.WriteLine(x.StackTrace);&lt;br /&gt;            Logger.Writer.WriteLine(x.StackTrace);&lt;br /&gt;&lt;br /&gt;            return false;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here&amp;#160; you see the two lines of real code, which inserts the...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=6a2sxD7Mac8:9cCw6dLUdHU:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?i=6a2sxD7Mac8:9cCw6dLUdHU:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=6a2sxD7Mac8:9cCw6dLUdHU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=6a2sxD7Mac8:9cCw6dLUdHU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?i=6a2sxD7Mac8:9cCw6dLUdHU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=6a2sxD7Mac8:9cCw6dLUdHU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=6a2sxD7Mac8:9cCw6dLUdHU:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=6a2sxD7Mac8:9cCw6dLUdHU:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=6a2sxD7Mac8:9cCw6dLUdHU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?i=6a2sxD7Mac8:9cCw6dLUdHU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?a=6a2sxD7Mac8:9cCw6dLUdHU:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OmarAlZabirBlog/~4/6a2sxD7Mac8" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/omaralzabirblog/~3/zrsF0EqMDJs/msdn-day-dhaka.aspx"&gt;MSDN Day @ Dhaka&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Wednesday, June 17, 2009&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;Venue.     &lt;br /&gt;IDB Auditorium     &lt;br /&gt;E/8-A Rokeya Sharani,     &lt;br /&gt;Sher-e-Bangla Nagar,     &lt;br /&gt;Agargaon, Dhaka 1207  &lt;br /&gt;Saturday June 20th 9:00 AM to 6:00 PM  &lt;br /&gt;Microsoft Community in Bangladesh proudly presents Microsoft Day @ Dhaka. This is a special day dedicated to all Microsoft technology professionals and students in Bangladesh. We will be having the best Microsoft community technologists from Bangladesh - Microsoft Most Valuable Professionals (MVPs) delivering sessions at the event. This technology marathon is a great opportunity to learn from the best and network with each other.    &lt;br /&gt;Both Microsoft developers and networking professionals would find the event worth attending.     &lt;br /&gt;The event will also feature a demo bonanza with Windows 7 and an extensive Question and Answer panel with the Bangladesh MVPs to answer your queries.   &lt;br /&gt;http://msdnbangladesh.net/content/msday.aspx  &lt;br /&gt;Please register soon! Limited sits. I have a session there as well.  &lt;br /&gt;&amp;#160;  &lt;br /&gt;AUDITORIUM – Dev Track  &lt;br /&gt;9:00 - 9:30: Opening Speech - Feroz Mahmood  &lt;br /&gt;9:30 - 10:30: Development in ASP.NET [LINQ, Web Forms, Dynamic Data] - Tanzim Saqib  &lt;br /&gt;10:30 - 11:15: My First ASP.NET MVC App - Mehfuz Hossain  &lt;br /&gt;11:15 - 11:45 : Unit Testing in MVC and Demo of dotnetshoutouts.com - Kazi Manzur Rashid  &lt;br /&gt;11:45- 12:30: Developing in Silverlight - Faisal Hossain Khan   &lt;br /&gt;12:30 - 1:30: Lunch  &lt;br /&gt;1:30 - 2:00 : Introduction to Sharepoint/ MOSS - Jannatul Ferdous  &lt;br /&gt;2:00 - 2:45: Production Challenges of ASP.NET Websites - Omar Al Zabir  &lt;br /&gt;2:45 - 3:15: Windows Azure - Ashic  &lt;br /&gt;3:15 - 3:45: Tea Break  &lt;br /&gt;3:45 - 4:30:&amp;#160; Overview of Visual Studio Team System 2010 - Mohammad Ashraful Alam  &lt;br /&gt;4:30 - 5:30:&amp;#160;&amp;#160; Features of Windows 7 - IE8 and Windows Live Features - Omi Azad  &lt;br /&gt;BREAK OUT – IT Pro Track  &lt;br /&gt;9:00 - 9:30: Opening Speech - Feroz Mahmood [IN AUDITORIUM]  &lt;br /&gt;9:30 – 10:30: Exchange Server 2010  &lt;br /&gt;10:30 - 11:30: Windows Server 2008 - Virtualisation &amp;amp; HyperV  &lt;br /&gt;11:30 - 12:30: Talking Windows Server 2008 and R2 [Windows Client &amp;amp; Windows Server 2008 NAP – Better Together] - Anwar Hossain (Technical Specialist, MS Bangladesh)  &lt;br /&gt;12:30 - 1:30: Lunch  &lt;br /&gt;1:30 - 2:15:&amp;#160; Session on MS Project &amp;amp; EPM : M. Manzurur Rahman (CEO, ICT Alliance)  &lt;br /&gt;2:15 - 3:00: Office 2007   &lt;br /&gt;3:00 - 3:30: Tea Break  &lt;br /&gt;3:30 - 4:30:&amp;#160; Introduction to SQL Server 2008  &lt;br /&gt;4:30 - 5:30:&amp;#160;&amp;#160; Features of Windows 7 - IE8 and Windows Live Features - Omi Azad [IN AUDITORIUM]&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/omaralzabirblog?a=zrsF0EqMDJs:msMnaB_O5w8:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/omaralzabirblog?i=zrsF0EqMDJs:msMnaB_O5w8:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/omaralzabirblog?a=zrsF0EqMDJs:msMnaB_O5w8:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/omaralzabirblog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/omaralzabirblog?a=zrsF0EqMDJs:msMnaB_O5w8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/omaralzabirblog?i=zrsF0EqMDJs:msMnaB_O5w8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/omaralzabirblog?a=zrsF0EqMDJs:msMnaB_O5w8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/omaralzabirblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/omaralzabirblog?a=zrsF0EqMDJs:msMnaB_O5w8:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/omaralzabirblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/omaralzabirblog?a=zrsF0EqMDJs:msMnaB_O5w8:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/omaralzabirblog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/omaralzabirblog?a=zrsF0EqMDJs:msMnaB_O5w8:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/omaralzabirblog?i=zrsF0EqMDJs:msMnaB_O5w8:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/omaralzabirblog?a=zrsF0EqMDJs:msMnaB_O5w8:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/omaralzabirblog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/omaralzabirblog/~4/zrsF0EqMDJs" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/Z2mwDWK93Bg/asp-net-ajax-testing-made-easy-using-visual-studio-2008-web-test.aspx"&gt;ASP.NET AJAX testing made easy using Visual Studio 2008 Web Test&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Monday, May 25, 2009&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;Visual Studio 2008 comes with rich Web Testing support, but it’s not rich enough to test highly dynamic AJAX websites where the page content is generated dynamically from database and the same page output changes very frequently based on some external data source e.g. RSS feed. Although you can use the Web Test Record feature to record some browser actions by running a real browser and then play it back. But if the page that you are testing changes everytime you visit the page, then your recorded tests no longer work as expected. The problem with recorded Web Test is that it stores the generated ASP.NET Control ID, Form field names inside the test. If the page is no longer producing the same ASP.NET Control ID or same Form fields, then the recorded test no longer works. A very simple example is in VS Web Test, you can say “click the button with ID ctrl00_UpdatePanel003_SubmitButton002”, but you cannot say “click the 2nd Submit button inside the third UpdatePanel”. Another key limitation is in Web Tests, you cannot address Controls using the Server side Control ID like “SubmitButton”. You have to always use the generated Client ID which is something weird like “ctrl_00_SomeControl001_SubmitButton”. Moreover, if you are making AJAX calls where certain call returns some JSON or updates some UpdatePanel and then based on the server returned response, you want to make further AJAX calls or post the refreshed UpdatePanel, then recorded tests don’t work properly. You *do* have the option to write the tests hand coded and write code to handle such scenario but it’s pretty difficult to write hand coded tests when you are using UpdatePanels because you have to keep track of the page viewstates, form hidden variables etc across async post backs. So, I have built a library that makes it significantly easier to test dynamic AJAX websites and UpdatePanel rich web pages. There are several ExtractionRule and ValidationRule available in the library which makes testing Cookies, Response Headers, JSON output, discovering all UpdatePanel in a page, finding controls in the response body, finding controls inside some UpdatePanel all very easy.  &lt;br /&gt;First, let me give you an example of what can be tested using this library. My open source project Dropthings produces a Web 2.0 Start Page where the page is composed of widgets.   &lt;br /&gt;  &lt;br /&gt;Each widget is composed of two UpdatePanel. There’s a header area in each widget which is one UpdatePanel and the body area is another UpdatePanel. Each widget is rendered from database using the unique ID of the widget row, which is an INT IDENTITY. Every page has unique widgets, with unique ASP.NET Control ID. As a result, there’s no way you can record a test and play it back because none of the ASP.NET Control IDs are ever same for the same page on different visits. This is where my library comes to the rescue.  &lt;br /&gt;See the web test I did:  &lt;br /&gt;  &lt;br /&gt;This test simulates an anonymous user visit. When anonymous user visits Dropthings for the first...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Z2mwDWK93Bg:aatI4Djkmto:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Z2mwDWK93Bg:aatI4Djkmto:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Z2mwDWK93Bg:aatI4Djkmto:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Z2mwDWK93Bg:aatI4Djkmto:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Z2mwDWK93Bg:aatI4Djkmto:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Z2mwDWK93Bg:aatI4Djkmto:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Z2mwDWK93Bg:aatI4Djkmto:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Z2mwDWK93Bg:aatI4Djkmto:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Z2mwDWK93Bg:aatI4Djkmto:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Z2mwDWK93Bg:aatI4Djkmto:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Z2mwDWK93Bg:aatI4Djkmto:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/Z2mwDWK93Bg" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/i4nIiY2Tnqo/web-2-0-ajax-portal-using-jquery-asp-net-3-5-silverlight-linq-to-sql-wf-and-unity.aspx"&gt;Web 2.0 AJAX Portal using jQuery, ASP.NET 3.5, Silverlight, Linq to SQL, WF and Unity&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Wednesday, April 08, 2009&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;Dropthings – my open source Web 2.0 Ajax Portal has gone through a technology overhauling. Previously it was built using ASP.NET AJAX, a little bit of Workflow Foundation and Linq to SQL. Now Dropthings boasts full jQuery front-end combined with ASP.NET AJAX UpdatePanel, Silverlight widget, full Workflow Foundation implementation on the business layer, 100% Linq to SQL Compiled Queries on the data access layer, Dependency Injection and Inversion of Control (IoC) using Microsoft Enterprise Library 4.1 and Unity. It also has a ASP.NET AJAX Web Test framework that makes it real easy to write Web Tests that simulates real user actions on AJAX web pages. This article will walk you through the challenges in getting these new technologies to work in an ASP.NET website and how performance, scalability, extensibility and maintainability has significantly improved by the new technologies. Dropthings has been licensed for commercial use by prominent companies including BT Business, Intel, Microsoft IS, Denmark Government portal for Citizens; Startups like Limead and many more. So, this is serious stuff! There’s a very cool open source implementation of Dropthings framework available at National University of Singapore portal.  &lt;br /&gt;Visit: http://dropthings.omaralzabir.com  &lt;br /&gt;  &lt;br /&gt;I have published a new article on this on CodeProject:  &lt;br /&gt;http://www.codeproject.com/KB/ajax/Web20Portal.aspx  Get the source code  &lt;br /&gt;Latest source code is hosted at Google code:  &lt;br /&gt;http://code.google.com/p/dropthings  &lt;br /&gt;There’s a CodePlex site for documentation and issue tracking:  &lt;br /&gt;http://www.codeplex.com/dropthings  &lt;br /&gt;You will need Visual Studio 2008 Team Suite with Service Pack 1 and Silverlight 2 SDK in order to run all the projects. If you have only Visual Studio 2008 Professional, then you will have to remove the Dropthings.Test project.  New features introduced  &lt;br /&gt;Dropthings new release has the following features:     Template users – you can define a user who’s pages and widgets are used as a template for new users. Whatever you put in that template user’s pages, it will be copied for every new user. Thus this is an easier way to define the default pages and widgets for new users. Similarly you can do the same for a registered user. The template users can be defined in the web.config.     Widget-to-Widget communication – Widgets can send message to each other. Widgets can subscribe to an Event Broker and exchange messages using a Pub-Sub pattern.     WidgetZone – you can create any number of zones in any shape on the page. You can have widgets laid in horizontal layout, you can have zones on different places on the page and so on. With this zone model, you are no longer limited to the Page-Column model where you could only have N vertical columns.     Role based widgets – now widgets are mapped to roles so that you can allow different users to see different widget list using ManageWidgetPersmission.aspx.     Role based page setup – you can define page setup for different roles. For...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=i4nIiY2Tnqo:mYjpzi3TiFg:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=i4nIiY2Tnqo:mYjpzi3TiFg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=i4nIiY2Tnqo:mYjpzi3TiFg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/i4nIiY2Tnqo" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/-LIRJgSGBXo/memory-leak-with-delegates-and-workflow-foundation.aspx"&gt;Memory Leak with delegates and workflow foundation&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Saturday, March 14, 2009&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;Recently after Load Testing my open source project Dropthings, I encountered a lot of memory leak. I found lots of Workflow Instances and Linq Entities were left in memory and never collected. After profiling the web application using .NET Memory Profiler, it showed the real picture:  &lt;br /&gt;  &lt;br /&gt;It shows you that instances of the several types are being created but not being removed. You see the “New” column has positive value, but the “Remove” column has 0. That means new instances are being created, but not removed. Basically the way you do Memory Profiling is, you take two snapshots. Say you take one snapshot when you first visit your website. Then you do some action on the website that results in allocation of objects. Then you take another snapshot. When you compare both snapshots, you can see how many instances of classes were created between these two snapshots and how many were removed. If they are not equal, then you have leak. Generally in web application many objects are created on every page hit and the end of the request, all those objects are supposed to be released. If they are not released, then we have a problem. But that’s the scenario for desktop applications because in a desktop application, objects can remain in memory until app is closed. But you should know best from the code which objects were supposed to go out of scope and get released.  &lt;br /&gt;For beginners, leak means objects are being allocated but not being freed because someone is holding reference to the objects. When objects leak, they remain in memory forever, until the process (or app domain) is closed. So, if you have a leaky website, your website is continuously taking up memory until it runs out of memory on the web server and thus crash. So, memory leak is a bad – it prevents you from running your product for long duration and requires frequent restart of app pool.   &lt;br /&gt;So, the above screenshot shows Workflow and Linq related classes are not being removed, and thus leaking. This means somewhere workflow instances are not being released and thus all workflow related objects are remaining. You can see the number is same 48 for all workflow related objects. This is a good indication that, almost every instance of workflow is leaked because there were total 48 workflows created and ran. Moreover it indicates we have a leak from a top Workflow instance level, not in some specific Activity or somewhere deep in the code.  &lt;br /&gt;As the workflows use Linq stuff, they held reference to the Linq stuffs and thus the Linq stuffs leaked as well. Sometimes you might be looking for why A is leaking. But you actually end up finding that since B was holding reference to A and B was leaking and thus A was leaking as well. This is sometimes tricky to figure out and you spend a lot of time looking at the wrong direction.  &lt;br /&gt;Now let me show you the buggy code:  ManualWorkflowSchedulerService manualScheduler = &lt;br /&gt;  workflowRuntime.GetService&amp;lt;ManualWorkflowSchedulerService&amp;gt;();&lt;br /&gt;&lt;br /&gt;WorkflowInstance...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=-LIRJgSGBXo:uk3bMbquKhU:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=-LIRJgSGBXo:uk3bMbquKhU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=-LIRJgSGBXo:uk3bMbquKhU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/-LIRJgSGBXo" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/dddCH2jA0Qk/optimize-asp-net-membership-stored-procedures-for-greater-speed-and-scalability.aspx"&gt;Optimize ASP.NET Membership Stored Procedures for greater speed and scalability&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Friday, March 13, 2009&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;Last year at Pageflakes, when we were getting millions of hits per day, we were having query timeout due to lock timeout and Transaction Deadlock errors. These locks were produced from aspnet_Users and aspnet_Membership tables. Since both of these tables are very high read (almost every request causes a read on these tables) and high write (every anonymous visit creates a row on aspnet_Users), there were just way too many locks created on these tables per second. SQL Counters showed thousands of locks per second being created. Moreover, we had queries that would select thousands of rows from these tables frequently and thus produced more locks for longer period, forcing other queries to timeout and thus throw errors on the website.&lt;br /&gt;&lt;br /&gt;If you have read my last blog post, you know why such locks happen. Basically every table when it grows up to hold millions of records and becomes popular goes through this trouble. It&amp;rsquo;s just a part of scalability problem that is common to database. But we rarely take prevention about it in our early design.&lt;br /&gt;&lt;br /&gt;The solution is simple, you should either have WITH (NOLOCK) or SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED before SELECT queries. Either of this will do. They tell SQL Server not to hold any lock on the table while it is reading the table. If some row is locked while the read is happening, it will just ignore that row. When you are reading a table thousand times per second, without these options, you are issuing lock on many places around the table thousand times per second. It not only makes read from table slower, but also so many lock prevents insert, update, delete from happening timely and thus queries timeout. If you have queries like &amp;ldquo;show the currently online users from last one hour based on LastActivityDate field&amp;rdquo;, that is going to issue such a wide lock that even other harmless select queries will timeout. And did I tell you that there&amp;rsquo;s no index on LastActivityDate on aspnet_Users table?&lt;br /&gt;&lt;br /&gt;Now don&amp;rsquo;t blame yourself for not putting either of these options on your every stored proc and every dynamically generated SQL from the very first day. ASP.NET developers made the same mistake. You won&amp;rsquo;t see either of these used in any of the stored procs used by ASP.NET Membership. For example, the following stored proc gets called whenever you access Profile object:&lt;br /&gt;ALTER PROCEDURE [dbo].[aspnet_Profile_GetProperties]&lt;br /&gt;    @ApplicationName      nvarchar(256),&lt;br /&gt;    @UserName             nvarchar(256),&lt;br /&gt;    @CurrentTimeUtc       datetime&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;&lt;br /&gt;    DECLARE @ApplicationId uniqueidentifier&lt;br /&gt;    SELECT  @ApplicationId = NULL&lt;br /&gt;    SELECT  @ApplicationId = ApplicationId FROM &lt;br /&gt;      dbo.aspnet_Applications WHERE LOWER(@ApplicationName) = LoweredApplicationName&lt;br /&gt;    IF (@ApplicationId IS NULL)&lt;br /&gt;        RETURN&lt;br /&gt;&lt;br /&gt;    DECLARE @UserId uniqueidentifier&lt;br /&gt;    DECLARE @LastActivityDate datetime&lt;br /&gt;    SELECT  @UserId = NULL&lt;br /&gt;&lt;br /&gt;    SELECT @UserId = UserId, @LastActivityDate = LastActivityDate&lt;br /&gt;    FROM...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=dddCH2jA0Qk:tbN1TJrDKSA:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=dddCH2jA0Qk:tbN1TJrDKSA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=dddCH2jA0Qk:tbN1TJrDKSA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/dddCH2jA0Qk" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/zpw40Zu0jms/linq-to-sql-solve-transaction-deadlock-and-query-timeout-problem-using-uncommitted-reads.aspx"&gt;Linq to SQL solve Transaction deadlock and Query timeout problem using uncommitted reads&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Saturday, March 07, 2009&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;When your database tables start accumulating thousands of rows and many users start working on the same table concurrently, SELECT queries on the tables start producing lock contentions and transaction deadlocks. This is a common problem in any high volume website. As soon as you start getting several concurrent users hitting your website that results in SELECT queries on some large table like aspnet_users table that are also being updated very frequently, you end up having one of these errors:     &lt;br /&gt;Transaction (Process ID ##) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.    &lt;br /&gt;Or,     &lt;br /&gt;Timeout Expired. The Timeout Period Elapsed Prior To Completion Of The Operation Or The Server Is Not Responding.    &lt;br /&gt;The solution to these problems are – use proper index on the table and use transaction isolation level Read Uncommitted or WITH (NOLOCK) in your SELECT queries. So, if you had a query like this:  SELECT * FORM aspnet_users &lt;br /&gt;where ApplicationID =’xxx’ AND LoweredUserName = &amp;#39;someuser&amp;#39;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You should end up having any of the above errors under high load. There are two ways to solve this:&lt;br /&gt;&lt;br /&gt;SET TRANSACTION LEVEL READ UNCOMMITTED;&lt;br /&gt;SELECT * FROM aspnet_Users &lt;br /&gt;WHERE ApplicationID =’xxx’ AND LoweredUserName = &amp;#39;someuser&amp;#39;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Or use the WITH (NOLOCK):&lt;br /&gt;&lt;br /&gt;SELECT * FROM aspnet_Users WITH (NOLOCK) &lt;br /&gt;WHERE ApplicationID =’xxx’ AND LoweredUserName = &amp;#39;someuser&amp;#39;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The reason for the errors are that since aspnet_users is a high read and high write table, during read, the table is partially locked and during write, it is also locked. So, when the locks overlap on each other from several queries and especially when there’s a query that’s trying to read a large number of rows and thus locking large number of rows, some of the queries either timeout or produce deadlocks.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Linq to Sql does not produce queries with the WITH (NOLOCK) option nor does it use READ UNCOMMITTED. So, if you are using Linq to SQL queries, you are going to end up with any of these problems on production pretty soon when your site becomes highly popular.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;For example, here’s a very simple query:&lt;br /&gt;&lt;br /&gt;using (var db = new DropthingsDataContext())&lt;br /&gt;{&lt;br /&gt;    var user = db.aspnet_Users.First();&lt;br /&gt;    var pages = user.Pages.ToList();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;DropthingsDataContext is a DataContext built from Dropthings database.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;When you attach SQL Profiler, you get this:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You see none of the queries have READ UNCOMMITTED or WITH (NOLOCK). &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The fix is to do this:&lt;br /&gt;&lt;br /&gt;using (var db = new DropthingsDataContext2())&lt;br /&gt;{&lt;br /&gt;    db.Connection.Open();&lt;br /&gt;    db.ExecuteCommand(&amp;quot;SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;&amp;quot;);&lt;br /&gt;&lt;br /&gt;    var user = db.aspnet_Users.First();&lt;br /&gt;    var pages = user.Pages.ToList();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This will result in the following profiler output&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;As you see, both queries execute within the same connection and the isolation level is set before the queries execute. So, both queries enjoy the isolation level.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now there’s a...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=zpw40Zu0jms:EGhEU2SFyWQ:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=zpw40Zu0jms:EGhEU2SFyWQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=zpw40Zu0jms:EGhEU2SFyWQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/zpw40Zu0jms" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/nOzECG83psk/strongly-typed-workflow-input-and-output-arguments.aspx"&gt;Strongly typed workflow input and output arguments&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Saturday, December 27, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;When you run a Workflow using Workflow Foundation, you pass arguments to the workflow in a Dictionary form where the type of Dictionary is Dictionary&amp;lt;string, object&amp;gt;. This means you miss the strong typing features of .NET languages. You have to know what arguments the workflow expects by looking at the Workflow public properties. Moreover, there’s no way to make arguments required. You pass parameter, expect it to run, if it throws exception, you pass more arguments, hope it works now. Similarly, if you are running workflow synchronously using ManualWorkflowSchedulerService, you expect return arguments from the Workflow immediately, but there again, you have to rely on the Dictionary key and value pair. No strong typing there as well.  &lt;br /&gt;In order to solve this, so that you could pass Workflow arguments as strongly typed classes, you can establish a format that every Workflow has only two arguments named &amp;quot;Request” and “Response” and none other. Whatever needs to be passed to the Workflow and expected out of it, must be passed via Request and must be expected via Response properties. Now the type of these arguments can be workflow specific, it can be any class with one or more parameters. This way, you could write code like this:  &lt;br /&gt;  &lt;br /&gt;The advantages of these strongly typed approach are:      Compile time validation of input parameters passed to workflow. No risk of passing unexpected object in Dictionary’s object type value.    Enforce required values by creating Request objects with non-default constructor.    Establish a fixed contract for Workflow input and output via the strongly typed Request and Response classes or interfaces.    Validate input arguments for the Workflow directly from the Request class, without going through the overhead of running a workflow.   &lt;br /&gt;If we follow this approach, we create workflows with only two DependencyProperty, one for Request and one for Response. Showing you an example from my open source project Dropthings, which uses Workflow for the entire Business Layer. Below you see the Workflow that executes when a new user visits Dropthings.com, creates a new user and setups all the pages and widgets for the user. It has only two Dependency property – Request and Response.  &lt;br /&gt;   &lt;br /&gt;The Request parameters is of type IUserVisitWorkflowRequest. So, you can pass any class as Request argument that implements the interface.   &lt;br /&gt;   &lt;br /&gt;Here I have used fancy inheritance to create Request object hierarchy. You don’t need to do that. Just remember, you can pass any class. You don’t even need to use interface for Request parameter. It can be a class directly. I use all these interfaces in order to facilitate Dependency Inversion.  &lt;br /&gt;Similarly, the Response object is also a class.  &lt;br /&gt;  &lt;br /&gt;The Response returns quite some properties. So, it’s kinda handy to wrap them all in one property.  &lt;br /&gt;So, there you have it, strongly typed Workflow arguments. You can attach properties of the Request object to any activity directly form the...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=nOzECG83psk:ZkqK3QKQmqM:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=nOzECG83psk:ZkqK3QKQmqM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=nOzECG83psk:ZkqK3QKQmqM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/nOzECG83psk" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/R5QvBFRfDKc/99-99-available-asp-net-and-sql-server-saas-production-architecture.aspx"&gt;99.99% available ASP.NET and SQL Server SaaS Production Architecture&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Wednesday, December 10, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;You have a hot ASP.NET+SQL Server product, growing at thousand users per day and you have hit the limit of your own garage hosting capability. Now that you have enough VC money in your pocket, you are planning to go out and host on some real hosting facility, maybe a colocation or managed hosting. So, you are thinking, how to design a physical architecture that will ensure performance, scalability, security and availability of your product? How can you achieve four-nine (99.99%) availability? How do you securely let your development team connect to production servers? How do you choose the right hardware for web and database server? Should you use Storage Area Network (SAN) or just local disks on RAID? How do you securely connect your office computers to production environment?&lt;br /&gt;&lt;br /&gt;Here I will answer all these queries. Let me first show you a diagram that I made for Pageflakes where we ensured we get four-nine availability. Since Pageflakes is a Level 3 SaaS, it&amp;rsquo;s absolutely important that we build a high performance, highly available product that can be used from anywhere in the world 24/7 and end-user gets quick access to their content with complete personalization and customization of content and can share it with others and to the world. So, you can take this production architecture as a very good candidate for Level 3 SaaS: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here&amp;rsquo;s a CodeProject article that explains all the ideas:&lt;br /&gt;&lt;br /&gt;99.99% available ASP.NET and SQL Server SaaS Production Architecture&lt;br /&gt;&lt;br /&gt;Hope you like it. Appreciate your vote.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=R5QvBFRfDKc:mqCjLkXCtpI:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=R5QvBFRfDKc:mqCjLkXCtpI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=R5QvBFRfDKc:mqCjLkXCtpI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/R5QvBFRfDKc" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/YXw8_xnXYOs/linq-to-sql-delete-an-entity-using-primary-key-only.aspx"&gt;Linq to SQL: Delete an entity using Primary Key only&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Thursday, October 30, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;Linq to Sql does not come with a function like .Delete(ID) which allows you to delete an entity using it&amp;rsquo;s primary key. You have to first get the object that you want to delete and then call .DeleteOnSubmit(obj) to queue it for delete. Then you have to call DataContext.SubmitChanges() to play the delete queries on database. So, how to delete object without getting them from database and avoid database roundtrip?&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;You can call this function using DeleteByPK&amp;lt;Employee, int&amp;gt;(10, dataContext);&lt;br /&gt;&lt;br /&gt;First type is the entity type and second one is the type of the primary key. If your object&amp;rsquo;s primary key is a Guid field, specify Guid instead of int.&lt;br /&gt;&lt;br /&gt;How it works:&lt;br /&gt;&lt;br /&gt;It figures out the table name and the primary key field name from the entity &lt;br /&gt;Then it uses the table name and primary key field name to build a DELETE query &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Figuring out the table name and primary key field name is a bit hard. There&amp;rsquo;s some reflection involved. The GetTableDef&amp;lt;TSource&amp;gt;() returns the table name and primary key field name for an entity.&lt;br /&gt;&lt;br /&gt;Every Linq Entity class is decorated with a Table attribute that has the table name:&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Then the primary key field is decorated with a Column attribute with IsPrimaryKey = true.&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;So, using reflection we can figure out the table name and the primary key property and the field name.&lt;br /&gt;&lt;br /&gt;Here&amp;rsquo;s the code that does it:&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Before you scream &amp;ldquo;Reflection is SLOW!!!!&amp;rdquo; the definition is cached. So, reflection is used only once per appDomain per entity. Subsequent call is just a dictionary lookup away, which is as fast as it can get.&lt;br /&gt;&lt;br /&gt;You can also delete a collection of object without ever getting any one of them. The the following function to delete a whole bunch of objects:&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;The code is available here:&lt;br /&gt;&lt;br /&gt;http://code.msdn.microsoft.com/DeleteEntitiesLinq&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=YXw8_xnXYOs:SIiDuFmSUOc:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=YXw8_xnXYOs:SIiDuFmSUOc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=YXw8_xnXYOs:SIiDuFmSUOc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/YXw8_xnXYOs" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/fvJttJrO18w/how-to-convince-developers-and-management-to-use-automated-unit-test-for-ajax-websites.aspx"&gt;How to convince developers and management to use automated unit test for AJAX websites&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Monday, October 27, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;Everyone agrees that unit testing is a good thing, we should all write unit tests. We read articles and blogs to keep us up-to-date on what’s going on in the unit test world so that we can sound cool talking to peers at lunch. But when we really sit down and try to write unit tests ourselves – “Naaah, this is waste of time, let’s ask my QA to test it; that’s much more reliable and guaranteed way to test this. What’s the point testing these functions when there are so many other functions that we should unit test first?” Had such moment yourself or with someone else? Read on.  &lt;br /&gt;I had a conversation with our development lead Mike (using a highly generic name since my last post caused some trouble), who runs “the show” in our engineering team. As usual there was reservation in introducing unit test to regular development schedule. Mike also had valid points about lack of powerful tools for doing unit test on AJAX websites. He also had confusion on ‘what’ and ‘how’ to unit test our code so that we aren’t just testing database failures but real user actions that executes both business and rendering logics. So, the discussion has a lot of useful information, that will help you take the right decision when you want to sell unit test to your ASP.NET and/or AJAX development team and finally to higher management so that you can buy enough time for the effort.  &lt;br /&gt;Friday, Jan 2007 – hallway      &lt;br /&gt;Omar: Hey Mike, we need to start doing unit testing at least on our web services. We are wasting way too much time on manual QA. Since we are an AJAX shop, unit testing all our web services should give us pretty well coverage.   &lt;br /&gt;Mike: Sure, that sounds fun. I will do some feasibility check and see how can we chip this in into our next sprint.  &lt;br /&gt;Friday, Feb 2007 – washroom&amp;#160; &lt;br /&gt;Omar: Hey Mike, let’s start doing unit tests. I haven’t seen any tests last month. Can we start from this sprint?  &lt;br /&gt;Mike: Sure, we can surely start from this sprint. Let me find out which tool is the right one for us.  &lt;br /&gt;Friday, March 2007 – meeting room     &lt;br /&gt;Omar: Hey Mike, haven’t seen any unit tests in the solution so far. Let’s seriously start writing unit tests. Did you make any plan how you want to start unit testing the webservices?  &lt;br /&gt;Mike: Yeah, I did some digging around and found some tools. But most of them are for non-AJAX sites where you can programmatically hit a URL or programmatically do HTTP POST on a URL. You can also record button clicks and form posts from the browser. There’s Visual Studio’s Web Test, which does pretty good job recording regular ASP.NET site, but poor on AJAX sites. Moreover, you need to buy Team Suite edition to get that Web Test feature. Besides, recording tests and playing them back really does not help us because all those tests contain hard coded data. We can’t repeat a particular step many times with random data, at least not using any off-the-shelf tools. We need to test things carefully and systematically using random data set and sometimes use...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=fvJttJrO18w:kiUnSE-1Xxg:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=fvJttJrO18w:kiUnSE-1Xxg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=fvJttJrO18w:kiUnSE-1Xxg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/fvJttJrO18w" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/Nc-bH9JpSO0/solving-common-problems-with-compiled-queries-in-linq-to-sql-for-high-demand-asp-net-websites.aspx"&gt;Solving common problems with Compiled Queries in Linq to Sql for high demand ASP.NET websites&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Monday, October 27, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;If you are using Linq to SQL, instead of writing regular Linq Queries, you should be using Compiled Queries. if you are building an ASP.NET web application that&amp;rsquo;s going to get thousands of hits per hour, the execution overhead of Linq queries is going to consume too much CPU and make your site slow. There&amp;rsquo;s a runtime cost associated with each and every Linq Query you write. The queries are parsed and converted to a nice SQL Statement on *every* hit. It&amp;rsquo;s not done at compile time because there&amp;rsquo;s no way to figure out what you might be sending as the parameters in the queries during runtime. So, if you have common Linq to Sql statements like the following one throughout your growing web application, you are soon going to have scalability nightmares:&lt;br /&gt;&lt;br /&gt;var query = from widget in dc.Widgets&lt;br /&gt;                where widget.ID == id &amp;amp;&amp;amp; widget.PageID == pageId&lt;br /&gt;                select widget;&lt;br /&gt;&lt;br /&gt;var widget = query.SingleOrDefault();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There&amp;rsquo;s a nice blog post by JD Conley that shows how evil Linq to Sql queries are:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You see how many times SqlVisitor.Visit is called to convert a Linq Query to its SQL representation? The runtime cost to convert a Linq query to its SQL Command representation is just way too high.&lt;br /&gt;&lt;br /&gt;Rico Mariani has a very informative performance comparison of regular Linq queries vs Compiled Linq queries performance:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Compiled Query wins on every case.&lt;br /&gt;&lt;br /&gt;So, now you know about the benefits of compiled queries. If you are building ASP.NET web application that is going to get high traffic and you have a lot of Linq to Sql queries throughout your project, you have to go for compiled queries. Compiled Queries are built for this specific scenario. &lt;br /&gt;&lt;br /&gt;In this article, I will show you some steps to convert regular Linq to Sql queries to their Compiled representation and how to avoid the dreaded exception &amp;ldquo;Compiled queries across DataContexts with different LoadOptions not supported.&amp;rdquo;&lt;br /&gt;&lt;br /&gt;Here are some step by step instruction on converting a Linq to Sql query to its compiled form:&lt;br /&gt;&lt;br /&gt;First we need to find out all the external decision factors in a query. It mostly means parameters in the WHERE clause. Say, we are trying to get a user from aspnet_users table using Username and Application ID:&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Here, we have two external decision factor &amp;ndash; one is the Username and another is the Application ID. So, first think this way, if you were to wrap this query in a function that will just return this query as it is, what would you do? You would create a function that takes the DataContext (dc named here), then two parameters named userName and applicationID, right?&lt;br /&gt;&lt;br /&gt;So, be it. We create one function that returns just this query:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Next step is to replace this function with a Func&amp;lt;&amp;gt; representation that returns the query. This is the hard part. If you haven&amp;rsquo;t dealt with Func&amp;lt;&amp;gt; and Lambda expression before, then I suggest you read this and this and then continue.&lt;br /&gt;&lt;br /&gt;So, here&amp;rsquo;s the delegate...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Nc-bH9JpSO0:QPjYis-Ap2U:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Nc-bH9JpSO0:QPjYis-Ap2U:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Nc-bH9JpSO0:QPjYis-Ap2U:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/Nc-bH9JpSO0" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/vBOI7L_fwcw/tips-and-tricks-to-rescue-overdue-projects.aspx"&gt;Tips and tricks to rescue overdue projects&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Monday, October 20, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;One of my friends, who runs his own offshore development shop, was having nightmare situation with one of his customers. He&amp;#39;s way overdue on a release, the customer is screaming everyday, he&amp;#39;s paying his team from his own pocket, customer is sending an ever increasing list of changes and so on. Here&amp;#39;s how we discussed some ideas to get out of such a situation and make sure it does not repeat in future:   &lt;br /&gt;Kabir: Hey, can you help me? My customer is making us work for free for extra two months to fix bugs from our last delivery. We did what he said. But after he saw the output, he came up with hundred changes, which he somehow presents as bugs or missing features and make them look like they are all our fault and making us work for last two months for free. He is sending new changes every week. We have no idea when we will complete the iteration.   &lt;br /&gt;Omar: I see. Did you get a signed list of requirements from customer before you started the development?   &lt;br /&gt;Kabir: Of course, I did. He sent us a word document explaining what he wants and we sent him a task breakup with hour estimates and total duration of three months. Now after three months when we showed him the product, he said, it&amp;#39;s no where close to what he had expected. Then he sent a gigantic list of things to change.   &lt;br /&gt;Omar: All of those are bugs?   &lt;br /&gt;Kabir: Of course not. Most of them are new features.   &lt;br /&gt;Omar: Then why don&amp;#39;t you say those are new features? You have the original word document to prove. Just ask him to show where in the word document did he said X needs to be done?   &lt;br /&gt;Kabir: Well..., he&amp;#39;s tricky. He somehow makes things look like it is obvious that X needs to be done and he&amp;#39;s not going to accept a requirement as done until X is done. For example, he said there must be a complete login form in the homepage. So, we did a typical login form with user name, password and OK, Cancel button. Now he says where&amp;#39;s the email verification thing? We said, you did not ask for it. He said, &amp;quot;this is obvious, every login form has a forgot password and email verification; I said *complete* login form, not half-baked login form&amp;quot;. So, you see, we can&amp;#39;t really argue to keep our image. Then, we did the login form exactly how he said. Now he says, where the client side validations of proper email address, username length, password confirmation? We said, you never asked for it! He says, &amp;quot;come on, every single website nowadays has AJAX enabled client side validation, do I have to tell you every single thing? Aren&amp;#39;t you guys smart enough to figure this out? You are already doing this for the third time, can&amp;#39;t you do it really well this time?&amp;quot;   &lt;br /&gt;Omar: OK, stop. I see what&amp;#39;s your problem. Some customer will always try to make you work more for less money. They will try to squeeze out every bit of development they can for their bucks. So, you have to be extra careful on how much you commit to them and make sure they cannot chip in more...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=vBOI7L_fwcw:4pKN0lLk8FM:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=vBOI7L_fwcw:4pKN0lLk8FM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=vBOI7L_fwcw:4pKN0lLk8FM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/vBOI7L_fwcw" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/Fb5wVsfQIf4/an-agile-developer-s-workflow-when-scrum-is-used.aspx"&gt;An Agile Developer's workflow when SCRUM is used&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Saturday, October 11, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;If you are planning to start SCRUM at your company, you might need to train developers and QA to get into the mindset of an Agile developer. SCRUM is only successful when the developers and QA get into the habit of following the principles of SCRUM by heart. So, sometimes you need to offer training or do trial sprints to give some room to your developers how to get used to the working fashion of SCRUM. Giving them a handy workflow diagram that shows how they should work helps soothe the steep learning curve required for non-super star developers. I made such a workflow while I was teaching SCRUM at my friend&amp;#39;s company. The following diagram was printed and hung over the desk of each and every developer to help them grasp the culture of SCRUM quickly:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;We use Flyspray for issue tracking, so you will see the mention of it frequently. &lt;br /&gt;&lt;br /&gt;You will see the step to &amp;quot;Update Sprint backlog with remaining hours&amp;quot; is missing. This is done kinda verbally and scrum master (sometimes same person who is the product owner) keeps track of it.&lt;br /&gt;&lt;br /&gt;Hope you find this useful.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Fb5wVsfQIf4:nPzXbpWOXEA:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Fb5wVsfQIf4:nPzXbpWOXEA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Fb5wVsfQIf4:nPzXbpWOXEA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/Fb5wVsfQIf4" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/gcjuL_ndnOA/asp-net-website-continuous-integration-deployment-using-cruisecontrol-net-subversion-msbuild-and-robocopy.aspx"&gt;ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Monday, October 06, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;You can setup continuous integration and automated deployment for your web application using CruiseControl.NET, Subversion, MSBuild and Robocopy. I will show you how you can automatically build the entire solution, email build report to developers and QA, deploy latest code in IIS all using CruiseControl.NET every N minutes. &lt;br /&gt;&lt;br /&gt;First get the following:&lt;br /&gt;&lt;br /&gt;CruiseControl.NET  &lt;br /&gt;Subversion (install the command line tools and add the Subversion bin path to PATH environment variable)  &lt;br /&gt;Robocopy (Windows Vista/2008 has it built-in, here&amp;#39;s the link for Windows 2003)  &lt;br /&gt;Install .NET Framework. You need it for MSBuild. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You will learn how I have configured Continuous Integration and Deployment for my open source AJAX Portal project www.Dropthings.com. The code is hosted at CodePlex. When some developer makes a commit, CruiseControl downloads the latest code, builds the entire solution, emails build report and then deploys the latest web site to IIS 6.0.&lt;br /&gt;&lt;br /&gt;After installing CruiseControl.NET, go to Programs -&amp;gt; Cruise Control -&amp;gt; CruiseControl.NET Config.&lt;br /&gt;&lt;br /&gt;Now keep copying and pasting the following XML blocks and make sure you understand each block and make necessary changes:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   1: &amp;lt;cruisecontrol&amp;gt;&lt;br /&gt;   2:     &amp;lt;project name=&amp;quot;Dropthings&amp;quot; queue=&amp;quot;DropthingsQueue&amp;quot; queuePriority=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;   3:         &amp;lt;!-- &lt;br /&gt;   4:         Path to the trunk folder where the full solution starts from. This is where&lt;br /&gt;   5:         subversion checkout and incremental update is performed &lt;br /&gt;   6:         --&amp;gt;&lt;br /&gt;   7:         &amp;lt;workingDirectory&amp;gt;d:\cc\dropthings\code\trunk\&amp;lt;/workingDirectory&amp;gt;&lt;br /&gt;   8:         &amp;lt;!-- Some path where CCNet writes its logs and stuffs. It can be outside the log folder --&amp;gt;&lt;br /&gt;   9:         &amp;lt;artifactDirectory&amp;gt;d:\cc\dropthings\artifact\&amp;lt;/artifactDirectory&amp;gt;&lt;br /&gt;  10:         &amp;lt;category&amp;gt;Dropthings&amp;lt;/category&amp;gt;&lt;br /&gt;  11:         &amp;lt;!-- CCNet installs a web dashboard. Enter the URL of that dashboard here --&amp;gt;&lt;br /&gt;  12:         &amp;lt;webURL&amp;gt;http://localhost/ccnet/&amp;lt;/webURL&amp;gt;&lt;br /&gt;  13:         &amp;lt;modificationDelaySeconds&amp;gt;60&amp;lt;/modificationDelaySeconds&amp;gt;&lt;br /&gt;  14:         &amp;lt;labeller type=&amp;quot;defaultlabeller&amp;quot;&amp;gt;&lt;br /&gt;  15:             &amp;lt;prefix&amp;gt;0.1.&amp;lt;/prefix&amp;gt;&lt;br /&gt;  16:             &amp;lt;incrementOnFailure&amp;gt;true&amp;lt;/incrementOnFailure&amp;gt;&lt;br /&gt;  17:             &amp;lt;labelFormat&amp;gt;000&amp;lt;/labelFormat&amp;gt;&lt;br /&gt;  18:         &amp;lt;/labeller&amp;gt;&lt;br /&gt;  19:         &amp;lt;state type=&amp;quot;state&amp;quot; directory=&amp;quot;State&amp;quot; /&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;First change the working directory. It needs to be the path of the folder where you will have the solution downloaded. I generally create folder structure like this:&lt;br /&gt;&lt;br /&gt;D:\CC - Root for all CC.NET enabled projects &lt;br /&gt;&lt;br /&gt;\ProjectName - Root project folder &lt;br /&gt;&lt;br /&gt;\Code - Code folder where code is downloaded from subversion &lt;br /&gt;&lt;br /&gt;\Artifact - CC.NET generates a lot of stuff. All goes here.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; Next comes the Subversion integration block:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   1: &amp;lt;sourcecontrol type=&amp;quot;svn&amp;quot;&amp;gt;&lt;br /&gt;   2:    ...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=gcjuL_ndnOA:0FVtpVe4JaA:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=gcjuL_ndnOA:0FVtpVe4JaA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=gcjuL_ndnOA:0FVtpVe4JaA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/gcjuL_ndnOA" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/kwIvli9E3gg/using-multiple-broadband-connections-without-using-any-special-router-or-software.aspx"&gt;Using multiple broadband connections without using any special router or software&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Sunday, October 05, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;I have two broadband connections. One cheap connection, which I mostly use for browsing and downloading. Another very expensive connection that I use for voice chat, remote desktop connection etc. Now, using these two connections at the same time required two computers before. But I figured out a way to use both connections at the same time using the same computer. Here&amp;#39;s how: &lt;br /&gt;Connect the cheap internet connection that is used mostly for non-critical purpose like downloading, browsing to a wireless router. &lt;br /&gt;Connect the expensive connection that is used for network latency sensitive work like Voice Conference, Remote Desktop directly via LAN. &lt;br /&gt;When you want to establish a critical connection like starting voice conf app (Skype) or remote desktop client, momentarily disconnect the wireless. This will make your LAN connection the only available internet. So, all the new connections will be established over the LAN. Now you can start Skype and initiate a voice conference or use Remote Desktop client and connect to a computer. The connection will be established over LAN. &lt;br /&gt;Now turn on wireless. Wireless will now become the first preference for Windows to go to internet. So, now you can start Outlook, browser etc and they will be using the wireless internet connection. During this time, Skype and Terminal Client is still connected over the LAN connection. As they use persisted connection, they keep using the LAN connection and do not switch to the wireless.  &lt;br /&gt;This way you get to use two broadband connections simultaneously. &lt;br /&gt;&amp;nbsp;  &lt;br /&gt;Here you see I have data transfer going on through two different connection. The bottom one is the LAN which is maintaining a continuous voice data stream. The upper one is the wireless connection that sometimes consumes bandwidth when I browse. &lt;br /&gt;  &lt;br /&gt;Using Sysinternal&amp;#39;s TCPView, I can see some connection is going through LAN and some through Belkin router. The selected ones - the terminal client and the MSN Messenger is using LAN where the Internet Explorer and Outlook is working over Wireless connection. &lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=kwIvli9E3gg:4yFKK3Xe42I:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=kwIvli9E3gg:4yFKK3Xe42I:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=kwIvli9E3gg:4yFKK3Xe42I:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/kwIvli9E3gg" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/UFBs-Pp0Pp8/best-practices-for-creating-websites-in-iis-6-0.aspx"&gt;Best practices for creating websites in IIS 6.0&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Saturday, October 04, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;Every time I create an IIS website, I do some steps, which I consider as best practice for creating any IIS website for better performance, maintainability, and scalability. Here&amp;#39; re the things I do: &lt;br /&gt;Create a separate application pool for each web application &lt;br /&gt;I always create separate app pool for each web app because I can select different schedule for app pool recycle. Some heavy traffic websites have long recycle schedule where low traffic websites have short recycle schedule to save memory. Moreover, I can choose different number of processes served by the app pool. Applications that are made for web garden mode can benefit from multiple process where applications that use in-process session, in memory cache needs to have single process serving the app pool. Hosting all my application under the DefaultAppPool does not give me the flexibility to control these per site. &lt;br /&gt;The more app pool you create, the more ASP.NET threads you make available to your application. Each w3wp.exe has it&amp;#39;s own thread pool. So, if some application is congesting particular w3wp.exe process, other applications can run happily on their separate w3wp.exe instance, running under separate app pool. Each app pool hosts its own w3wp.exe instance. &lt;br /&gt;So, my rule of thumb: Always create new app pool for new web applications and name the app pool based on the site&amp;#39;s domain name or some internal name that makes sense. For example, if you are creating a new website alzabir.com, name the app pool alzabir.com to easily identify it. &lt;br /&gt;Another best practice: Disable the DefaultAppPool so that you don&amp;#39;t mistakenly keep adding sites to DefaultAppPool. &lt;br /&gt;  &lt;br /&gt;First you create a new application pool. Then you create a new Website or Virtual Directory, go to Properties -&amp;gt; Home Directory tab -&amp;gt; Select the new app pool. &lt;br /&gt; &lt;br /&gt;Customize Website properties for performance, scalability and maintainability &lt;br /&gt;First you map the right host headers to your website. In order to do this, go to WebSite tab and click on &amp;quot;Advanced&amp;quot; button. Add mapping for both domain.com and www.domain.com. Most of the time, people forget to map the domain.com. Thus many visitors skip typing the www prefix and get no page served. &lt;br /&gt; &lt;br /&gt;Next turn on some log entries: &lt;br /&gt; &lt;br /&gt;These are very handy for analysis. If you want to measure your bandwidth consumption for specific sites, you need the Bytes Sent. If you want to measure the execution time of different pages and find out the slow running pages, you need Time Taken. If you want to measure unique and returning visitors, you need the Cookie. If you need to know who is sending you most traffic - search engines or some websites, you need the Referer. Once these entries are turned on, you can use variety of Log Analysis tools to do the analysis. For example, open source AWStats.  &lt;br /&gt;But if you are using Google Analytics or something else, you should have these turned off, especially the Cookie and Referer because they take quite some space on the log. If...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=UFBs-Pp0Pp8:Rfar1v6i7ho:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=UFBs-Pp0Pp8:Rfar1v6i7ho:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=UFBs-Pp0Pp8:Rfar1v6i7ho:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/UFBs-Pp0Pp8" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/x8AlDh3RxXY/create-asp-net-mvc-controllers-under-namespace-and-specific-url.aspx"&gt;Create ASP.NET MVC Controllers under Namespace and specific URL&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Saturday, October 04, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;When you have a lot of controllers, you need to organize them under Namespaces. Also, it is better to put controllers under subfolders in order to organize them properly and have some meaningful URL for them like /Admin/User where Admin is the subfolder and User is the controller. For example, you might have a lot of controllers that are APIs exposed by your web app, not regular pages. So, you might want to put them under /API/ folder. You also want to make sure no one can access those controllers from the root url. For example, no one must call /User/GetUserList instead they must call /API/User/GetUserList &lt;br /&gt;ASP.NET MVC default routing and Controller Factory is very greedy, it ignores the subfolders inside the &amp;quot;Controllers&amp;quot; folder. There&amp;#39;s a DefaultControllerFactory class in ASP.NET MVC which traverses all controllers under the &amp;quot;Controller&amp;quot; folder and creates a cache using just the class name as the key. So, it ignores any namespace or any subfolder where you have put the controller. So, I created a derivative of the default controller factory and created a new factory that checks if the requested controller belongs to any specific namespace and whether that controller must be inside a specific subfolder. You can map /Admin folder to respond to all controllers that are under then YourWebApp.Admin namespace. Similarly, you can map /API folder to respond to all controllers that are under the YourWebApp.API namespace. None of these controllers can be accessed outside the specified URL. Here&amp;#39;s the factory that does it: &lt;br /&gt; &lt;br /&gt;This controller checks the namespace of the controller being returned by ASP.NET MVC&amp;#39;s default implementation and ensures the requested URL is the right url where controllers from the namespace can be accessed. So, this means if the controller matches MvcWebAPI.API.UserController, it ensures the URL being requested must be /MvcWebAPI/API/User. It will return null if the URL was something else like /MvcWebAPI/User or /MvcWebAPI/SomeotherFolder/User. &lt;br /&gt;Here&amp;#39;s how you use it form Global.asax: &lt;br /&gt;  &lt;br /&gt;You create a mapping for a Namespace and the subfolder it must belong to. Then you register the new Controller Factory as the default controller factory. &lt;br /&gt;Now the second catch is, the default Route for the {controller}/{action}/{id} won&amp;#39;t work for you. You need to create a specific router that starts with the subfolder name. For example, API/{controller}/{action} &lt;br /&gt;  &lt;br /&gt;Here&amp;#39; two things to notice:  The use of PathStartWith routing constraint, which I will explain soon  The last parameter which tells the route to include the API namespace for this route. Otherwise it can&amp;#39;t find the controllers in the API namespace &lt;br /&gt;So, the PathStartsWith routing constraint ensures this route gets hit only when the requested URL is under the /API/ folder. For any other URL, it returns false and thus the routing handler skips this route. &lt;br /&gt;  &lt;br /&gt;It just does a comparison on the AbsolutePath of the current request URL to...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=x8AlDh3RxXY:zjEuKozKamc:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=x8AlDh3RxXY:zjEuKozKamc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=x8AlDh3RxXY:zjEuKozKamc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/x8AlDh3RxXY" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="accentbar"&gt;&lt;span class="left"&gt;&amp;nbsp;&lt;/span&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5 News Feed&lt;span class="right"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="ClearBoth"&gt;&lt;/div&gt;</description><author>oazabir</author><pubDate>Tue, 06 Oct 2009 14:37:05 GMT</pubDate><guid isPermaLink="false">Updated Wiki: Home 20091006023705P</guid></item><item><title>Updated Wiki: Home</title><link>http://dropthings.codeplex.com/Wiki/View.aspx?title=Home&amp;version=29</link><description>&lt;div class="wikidoc"&gt;&lt;b&gt;Project Description&lt;/b&gt;&lt;br /&gt;Ajax Web Portal built on Linq, Workflow Foundation and ASP.NET AJAX. Code is in Visual Studio 2008 using .NET 3.0 and .NET 3.5.&lt;br /&gt;
&lt;h1&gt;Production site&lt;/h1&gt;&lt;a href="http://dropthings.omaralzabir.com" class="externalLink"&gt;http://dropthings.omaralzabir.com&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;For latest news and updates, visit my blog &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/omar/" class="externalLink"&gt;http://msmvps.com/blogs/omar/&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;
&lt;h1&gt;Source Code&lt;/h1&gt;&lt;a href="http://code.google.com/p/dropthings/" class="externalLink"&gt;http://code.google.com/p/dropthings/&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Book about this project&lt;/b&gt;&lt;br /&gt;&lt;img src="http://i3.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=dropthings&amp;DownloadId=27511" alt="MyBook.jpg" title="MyBook.jpg" /&gt;&lt;br /&gt;This book explains how this project has been built step by step. It also explains many advance AJAX concepts, development and production challenges for building and maintaining a high volume production website.&lt;br /&gt;&lt;br /&gt;Get it from Amazon:&lt;br /&gt;&lt;a href="http://www.amazon.com/Building-Web-2-0-Portal-ASP-NET/dp/0596510500" class="externalLink"&gt;http://www.amazon.com/Building-Web-2-0-Portal-ASP-NET/dp/0596510500&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Technologies&lt;/b&gt;
&lt;ul&gt;&lt;li&gt;ASP.NET 2.0&lt;/li&gt;
&lt;li&gt;jQuery&lt;/li&gt;
&lt;li&gt;ASP.NET AJAX (.NET 3.5)&lt;/li&gt;
&lt;li&gt;Silverlight&lt;/li&gt;
&lt;li&gt;Linq to Sql&lt;/li&gt;
&lt;li&gt;Linq to Xml&lt;/li&gt;
&lt;li&gt;Workflow Foundation (.NET 3.0)&lt;/li&gt;
&lt;li&gt;Visual Studio 2008 and SQL Server 2005&lt;/li&gt;&lt;/ul&gt;
&lt;br /&gt;&lt;b&gt;Features&lt;/b&gt;
&lt;ul&gt;&lt;li&gt;Configure widgets for specific user roles.&lt;/li&gt;
&lt;li&gt;Configure different default page setup for different roles - Managers get some widgets, Employees get different widgets and so on.&lt;/li&gt;
&lt;li&gt;Ability to define page setup for anonymous users and different page setup for logged in users.&lt;/li&gt;
&lt;li&gt;Multiple Tabs.&lt;/li&gt;
&lt;li&gt;Customizable Widget Gallery.&lt;/li&gt;
&lt;li&gt;Different column setup.&lt;/li&gt;
&lt;li&gt;Build your own widgets using Silverlight, ASP.NET or plain Javascripts.&lt;/li&gt;
&lt;li&gt;Host widgets on any page of your website&lt;/li&gt;
&lt;li&gt;Easy to integrate Dropthings to your own website e.g. http://myoffice.bt.com is built on top of Dropthings.&lt;/li&gt;
&lt;li&gt;Business Layer is entirely Workflow Foundation driven - easy to plug-in your own business logic as Activities.&lt;/li&gt;&lt;/ul&gt;
&lt;br /&gt;&lt;b&gt;Join Us&lt;/b&gt;&lt;br /&gt;If you are a seasoned ASP.NET Developer and have ASP.NET AJAX skill, come and join us to make Dropthings a feature rich Ajax Web Portal. Please email me at &amp;quot;OmarALZabir&amp;quot; at gmail dot com.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;What is an AJAX Portal&lt;/b&gt;&lt;br /&gt;A &lt;i&gt;Portal&lt;/i&gt; refers to a page that allows users to customize their own homepage by dragging and dropping &lt;i&gt;widgets&lt;/i&gt; onto the page. This approach gives users complete control over what content they see on their page, where they want to see it, and how they want to interact with it. &lt;br /&gt;&lt;br /&gt;A widget is a discrete piece on a Web page that performs a particular function and comes with its own UI and set of features. Examples of widgets include a to-do-list, an address book, a contact list, an RSS feed, or even a clock, calendar, playlist, stock ticker, weather report, traffic report, dictionary, game, or almost anything you can imagine that can be packaged up and dropped on a Web page. In a corporate environment, widgets can connect to internal systems, such as an Expense Tracker widget that interacts directly with the internal Accounting System. If you are familiar with Sharepoint Portal, then you already know about Widgets. They are called Web parts in Sharepoint’s term and also in ASP.NET 2.0. &lt;br /&gt;&lt;br /&gt;Portals are powerful RSS aggregation platform. You can put as many RSS widgets as you like on your page and get fresh content delivered to you as soon as it is published. Some Portal like Pageflakes archives RSS for a long time and thus you can go back in time and read older posts, save posts, and forward interesting articles to your friends.&lt;br /&gt;&lt;br /&gt;An Ajax-powered portal is specifically a portal that uses Ajax technologies to create richer experiences for its users. It is one step ahead of previous generation portals like My Yahoo or MSN.com, because it gives you state-of-the-art UI that behaves more like a Windows client application -- with widgets, animations, popups, client side data grids, and other effects not usually found on a non-Ajax Web portal . &lt;br /&gt;&lt;br /&gt;&lt;b&gt;How to run the project&lt;/b&gt;
&lt;ol&gt;&lt;li&gt;Download the latest source code from Google Code site &lt;a href="http://code.google.com/p/dropthings/" class="externalLink"&gt;http://code.google.com/p/dropthings/&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Follow the Readme.txt&lt;/li&gt;&lt;/ol&gt;
&lt;br /&gt;&lt;b&gt;How is ASP.NET AJAX used in this project?&lt;/b&gt;&lt;br /&gt;It is an N-tier application, with a user interface (UI) layer, a business layer, and a data access layer. I have used ASP.NET AJAX to implement the UI layer of the portal application which includes the homepage and the widgets’ UI. ASP.NET AJAX provides the framework for loading widgets onto the home page, updating widgets without doing any postbacks (via UpdatePanel), and changing page layout by dragging and dropping widgets on the page. It also provides a rich collection of Control Extenders, that add cool effects like fade in/fade out, smooth transitions, and client side animations . You can add to the rich clientside experience by providing auto-completion behavior on text boxes, asynchronous data loading via webservice  calls, and client side paging, sorting and many more.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;How is .NET 3.5 used in this project&lt;/b&gt;&lt;br /&gt;The business layer of the application is built with the Workflow Foundation  in .NET 3.0 . Major operations like a first-time user visit, a subsequent user visit, adding a new widget, and creating a new page are all orchestrated using workflow . The workflows contain all the business rules and activities needed to complete each operation. For example, the &amp;quot;New User Visit&amp;quot; workflow creates the user account, populates the user profile with default values, creates some default pages, populates them with specific widgets, etc. Such compound operations are very easy to build with Workflows , which enables you to break the complete workflow operation into smaller chunks named Activities. Each Activity does a very small amount of work. It talks to the data access layer and performs the task. The data access layer is built with .NET 3.5 , utilizing LINQ to SQL .&lt;br /&gt;The web project and the widgets make good use of .NET 3.5 by utilizing lambda expressions , LINQ  to SQL, and LINQ to XML. You will use Linq queries to work with collections and database rows. Widgets make good use of Linq to Xml in order to consume XML from external data sources.&lt;br /&gt;&lt;br /&gt;Warning: Dropthings.com is a very simple, open-source example of what can be done with AJAX and Microsoft technologies.  It is intended for educational purposes only.  Dropthings.com has absolutely nothing to do with &lt;a href="http://www.pageflakes.com" class="externalLink"&gt;http://www.pageflakes.com&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;.  But this project does a good job to show you how all the new hot technologies work together in a working web application that's production ready.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;
&lt;h1&gt;My Blog&lt;/h1&gt;---&lt;br /&gt;&lt;div class="rss"&gt;&lt;div class="accentbar"&gt;&lt;span class="left"&gt;&amp;nbsp;&lt;/span&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5 News Feed&lt;span class="right"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/i4nIiY2Tnqo/web-2-0-ajax-portal-using-jquery-asp-net-3-5-silverlight-linq-to-sql-wf-and-unity.aspx"&gt;Web 2.0 AJAX Portal using jQuery, ASP.NET 3.5, Silverlight, Linq to SQL, WF and Unity&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Thursday, April 09, 2009&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;Dropthings – my open source Web 2.0 Ajax Portal has gone through a technology overhauling. Previously it was built using ASP.NET AJAX, a little bit of Workflow Foundation and Linq to SQL. Now Dropthings boasts full jQuery front-end combined with ASP.NET AJAX UpdatePanel, Silverlight widget, full Workflow Foundation implementation on the business layer, 100% Linq to SQL Compiled Queries on the data access layer, Dependency Injection and Inversion of Control (IoC) using Microsoft Enterprise Library 4.1 and Unity. It also has a ASP.NET AJAX Web Test framework that makes it real easy to write Web Tests that simulates real user actions on AJAX web pages. This article will walk you through the challenges in getting these new technologies to work in an ASP.NET website and how performance, scalability, extensibility and maintainability has significantly improved by the new technologies. Dropthings has been licensed for commercial use by prominent companies including BT Business, Intel, Microsoft IS, Denmark Government portal for Citizens; Startups like Limead and many more. So, this is serious stuff! There’s a very cool open source implementation of Dropthings framework available at National University of Singapore portal.  &lt;br /&gt;Visit: http://dropthings.omaralzabir.com  &lt;br /&gt;  &lt;br /&gt;I have published a new article on this on CodeProject:  &lt;br /&gt;http://www.codeproject.com/KB/ajax/Web20Portal.aspx  Get the source code  &lt;br /&gt;Latest source code is hosted at Google code:  &lt;br /&gt;http://code.google.com/p/dropthings  &lt;br /&gt;There’s a CodePlex site for documentation and issue tracking:  &lt;br /&gt;http://www.codeplex.com/dropthings  &lt;br /&gt;You will need Visual Studio 2008 Team Suite with Service Pack 1 and Silverlight 2 SDK in order to run all the projects. If you have only Visual Studio 2008 Professional, then you will have to remove the Dropthings.Test project.  New features introduced  &lt;br /&gt;Dropthings new release has the following features:     Template users – you can define a user who’s pages and widgets are used as a template for new users. Whatever you put in that template user’s pages, it will be copied for every new user. Thus this is an easier way to define the default pages and widgets for new users. Similarly you can do the same for a registered user. The template users can be defined in the web.config.     Widget-to-Widget communication – Widgets can send message to each other. Widgets can subscribe to an Event Broker and exchange messages using a Pub-Sub pattern.     WidgetZone – you can create any number of zones in any shape on the page. You can have widgets laid in horizontal layout, you can have zones on different places on the page and so on. With this zone model, you are no longer limited to the Page-Column model where you could only have N vertical columns.     Role based widgets – now widgets are mapped to roles so that you can allow different users to see different widget list using ManageWidgetPersmission.aspx.     Role based page setup – you can define page setup for different roles. For...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=i4nIiY2Tnqo:mYjpzi3TiFg:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=i4nIiY2Tnqo:mYjpzi3TiFg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=i4nIiY2Tnqo:mYjpzi3TiFg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/i4nIiY2Tnqo" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/-LIRJgSGBXo/memory-leak-with-delegates-and-workflow-foundation.aspx"&gt;Memory Leak with delegates and workflow foundation&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Saturday, March 14, 2009&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;Recently after Load Testing my open source project Dropthings, I encountered a lot of memory leak. I found lots of Workflow Instances and Linq Entities were left in memory and never collected. After profiling the web application using .NET Memory Profiler, it showed the real picture:  &lt;br /&gt;  &lt;br /&gt;It shows you that instances of the several types are being created but not being removed. You see the “New” column has positive value, but the “Remove” column has 0. That means new instances are being created, but not removed. Basically the way you do Memory Profiling is, you take two snapshots. Say you take one snapshot when you first visit your website. Then you do some action on the website that results in allocation of objects. Then you take another snapshot. When you compare both snapshots, you can see how many instances of classes were created between these two snapshots and how many were removed. If they are not equal, then you have leak. Generally in web application many objects are created on every page hit and the end of the request, all those objects are supposed to be released. If they are not released, then we have a problem. But that’s the scenario for desktop applications because in a desktop application, objects can remain in memory until app is closed. But you should know best from the code which objects were supposed to go out of scope and get released.  &lt;br /&gt;For beginners, leak means objects are being allocated but not being freed because someone is holding reference to the objects. When objects leak, they remain in memory forever, until the process (or app domain) is closed. So, if you have a leaky website, your website is continuously taking up memory until it runs out of memory on the web server and thus crash. So, memory leak is a bad – it prevents you from running your product for long duration and requires frequent restart of app pool.   &lt;br /&gt;So, the above screenshot shows Workflow and Linq related classes are not being removed, and thus leaking. This means somewhere workflow instances are not being released and thus all workflow related objects are remaining. You can see the number is same 48 for all workflow related objects. This is a good indication that, almost every instance of workflow is leaked because there were total 48 workflows created and ran. Moreover it indicates we have a leak from a top Workflow instance level, not in some specific Activity or somewhere deep in the code.  &lt;br /&gt;As the workflows use Linq stuff, they held reference to the Linq stuffs and thus the Linq stuffs leaked as well. Sometimes you might be looking for why A is leaking. But you actually end up finding that since B was holding reference to A and B was leaking and thus A was leaking as well. This is sometimes tricky to figure out and you spend a lot of time looking at the wrong direction.  &lt;br /&gt;Now let me show you the buggy code:  ManualWorkflowSchedulerService manualScheduler = &lt;br /&gt;  workflowRuntime.GetService&amp;lt;ManualWorkflowSchedulerService&amp;gt;();&lt;br /&gt;&lt;br /&gt;WorkflowInstance...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=-LIRJgSGBXo:uk3bMbquKhU:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=-LIRJgSGBXo:uk3bMbquKhU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=-LIRJgSGBXo:uk3bMbquKhU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/-LIRJgSGBXo" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/dddCH2jA0Qk/optimize-asp-net-membership-stored-procedures-for-greater-speed-and-scalability.aspx"&gt;Optimize ASP.NET Membership Stored Procedures for greater speed and scalability&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Friday, March 13, 2009&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;Last year at Pageflakes, when we were getting millions of hits per day, we were having query timeout due to lock timeout and Transaction Deadlock errors. These locks were produced from aspnet_Users and aspnet_Membership tables. Since both of these tables are very high read (almost every request causes a read on these tables) and high write (every anonymous visit creates a row on aspnet_Users), there were just way too many locks created on these tables per second. SQL Counters showed thousands of locks per second being created. Moreover, we had queries that would select thousands of rows from these tables frequently and thus produced more locks for longer period, forcing other queries to timeout and thus throw errors on the website.&lt;br /&gt;&lt;br /&gt;If you have read my last blog post, you know why such locks happen. Basically every table when it grows up to hold millions of records and becomes popular goes through this trouble. It&amp;rsquo;s just a part of scalability problem that is common to database. But we rarely take prevention about it in our early design.&lt;br /&gt;&lt;br /&gt;The solution is simple, you should either have WITH (NOLOCK) or SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED before SELECT queries. Either of this will do. They tell SQL Server not to hold any lock on the table while it is reading the table. If some row is locked while the read is happening, it will just ignore that row. When you are reading a table thousand times per second, without these options, you are issuing lock on many places around the table thousand times per second. It not only makes read from table slower, but also so many lock prevents insert, update, delete from happening timely and thus queries timeout. If you have queries like &amp;ldquo;show the currently online users from last one hour based on LastActivityDate field&amp;rdquo;, that is going to issue such a wide lock that even other harmless select queries will timeout. And did I tell you that there&amp;rsquo;s no index on LastActivityDate on aspnet_Users table?&lt;br /&gt;&lt;br /&gt;Now don&amp;rsquo;t blame yourself for not putting either of these options on your every stored proc and every dynamically generated SQL from the very first day. ASP.NET developers made the same mistake. You won&amp;rsquo;t see either of these used in any of the stored procs used by ASP.NET Membership. For example, the following stored proc gets called whenever you access Profile object:&lt;br /&gt;ALTER PROCEDURE [dbo].[aspnet_Profile_GetProperties]&lt;br /&gt;    @ApplicationName      nvarchar(256),&lt;br /&gt;    @UserName             nvarchar(256),&lt;br /&gt;    @CurrentTimeUtc       datetime&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;&lt;br /&gt;    DECLARE @ApplicationId uniqueidentifier&lt;br /&gt;    SELECT  @ApplicationId = NULL&lt;br /&gt;    SELECT  @ApplicationId = ApplicationId FROM &lt;br /&gt;      dbo.aspnet_Applications WHERE LOWER(@ApplicationName) = LoweredApplicationName&lt;br /&gt;    IF (@ApplicationId IS NULL)&lt;br /&gt;        RETURN&lt;br /&gt;&lt;br /&gt;    DECLARE @UserId uniqueidentifier&lt;br /&gt;    DECLARE @LastActivityDate datetime&lt;br /&gt;    SELECT  @UserId = NULL&lt;br /&gt;&lt;br /&gt;    SELECT @UserId = UserId, @LastActivityDate = LastActivityDate&lt;br /&gt;    FROM...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=dddCH2jA0Qk:tbN1TJrDKSA:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=dddCH2jA0Qk:tbN1TJrDKSA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=dddCH2jA0Qk:tbN1TJrDKSA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/dddCH2jA0Qk" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/zpw40Zu0jms/linq-to-sql-solve-transaction-deadlock-and-query-timeout-problem-using-uncommitted-reads.aspx"&gt;Linq to SQL solve Transaction deadlock and Query timeout problem using uncommitted reads&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Saturday, March 07, 2009&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;When your database tables start accumulating thousands of rows and many users start working on the same table concurrently, SELECT queries on the tables start producing lock contentions and transaction deadlocks. This is a common problem in any high volume website. As soon as you start getting several concurrent users hitting your website that results in SELECT queries on some large table like aspnet_users table that are also being updated very frequently, you end up having one of these errors:     &lt;br /&gt;Transaction (Process ID ##) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.    &lt;br /&gt;Or,     &lt;br /&gt;Timeout Expired. The Timeout Period Elapsed Prior To Completion Of The Operation Or The Server Is Not Responding.    &lt;br /&gt;The solution to these problems are – use proper index on the table and use transaction isolation level Read Uncommitted or WITH (NOLOCK) in your SELECT queries. So, if you had a query like this:  SELECT * FORM aspnet_users &lt;br /&gt;where ApplicationID =’xxx’ AND LoweredUserName = &amp;#39;someuser&amp;#39;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You should end up having any of the above errors under high load. There are two ways to solve this:&lt;br /&gt;&lt;br /&gt;SET TRANSACTION LEVEL READ UNCOMMITTED;&lt;br /&gt;SELECT * FROM aspnet_Users &lt;br /&gt;WHERE ApplicationID =’xxx’ AND LoweredUserName = &amp;#39;someuser&amp;#39;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Or use the WITH (NOLOCK):&lt;br /&gt;&lt;br /&gt;SELECT * FROM aspnet_Users WITH (NOLOCK) &lt;br /&gt;WHERE ApplicationID =’xxx’ AND LoweredUserName = &amp;#39;someuser&amp;#39;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The reason for the errors are that since aspnet_users is a high read and high write table, during read, the table is partially locked and during write, it is also locked. So, when the locks overlap on each other from several queries and especially when there’s a query that’s trying to read a large number of rows and thus locking large number of rows, some of the queries either timeout or produce deadlocks.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Linq to Sql does not produce queries with the WITH (NOLOCK) option nor does it use READ UNCOMMITTED. So, if you are using Linq to SQL queries, you are going to end up with any of these problems on production pretty soon when your site becomes highly popular.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;For example, here’s a very simple query:&lt;br /&gt;&lt;br /&gt;using (var db = new DropthingsDataContext())&lt;br /&gt;{&lt;br /&gt;    var user = db.aspnet_Users.First();&lt;br /&gt;    var pages = user.Pages.ToList();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;DropthingsDataContext is a DataContext built from Dropthings database.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;When you attach SQL Profiler, you get this:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You see none of the queries have READ UNCOMMITTED or WITH (NOLOCK). &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The fix is to do this:&lt;br /&gt;&lt;br /&gt;using (var db = new DropthingsDataContext2())&lt;br /&gt;{&lt;br /&gt;    db.Connection.Open();&lt;br /&gt;    db.ExecuteCommand(&amp;quot;SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;&amp;quot;);&lt;br /&gt;&lt;br /&gt;    var user = db.aspnet_Users.First();&lt;br /&gt;    var pages = user.Pages.ToList();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This will result in the following profiler output&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;As you see, both queries execute within the same connection and the isolation level is set before the queries execute. So, both queries enjoy the isolation level.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now there’s a...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=zpw40Zu0jms:EGhEU2SFyWQ:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=zpw40Zu0jms:EGhEU2SFyWQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=zpw40Zu0jms:EGhEU2SFyWQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/zpw40Zu0jms" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/nOzECG83psk/strongly-typed-workflow-input-and-output-arguments.aspx"&gt;Strongly typed workflow input and output arguments&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Saturday, December 27, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;When you run a Workflow using Workflow Foundation, you pass arguments to the workflow in a Dictionary form where the type of Dictionary is Dictionary&amp;lt;string, object&amp;gt;. This means you miss the strong typing features of .NET languages. You have to know what arguments the workflow expects by looking at the Workflow public properties. Moreover, there’s no way to make arguments required. You pass parameter, expect it to run, if it throws exception, you pass more arguments, hope it works now. Similarly, if you are running workflow synchronously using ManualWorkflowSchedulerService, you expect return arguments from the Workflow immediately, but there again, you have to rely on the Dictionary key and value pair. No strong typing there as well.  &lt;br /&gt;In order to solve this, so that you could pass Workflow arguments as strongly typed classes, you can establish a format that every Workflow has only two arguments named &amp;quot;Request” and “Response” and none other. Whatever needs to be passed to the Workflow and expected out of it, must be passed via Request and must be expected via Response properties. Now the type of these arguments can be workflow specific, it can be any class with one or more parameters. This way, you could write code like this:  &lt;br /&gt;  &lt;br /&gt;The advantages of these strongly typed approach are:      Compile time validation of input parameters passed to workflow. No risk of passing unexpected object in Dictionary’s object type value.    Enforce required values by creating Request objects with non-default constructor.    Establish a fixed contract for Workflow input and output via the strongly typed Request and Response classes or interfaces.    Validate input arguments for the Workflow directly from the Request class, without going through the overhead of running a workflow.   &lt;br /&gt;If we follow this approach, we create workflows with only two DependencyProperty, one for Request and one for Response. Showing you an example from my open source project Dropthings, which uses Workflow for the entire Business Layer. Below you see the Workflow that executes when a new user visits Dropthings.com, creates a new user and setups all the pages and widgets for the user. It has only two Dependency property – Request and Response.  &lt;br /&gt;   &lt;br /&gt;The Request parameters is of type IUserVisitWorkflowRequest. So, you can pass any class as Request argument that implements the interface.   &lt;br /&gt;   &lt;br /&gt;Here I have used fancy inheritance to create Request object hierarchy. You don’t need to do that. Just remember, you can pass any class. You don’t even need to use interface for Request parameter. It can be a class directly. I use all these interfaces in order to facilitate Dependency Inversion.  &lt;br /&gt;Similarly, the Response object is also a class.  &lt;br /&gt;  &lt;br /&gt;The Response returns quite some properties. So, it’s kinda handy to wrap them all in one property.  &lt;br /&gt;So, there you have it, strongly typed Workflow arguments. You can attach properties of the Request object to any activity directly form the...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=nOzECG83psk:ZkqK3QKQmqM:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=nOzECG83psk:ZkqK3QKQmqM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=nOzECG83psk:ZkqK3QKQmqM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/nOzECG83psk" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/R5QvBFRfDKc/99-99-available-asp-net-and-sql-server-saas-production-architecture.aspx"&gt;99.99% available ASP.NET and SQL Server SaaS Production Architecture&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Wednesday, December 10, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;You have a hot ASP.NET+SQL Server product, growing at thousand users per day and you have hit the limit of your own garage hosting capability. Now that you have enough VC money in your pocket, you are planning to go out and host on some real hosting facility, maybe a colocation or managed hosting. So, you are thinking, how to design a physical architecture that will ensure performance, scalability, security and availability of your product? How can you achieve four-nine (99.99%) availability? How do you securely let your development team connect to production servers? How do you choose the right hardware for web and database server? Should you use Storage Area Network (SAN) or just local disks on RAID? How do you securely connect your office computers to production environment?&lt;br /&gt;&lt;br /&gt;Here I will answer all these queries. Let me first show you a diagram that I made for Pageflakes where we ensured we get four-nine availability. Since Pageflakes is a Level 3 SaaS, it&amp;rsquo;s absolutely important that we build a high performance, highly available product that can be used from anywhere in the world 24/7 and end-user gets quick access to their content with complete personalization and customization of content and can share it with others and to the world. So, you can take this production architecture as a very good candidate for Level 3 SaaS: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here&amp;rsquo;s a CodeProject article that explains all the ideas:&lt;br /&gt;&lt;br /&gt;99.99% available ASP.NET and SQL Server SaaS Production Architecture&lt;br /&gt;&lt;br /&gt;Hope you like it. Appreciate your vote.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=R5QvBFRfDKc:mqCjLkXCtpI:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=R5QvBFRfDKc:mqCjLkXCtpI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=R5QvBFRfDKc:mqCjLkXCtpI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/R5QvBFRfDKc" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/YXw8_xnXYOs/linq-to-sql-delete-an-entity-using-primary-key-only.aspx"&gt;Linq to SQL: Delete an entity using Primary Key only&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Thursday, October 30, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;Linq to Sql does not come with a function like .Delete(ID) which allows you to delete an entity using it&amp;rsquo;s primary key. You have to first get the object that you want to delete and then call .DeleteOnSubmit(obj) to queue it for delete. Then you have to call DataContext.SubmitChanges() to play the delete queries on database. So, how to delete object without getting them from database and avoid database roundtrip?&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;You can call this function using DeleteByPK&amp;lt;Employee, int&amp;gt;(10, dataContext);&lt;br /&gt;&lt;br /&gt;First type is the entity type and second one is the type of the primary key. If your object&amp;rsquo;s primary key is a Guid field, specify Guid instead of int.&lt;br /&gt;&lt;br /&gt;How it works:&lt;br /&gt;&lt;br /&gt;It figures out the table name and the primary key field name from the entity &lt;br /&gt;Then it uses the table name and primary key field name to build a DELETE query &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Figuring out the table name and primary key field name is a bit hard. There&amp;rsquo;s some reflection involved. The GetTableDef&amp;lt;TSource&amp;gt;() returns the table name and primary key field name for an entity.&lt;br /&gt;&lt;br /&gt;Every Linq Entity class is decorated with a Table attribute that has the table name:&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Then the primary key field is decorated with a Column attribute with IsPrimaryKey = true.&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;So, using reflection we can figure out the table name and the primary key property and the field name.&lt;br /&gt;&lt;br /&gt;Here&amp;rsquo;s the code that does it:&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Before you scream &amp;ldquo;Reflection is SLOW!!!!&amp;rdquo; the definition is cached. So, reflection is used only once per appDomain per entity. Subsequent call is just a dictionary lookup away, which is as fast as it can get.&lt;br /&gt;&lt;br /&gt;You can also delete a collection of object without ever getting any one of them. The the following function to delete a whole bunch of objects:&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;The code is available here:&lt;br /&gt;&lt;br /&gt;http://code.msdn.microsoft.com/DeleteEntitiesLinq&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=YXw8_xnXYOs:SIiDuFmSUOc:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=YXw8_xnXYOs:SIiDuFmSUOc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=YXw8_xnXYOs:SIiDuFmSUOc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/YXw8_xnXYOs" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/fvJttJrO18w/how-to-convince-developers-and-management-to-use-automated-unit-test-for-ajax-websites.aspx"&gt;How to convince developers and management to use automated unit test for AJAX websites&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Monday, October 27, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;Everyone agrees that unit testing is a good thing, we should all write unit tests. We read articles and blogs to keep us up-to-date on what’s going on in the unit test world so that we can sound cool talking to peers at lunch. But when we really sit down and try to write unit tests ourselves – “Naaah, this is waste of time, let’s ask my QA to test it; that’s much more reliable and guaranteed way to test this. What’s the point testing these functions when there are so many other functions that we should unit test first?” Had such moment yourself or with someone else? Read on.  &lt;br /&gt;I had a conversation with our development lead Mike (using a highly generic name since my last post caused some trouble), who runs “the show” in our engineering team. As usual there was reservation in introducing unit test to regular development schedule. Mike also had valid points about lack of powerful tools for doing unit test on AJAX websites. He also had confusion on ‘what’ and ‘how’ to unit test our code so that we aren’t just testing database failures but real user actions that executes both business and rendering logics. So, the discussion has a lot of useful information, that will help you take the right decision when you want to sell unit test to your ASP.NET and/or AJAX development team and finally to higher management so that you can buy enough time for the effort.  &lt;br /&gt;Friday, Jan 2007 – hallway      &lt;br /&gt;Omar: Hey Mike, we need to start doing unit testing at least on our web services. We are wasting way too much time on manual QA. Since we are an AJAX shop, unit testing all our web services should give us pretty well coverage.   &lt;br /&gt;Mike: Sure, that sounds fun. I will do some feasibility check and see how can we chip this in into our next sprint.  &lt;br /&gt;Friday, Feb 2007 – washroom&amp;#160; &lt;br /&gt;Omar: Hey Mike, let’s start doing unit tests. I haven’t seen any tests last month. Can we start from this sprint?  &lt;br /&gt;Mike: Sure, we can surely start from this sprint. Let me find out which tool is the right one for us.  &lt;br /&gt;Friday, March 2007 – meeting room     &lt;br /&gt;Omar: Hey Mike, haven’t seen any unit tests in the solution so far. Let’s seriously start writing unit tests. Did you make any plan how you want to start unit testing the webservices?  &lt;br /&gt;Mike: Yeah, I did some digging around and found some tools. But most of them are for non-AJAX sites where you can programmatically hit a URL or programmatically do HTTP POST on a URL. You can also record button clicks and form posts from the browser. There’s Visual Studio’s Web Test, which does pretty good job recording regular ASP.NET site, but poor on AJAX sites. Moreover, you need to buy Team Suite edition to get that Web Test feature. Besides, recording tests and playing them back really does not help us because all those tests contain hard coded data. We can’t repeat a particular step many times with random data, at least not using any off-the-shelf tools. We need to test things carefully and systematically using random data set and sometimes use...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=fvJttJrO18w:kiUnSE-1Xxg:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=fvJttJrO18w:kiUnSE-1Xxg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=fvJttJrO18w:kiUnSE-1Xxg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/fvJttJrO18w" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/Nc-bH9JpSO0/solving-common-problems-with-compiled-queries-in-linq-to-sql-for-high-demand-asp-net-websites.aspx"&gt;Solving common problems with Compiled Queries in Linq to Sql for high demand ASP.NET websites&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Monday, October 27, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;If you are using Linq to SQL, instead of writing regular Linq Queries, you should be using Compiled Queries. if you are building an ASP.NET web application that&amp;rsquo;s going to get thousands of hits per hour, the execution overhead of Linq queries is going to consume too much CPU and make your site slow. There&amp;rsquo;s a runtime cost associated with each and every Linq Query you write. The queries are parsed and converted to a nice SQL Statement on *every* hit. It&amp;rsquo;s not done at compile time because there&amp;rsquo;s no way to figure out what you might be sending as the parameters in the queries during runtime. So, if you have common Linq to Sql statements like the following one throughout your growing web application, you are soon going to have scalability nightmares:&lt;br /&gt;&lt;br /&gt;var query = from widget in dc.Widgets&lt;br /&gt;                where widget.ID == id &amp;amp;&amp;amp; widget.PageID == pageId&lt;br /&gt;                select widget;&lt;br /&gt;&lt;br /&gt;var widget = query.SingleOrDefault();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There&amp;rsquo;s a nice blog post by JD Conley that shows how evil Linq to Sql queries are:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You see how many times SqlVisitor.Visit is called to convert a Linq Query to its SQL representation? The runtime cost to convert a Linq query to its SQL Command representation is just way too high.&lt;br /&gt;&lt;br /&gt;Rico Mariani has a very informative performance comparison of regular Linq queries vs Compiled Linq queries performance:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Compiled Query wins on every case.&lt;br /&gt;&lt;br /&gt;So, now you know about the benefits of compiled queries. If you are building ASP.NET web application that is going to get high traffic and you have a lot of Linq to Sql queries throughout your project, you have to go for compiled queries. Compiled Queries are built for this specific scenario. &lt;br /&gt;&lt;br /&gt;In this article, I will show you some steps to convert regular Linq to Sql queries to their Compiled representation and how to avoid the dreaded exception &amp;ldquo;Compiled queries across DataContexts with different LoadOptions not supported.&amp;rdquo;&lt;br /&gt;&lt;br /&gt;Here are some step by step instruction on converting a Linq to Sql query to its compiled form:&lt;br /&gt;&lt;br /&gt;First we need to find out all the external decision factors in a query. It mostly means parameters in the WHERE clause. Say, we are trying to get a user from aspnet_users table using Username and Application ID:&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Here, we have two external decision factor &amp;ndash; one is the Username and another is the Application ID. So, first think this way, if you were to wrap this query in a function that will just return this query as it is, what would you do? You would create a function that takes the DataContext (dc named here), then two parameters named userName and applicationID, right?&lt;br /&gt;&lt;br /&gt;So, be it. We create one function that returns just this query:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Next step is to replace this function with a Func&amp;lt;&amp;gt; representation that returns the query. This is the hard part. If you haven&amp;rsquo;t dealt with Func&amp;lt;&amp;gt; and Lambda expression before, then I suggest you read this and this and then continue.&lt;br /&gt;&lt;br /&gt;So, here&amp;rsquo;s the delegate...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Nc-bH9JpSO0:QPjYis-Ap2U:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Nc-bH9JpSO0:QPjYis-Ap2U:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Nc-bH9JpSO0:QPjYis-Ap2U:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/Nc-bH9JpSO0" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/vBOI7L_fwcw/tips-and-tricks-to-rescue-overdue-projects.aspx"&gt;Tips and tricks to rescue overdue projects&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Tuesday, October 21, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;One of my friends, who runs his own offshore development shop, was having nightmare situation with one of his customers. He&amp;#39;s way overdue on a release, the customer is screaming everyday, he&amp;#39;s paying his team from his own pocket, customer is sending an ever increasing list of changes and so on. Here&amp;#39;s how we discussed some ideas to get out of such a situation and make sure it does not repeat in future:   &lt;br /&gt;Kabir: Hey, can you help me? My customer is making us work for free for extra two months to fix bugs from our last delivery. We did what he said. But after he saw the output, he came up with hundred changes, which he somehow presents as bugs or missing features and make them look like they are all our fault and making us work for last two months for free. He is sending new changes every week. We have no idea when we will complete the iteration.   &lt;br /&gt;Omar: I see. Did you get a signed list of requirements from customer before you started the development?   &lt;br /&gt;Kabir: Of course, I did. He sent us a word document explaining what he wants and we sent him a task breakup with hour estimates and total duration of three months. Now after three months when we showed him the product, he said, it&amp;#39;s no where close to what he had expected. Then he sent a gigantic list of things to change.   &lt;br /&gt;Omar: All of those are bugs?   &lt;br /&gt;Kabir: Of course not. Most of them are new features.   &lt;br /&gt;Omar: Then why don&amp;#39;t you say those are new features? You have the original word document to prove. Just ask him to show where in the word document did he said X needs to be done?   &lt;br /&gt;Kabir: Well..., he&amp;#39;s tricky. He somehow makes things look like it is obvious that X needs to be done and he&amp;#39;s not going to accept a requirement as done until X is done. For example, he said there must be a complete login form in the homepage. So, we did a typical login form with user name, password and OK, Cancel button. Now he says where&amp;#39;s the email verification thing? We said, you did not ask for it. He said, &amp;quot;this is obvious, every login form has a forgot password and email verification; I said *complete* login form, not half-baked login form&amp;quot;. So, you see, we can&amp;#39;t really argue to keep our image. Then, we did the login form exactly how he said. Now he says, where the client side validations of proper email address, username length, password confirmation? We said, you never asked for it! He says, &amp;quot;come on, every single website nowadays has AJAX enabled client side validation, do I have to tell you every single thing? Aren&amp;#39;t you guys smart enough to figure this out? You are already doing this for the third time, can&amp;#39;t you do it really well this time?&amp;quot;   &lt;br /&gt;Omar: OK, stop. I see what&amp;#39;s your problem. Some customer will always try to make you work more for less money. They will try to squeeze out every bit of development they can for their bucks. So, you have to be extra careful on how much you commit to them and make sure they cannot chip in more...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=vBOI7L_fwcw:4pKN0lLk8FM:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=vBOI7L_fwcw:4pKN0lLk8FM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=vBOI7L_fwcw:4pKN0lLk8FM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/vBOI7L_fwcw" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/Fb5wVsfQIf4/an-agile-developer-s-workflow-when-scrum-is-used.aspx"&gt;An Agile Developer's workflow when SCRUM is used&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Saturday, October 11, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;If you are planning to start SCRUM at your company, you might need to train developers and QA to get into the mindset of an Agile developer. SCRUM is only successful when the developers and QA get into the habit of following the principles of SCRUM by heart. So, sometimes you need to offer training or do trial sprints to give some room to your developers how to get used to the working fashion of SCRUM. Giving them a handy workflow diagram that shows how they should work helps soothe the steep learning curve required for non-super star developers. I made such a workflow while I was teaching SCRUM at my friend&amp;#39;s company. The following diagram was printed and hung over the desk of each and every developer to help them grasp the culture of SCRUM quickly:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;We use Flyspray for issue tracking, so you will see the mention of it frequently. &lt;br /&gt;&lt;br /&gt;You will see the step to &amp;quot;Update Sprint backlog with remaining hours&amp;quot; is missing. This is done kinda verbally and scrum master (sometimes same person who is the product owner) keeps track of it.&lt;br /&gt;&lt;br /&gt;Hope you find this useful.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Fb5wVsfQIf4:nPzXbpWOXEA:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Fb5wVsfQIf4:nPzXbpWOXEA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Fb5wVsfQIf4:nPzXbpWOXEA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/Fb5wVsfQIf4" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/gcjuL_ndnOA/asp-net-website-continuous-integration-deployment-using-cruisecontrol-net-subversion-msbuild-and-robocopy.aspx"&gt;ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Monday, October 06, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;You can setup continuous integration and automated deployment for your web application using CruiseControl.NET, Subversion, MSBuild and Robocopy. I will show you how you can automatically build the entire solution, email build report to developers and QA, deploy latest code in IIS all using CruiseControl.NET every N minutes. &lt;br /&gt;&lt;br /&gt;First get the following:&lt;br /&gt;&lt;br /&gt;CruiseControl.NET  &lt;br /&gt;Subversion (install the command line tools and add the Subversion bin path to PATH environment variable)  &lt;br /&gt;Robocopy (Windows Vista/2008 has it built-in, here&amp;#39;s the link for Windows 2003)  &lt;br /&gt;Install .NET Framework. You need it for MSBuild. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You will learn how I have configured Continuous Integration and Deployment for my open source AJAX Portal project www.Dropthings.com. The code is hosted at CodePlex. When some developer makes a commit, CruiseControl downloads the latest code, builds the entire solution, emails build report and then deploys the latest web site to IIS 6.0.&lt;br /&gt;&lt;br /&gt;After installing CruiseControl.NET, go to Programs -&amp;gt; Cruise Control -&amp;gt; CruiseControl.NET Config.&lt;br /&gt;&lt;br /&gt;Now keep copying and pasting the following XML blocks and make sure you understand each block and make necessary changes:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   1: &amp;lt;cruisecontrol&amp;gt;&lt;br /&gt;   2:     &amp;lt;project name=&amp;quot;Dropthings&amp;quot; queue=&amp;quot;DropthingsQueue&amp;quot; queuePriority=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;   3:         &amp;lt;!-- &lt;br /&gt;   4:         Path to the trunk folder where the full solution starts from. This is where&lt;br /&gt;   5:         subversion checkout and incremental update is performed &lt;br /&gt;   6:         --&amp;gt;&lt;br /&gt;   7:         &amp;lt;workingDirectory&amp;gt;d:\cc\dropthings\code\trunk\&amp;lt;/workingDirectory&amp;gt;&lt;br /&gt;   8:         &amp;lt;!-- Some path where CCNet writes its logs and stuffs. It can be outside the log folder --&amp;gt;&lt;br /&gt;   9:         &amp;lt;artifactDirectory&amp;gt;d:\cc\dropthings\artifact\&amp;lt;/artifactDirectory&amp;gt;&lt;br /&gt;  10:         &amp;lt;category&amp;gt;Dropthings&amp;lt;/category&amp;gt;&lt;br /&gt;  11:         &amp;lt;!-- CCNet installs a web dashboard. Enter the URL of that dashboard here --&amp;gt;&lt;br /&gt;  12:         &amp;lt;webURL&amp;gt;http://localhost/ccnet/&amp;lt;/webURL&amp;gt;&lt;br /&gt;  13:         &amp;lt;modificationDelaySeconds&amp;gt;60&amp;lt;/modificationDelaySeconds&amp;gt;&lt;br /&gt;  14:         &amp;lt;labeller type=&amp;quot;defaultlabeller&amp;quot;&amp;gt;&lt;br /&gt;  15:             &amp;lt;prefix&amp;gt;0.1.&amp;lt;/prefix&amp;gt;&lt;br /&gt;  16:             &amp;lt;incrementOnFailure&amp;gt;true&amp;lt;/incrementOnFailure&amp;gt;&lt;br /&gt;  17:             &amp;lt;labelFormat&amp;gt;000&amp;lt;/labelFormat&amp;gt;&lt;br /&gt;  18:         &amp;lt;/labeller&amp;gt;&lt;br /&gt;  19:         &amp;lt;state type=&amp;quot;state&amp;quot; directory=&amp;quot;State&amp;quot; /&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;First change the working directory. It needs to be the path of the folder where you will have the solution downloaded. I generally create folder structure like this:&lt;br /&gt;&lt;br /&gt;D:\CC - Root for all CC.NET enabled projects &lt;br /&gt;&lt;br /&gt;\ProjectName - Root project folder &lt;br /&gt;&lt;br /&gt;\Code - Code folder where code is downloaded from subversion &lt;br /&gt;&lt;br /&gt;\Artifact - CC.NET generates a lot of stuff. All goes here.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; Next comes the Subversion integration block:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   1: &amp;lt;sourcecontrol type=&amp;quot;svn&amp;quot;&amp;gt;&lt;br /&gt;   2:    ...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=gcjuL_ndnOA:0FVtpVe4JaA:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=gcjuL_ndnOA:0FVtpVe4JaA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=gcjuL_ndnOA:0FVtpVe4JaA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/gcjuL_ndnOA" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/kwIvli9E3gg/using-multiple-broadband-connections-without-using-any-special-router-or-software.aspx"&gt;Using multiple broadband connections without using any special router or software&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Sunday, October 05, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;I have two broadband connections. One cheap connection, which I mostly use for browsing and downloading. Another very expensive connection that I use for voice chat, remote desktop connection etc. Now, using these two connections at the same time required two computers before. But I figured out a way to use both connections at the same time using the same computer. Here&amp;#39;s how: &lt;br /&gt;Connect the cheap internet connection that is used mostly for non-critical purpose like downloading, browsing to a wireless router. &lt;br /&gt;Connect the expensive connection that is used for network latency sensitive work like Voice Conference, Remote Desktop directly via LAN. &lt;br /&gt;When you want to establish a critical connection like starting voice conf app (Skype) or remote desktop client, momentarily disconnect the wireless. This will make your LAN connection the only available internet. So, all the new connections will be established over the LAN. Now you can start Skype and initiate a voice conference or use Remote Desktop client and connect to a computer. The connection will be established over LAN. &lt;br /&gt;Now turn on wireless. Wireless will now become the first preference for Windows to go to internet. So, now you can start Outlook, browser etc and they will be using the wireless internet connection. During this time, Skype and Terminal Client is still connected over the LAN connection. As they use persisted connection, they keep using the LAN connection and do not switch to the wireless.  &lt;br /&gt;This way you get to use two broadband connections simultaneously. &lt;br /&gt;&amp;nbsp;  &lt;br /&gt;Here you see I have data transfer going on through two different connection. The bottom one is the LAN which is maintaining a continuous voice data stream. The upper one is the wireless connection that sometimes consumes bandwidth when I browse. &lt;br /&gt;  &lt;br /&gt;Using Sysinternal&amp;#39;s TCPView, I can see some connection is going through LAN and some through Belkin router. The selected ones - the terminal client and the MSN Messenger is using LAN where the Internet Explorer and Outlook is working over Wireless connection. &lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=kwIvli9E3gg:4yFKK3Xe42I:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=kwIvli9E3gg:4yFKK3Xe42I:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=kwIvli9E3gg:4yFKK3Xe42I:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/kwIvli9E3gg" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/UFBs-Pp0Pp8/best-practices-for-creating-websites-in-iis-6-0.aspx"&gt;Best practices for creating websites in IIS 6.0&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Saturday, October 04, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;Every time I create an IIS website, I do some steps, which I consider as best practice for creating any IIS website for better performance, maintainability, and scalability. Here&amp;#39; re the things I do: &lt;br /&gt;Create a separate application pool for each web application &lt;br /&gt;I always create separate app pool for each web app because I can select different schedule for app pool recycle. Some heavy traffic websites have long recycle schedule where low traffic websites have short recycle schedule to save memory. Moreover, I can choose different number of processes served by the app pool. Applications that are made for web garden mode can benefit from multiple process where applications that use in-process session, in memory cache needs to have single process serving the app pool. Hosting all my application under the DefaultAppPool does not give me the flexibility to control these per site. &lt;br /&gt;The more app pool you create, the more ASP.NET threads you make available to your application. Each w3wp.exe has it&amp;#39;s own thread pool. So, if some application is congesting particular w3wp.exe process, other applications can run happily on their separate w3wp.exe instance, running under separate app pool. Each app pool hosts its own w3wp.exe instance. &lt;br /&gt;So, my rule of thumb: Always create new app pool for new web applications and name the app pool based on the site&amp;#39;s domain name or some internal name that makes sense. For example, if you are creating a new website alzabir.com, name the app pool alzabir.com to easily identify it. &lt;br /&gt;Another best practice: Disable the DefaultAppPool so that you don&amp;#39;t mistakenly keep adding sites to DefaultAppPool. &lt;br /&gt;  &lt;br /&gt;First you create a new application pool. Then you create a new Website or Virtual Directory, go to Properties -&amp;gt; Home Directory tab -&amp;gt; Select the new app pool. &lt;br /&gt; &lt;br /&gt;Customize Website properties for performance, scalability and maintainability &lt;br /&gt;First you map the right host headers to your website. In order to do this, go to WebSite tab and click on &amp;quot;Advanced&amp;quot; button. Add mapping for both domain.com and www.domain.com. Most of the time, people forget to map the domain.com. Thus many visitors skip typing the www prefix and get no page served. &lt;br /&gt; &lt;br /&gt;Next turn on some log entries: &lt;br /&gt; &lt;br /&gt;These are very handy for analysis. If you want to measure your bandwidth consumption for specific sites, you need the Bytes Sent. If you want to measure the execution time of different pages and find out the slow running pages, you need Time Taken. If you want to measure unique and returning visitors, you need the Cookie. If you need to know who is sending you most traffic - search engines or some websites, you need the Referer. Once these entries are turned on, you can use variety of Log Analysis tools to do the analysis. For example, open source AWStats.  &lt;br /&gt;But if you are using Google Analytics or something else, you should have these turned off, especially the Cookie and Referer because they take quite some space on the log. If...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=UFBs-Pp0Pp8:Rfar1v6i7ho:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=UFBs-Pp0Pp8:Rfar1v6i7ho:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=UFBs-Pp0Pp8:Rfar1v6i7ho:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/UFBs-Pp0Pp8" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/x8AlDh3RxXY/create-asp-net-mvc-controllers-under-namespace-and-specific-url.aspx"&gt;Create ASP.NET MVC Controllers under Namespace and specific URL&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Saturday, October 04, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;When you have a lot of controllers, you need to organize them under Namespaces. Also, it is better to put controllers under subfolders in order to organize them properly and have some meaningful URL for them like /Admin/User where Admin is the subfolder and User is the controller. For example, you might have a lot of controllers that are APIs exposed by your web app, not regular pages. So, you might want to put them under /API/ folder. You also want to make sure no one can access those controllers from the root url. For example, no one must call /User/GetUserList instead they must call /API/User/GetUserList &lt;br /&gt;ASP.NET MVC default routing and Controller Factory is very greedy, it ignores the subfolders inside the &amp;quot;Controllers&amp;quot; folder. There&amp;#39;s a DefaultControllerFactory class in ASP.NET MVC which traverses all controllers under the &amp;quot;Controller&amp;quot; folder and creates a cache using just the class name as the key. So, it ignores any namespace or any subfolder where you have put the controller. So, I created a derivative of the default controller factory and created a new factory that checks if the requested controller belongs to any specific namespace and whether that controller must be inside a specific subfolder. You can map /Admin folder to respond to all controllers that are under then YourWebApp.Admin namespace. Similarly, you can map /API folder to respond to all controllers that are under the YourWebApp.API namespace. None of these controllers can be accessed outside the specified URL. Here&amp;#39;s the factory that does it: &lt;br /&gt; &lt;br /&gt;This controller checks the namespace of the controller being returned by ASP.NET MVC&amp;#39;s default implementation and ensures the requested URL is the right url where controllers from the namespace can be accessed. So, this means if the controller matches MvcWebAPI.API.UserController, it ensures the URL being requested must be /MvcWebAPI/API/User. It will return null if the URL was something else like /MvcWebAPI/User or /MvcWebAPI/SomeotherFolder/User. &lt;br /&gt;Here&amp;#39;s how you use it form Global.asax: &lt;br /&gt;  &lt;br /&gt;You create a mapping for a Namespace and the subfolder it must belong to. Then you register the new Controller Factory as the default controller factory. &lt;br /&gt;Now the second catch is, the default Route for the {controller}/{action}/{id} won&amp;#39;t work for you. You need to create a specific router that starts with the subfolder name. For example, API/{controller}/{action} &lt;br /&gt;  &lt;br /&gt;Here&amp;#39; two things to notice:  The use of PathStartWith routing constraint, which I will explain soon  The last parameter which tells the route to include the API namespace for this route. Otherwise it can&amp;#39;t find the controllers in the API namespace &lt;br /&gt;So, the PathStartsWith routing constraint ensures this route gets hit only when the requested URL is under the /API/ folder. For any other URL, it returns false and thus the routing handler skips this route. &lt;br /&gt;  &lt;br /&gt;It just does a comparison on the AbsolutePath of the current request URL to...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=x8AlDh3RxXY:zjEuKozKamc:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=x8AlDh3RxXY:zjEuKozKamc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=x8AlDh3RxXY:zjEuKozKamc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/x8AlDh3RxXY" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/n0CtjdX0MpY/create-rest-api-using-asp-net-mvc-that-speaks-both-json-and-plain-xml.aspx"&gt;Create REST API using ASP.NET MVC that speaks both Json and plain Xml&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Friday, October 03, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;ASP.NET MVC Controllers can directly return objects and collections, without rendering a view, which makes it quite appealing for creating REST like API. The nice extensionless Url provided by MVC makes it handy to build REST services, which means you can create APIs with smart Url like &amp;quot;something.com/API/User/GetUserList&amp;quot; &lt;br /&gt;There are some challenges to solve in order to expose REST API:  Based on who is calling your API, you need to be able to speak both Json and plain old Xml (POX). If the call comes from an AJAX front-end, you need to return objects serialized as Json. If it&amp;#39;s coming from some other client, say a PHP website, you need to return plain Xml.  Similarly you need to be able to understand REST, Json and plain Xml calls. Someone can hit you using REST url, someone can post a Json payload or someone can post Xml payload. &lt;br /&gt;I have created an ObjectResult class which takes an object and generates Xml or Json output automatically looking at the Content-Type header of HttpRequest. AJAX calls send Content-Type=application/json. So, it generates Json as response in that case, but when Content-Type is something else, it does simple Xml Serialzation.  &lt;br /&gt; &lt;br /&gt;Here&amp;#39;s the ObjectResult that you can use from Controllers to return objects and it takes care of proper serialization method. Above shows the Json serialization, which is quite simple. XmlSerialization is a bit complex though: &lt;br /&gt; Things to note here:  You have to force UTF8 encoding. Otherwise it produces UTF16 output.  XML Declaration is skipped because that&amp;#39;s not quite necessary. Wastes bandwidth. If you need it, turn it on.  I have turned on indenting for better readability. You can turn it off to save bandwidth. &lt;br /&gt;Some of you might be boiling inside looking at my obscure coding style. I love this style! I am spoiled by jQuery. I wish there was a cQuery. I actually started writing one, but it never saw day light just like my hundred other open source attempts. &lt;br /&gt;Now back to Object Serialization, we got the serialization done. Now you can return objects from Controller easily: &lt;br /&gt;  &lt;br /&gt;You can use the test web project to call these methods and see the result: &lt;br /&gt;  &lt;br /&gt;So far you have seen simple object and list serialization. A best practice is to return a common result object that has some status, message and then the real payload. It&amp;#39;s handy when you only need to return some error but no object or list. I use a common Result object that has three properties - ErrorCode (0 by default means success), Message (a string data type) and Data which is the real object. &lt;br /&gt;  &lt;br /&gt;When you want to return only a result with error message, you can do this: &lt;br /&gt;  &lt;br /&gt;This produces a result like this: &lt;br /&gt;  &lt;br /&gt;No payload here. So, the return format is always consistent. Those who are consuming service can write a common Xml or Json parsing code to consume both success and failure response. Those who are building API for their website, I humbly request you to return consistent response for both success and...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=n0CtjdX0MpY:Bl6iaCPqcq4:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=n0CtjdX0MpY:Bl6iaCPqcq4:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=n0CtjdX0MpY:Bl6iaCPqcq4:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=n0CtjdX0MpY:Bl6iaCPqcq4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=n0CtjdX0MpY:Bl6iaCPqcq4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=n0CtjdX0MpY:Bl6iaCPqcq4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=n0CtjdX0MpY:Bl6iaCPqcq4:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=n0CtjdX0MpY:Bl6iaCPqcq4:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=n0CtjdX0MpY:Bl6iaCPqcq4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=n0CtjdX0MpY:Bl6iaCPqcq4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=n0CtjdX0MpY:Bl6iaCPqcq4:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/n0CtjdX0MpY" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/tv_cnv3oCV0/http-handler-to-combine-multiple-files-cache-and-deliver-compressed-output-for-faster-page-load.aspx"&gt;HTTP handler to combine multiple files, cache and deliver compressed output for faster page load&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Friday, August 29, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;It&amp;#39;s a good practice to use many small Javascript and CSS files instead of one large Javascript/CSS file for better code maintainability, but bad in terms of website performance. Although you should write your Javascript code in small files and break large CSS files into small chunks but when browser requests those javascript and css files, it makes one Http request per file. Every Http Request results in a network roundtrip form your browser to the server and the delay in reaching the server and coming back to the browser is called latency. So, if you have four javascripts and three css files loaded by a page, you are wasting time in seven network roundtrips. Within USA, latency is average 70ms. So, you waste 7x70 = 490ms, about half a second of delay. Outside USA, average latency is around 200ms. So, that means 1400ms of waiting. Browser cannot show the page properly until Css and Javascripts are fully loaded. So, the more latency you have, the slower page loads. &lt;br /&gt;Here&amp;#39;s a graph that shows how each request latency adds up and introduces significant delay in page loading: &lt;br /&gt;  &lt;br /&gt;You can reduce the wait time by using a CDN. Read my previous blog post about using CDN. However, a better solution is to deliver multiple files over one request using an HttpHandler that combines several files and delivers as one output. So, instead of putting many &amp;lt;script&amp;gt; or &amp;lt;link&amp;gt; tag, you just put one &amp;lt;script&amp;gt; and one &amp;lt;link&amp;gt; tag, and point them to the HttpHandler. You tell the handler which files to combine and it delivers those files in one response. This saves browser from making many requests and eliminates the latency.  &lt;br /&gt;  &lt;br /&gt;Here you can see how much improvement you get if you can combine multiple javascripts and css into one. &lt;br /&gt;In a typical web page, you will see many javascripts referenced:&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;/Content/JScript/jquery.js&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;/Content/JScript/jDate.js&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;/Content/JScript/jQuery.Core.js&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;/Content/JScript/jQuery.Delegate.js&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;/Content/JScript/jQuery.Validation.js&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;br /&gt;Instead of these individual &amp;lt;script&amp;gt; tags, you can use only one &amp;lt;script&amp;gt; tag to serve the whole set of scripts using an Http Handler:&amp;lt;script type=&amp;quot;text/javascript&amp;quot; &lt;br /&gt;    src=&amp;quot;HttpCombiner.ashx?s=jQueryScripts&amp;amp;t=text/javascript&amp;amp;v=1&amp;quot; &amp;gt;&lt;br /&gt;&amp;lt;/script&amp;gt; &lt;br /&gt;&lt;br /&gt;The Http Handler reads the file names defined in a configuration and combines all those files and delivers as one response. It delivers the response as gzip compressed to save bandwidth. Moreover, it generates proper cache header to cache the response in browser cache, so that, browser does not request it...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=tv_cnv3oCV0:S-Eph0b0y58:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=tv_cnv3oCV0:S-Eph0b0y58:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=tv_cnv3oCV0:S-Eph0b0y58:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=tv_cnv3oCV0:S-Eph0b0y58:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=tv_cnv3oCV0:S-Eph0b0y58:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=tv_cnv3oCV0:S-Eph0b0y58:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=tv_cnv3oCV0:S-Eph0b0y58:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=tv_cnv3oCV0:S-Eph0b0y58:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=tv_cnv3oCV0:S-Eph0b0y58:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=tv_cnv3oCV0:S-Eph0b0y58:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=tv_cnv3oCV0:S-Eph0b0y58:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/tv_cnv3oCV0" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/9ge7sjX9TnU/loading-static-content-in-asp-net-pages-from-different-domain-for-faster-parallel-download.aspx"&gt;Loading static content in ASP.NET pages from different domain for faster parallel download&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Saturday, August 02, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;Generally we put static content (images, css, js) of our website inside the same web project. Thus they get downloaded from the same domain like www.dropthings.com. There are three problems in this approach:  They occupy connections on the same domain www.dropthings.com and thus other important calls like Web service call do not get a chance to happen earlier as browser can only make two simultaneous connections per domain.  If you are using ASP.NET Forms Authentication, then you have that gigantic Forms Authentication cookie being sent with every single request on www.dropthings.com. This cookie gets sent for all images, CSS and JS files, which has no use for the cookie. Thus it wastes upload bandwidth and makes every request slower. Upload bandwidth is very limited for users compared to download bandwidth. Generally users with 1Mbps download speed has around 128kbps upload speed. So, adding another 100 bytes on the request for the unnecessary cookie results in delay in sending the request and thus increases your site load time and the site feels slow to respond.  It creates enormous IIS Logs as it records the cookies for each static content request. Moreover, if you are using Google Analytics to track hits to your site, it issues four big cookies that gets sent for each and every image, css and js files resulting in slower requests and even larger IIS log entries. &lt;br /&gt;Let&amp;#39;s see the first problem, browser&amp;#39;s two connection limit. See what happens when content download using two HTTP requests in parallel: &lt;br /&gt; &lt;br /&gt;This figure shows only two files are downloaded in parallel. All the hits are going to the same domain e.g. www.dropthings.com. As you see, only two call can execute at the same time. Moreover, due to browser&amp;#39;s way of handling script tags, once a script is being downloaded, browser does not download anything else until the script has downloaded and executed. &lt;br /&gt;Now, if we can download the images from different domain, which allows browser to open another two simultaneous connections, then the page loads a lot faster: &lt;br /&gt; &lt;br /&gt;You see, the total page downloads 40% faster. Here only the images are downloaded from a different domain e.g. &amp;quot;s.dropthings.com&amp;quot;, thus the calls for the script, CSS and webservices still go to main domain e.g. www.dropthings.com &lt;br /&gt;The second problem for loading static content from same domain is the gigantic forms authentication cookie or any other cookie being registered on the main domain e.g. www subdomain. Here&amp;#39;s how Pageflake&amp;#39;s website&amp;#39;s request looks like with the forms authentication cookie and Google Analytics cookies: &lt;br /&gt;  &lt;br /&gt;You see a lot of data being sent on the request header which has no use for any static content. Thus it wastes bandwidth, makes request reach server slower and produces large IIS logs. &lt;br /&gt;You can solve this problem by loading static contents from different domain as we have done it at Pageflakes by loading static contents from a different domain e.g. flakepage.com. As the...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=9ge7sjX9TnU:xXFnXhHlJ3o:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=9ge7sjX9TnU:xXFnXhHlJ3o:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=9ge7sjX9TnU:xXFnXhHlJ3o:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=9ge7sjX9TnU:xXFnXhHlJ3o:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=9ge7sjX9TnU:xXFnXhHlJ3o:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=9ge7sjX9TnU:xXFnXhHlJ3o:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=9ge7sjX9TnU:xXFnXhHlJ3o:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=9ge7sjX9TnU:xXFnXhHlJ3o:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=9ge7sjX9TnU:xXFnXhHlJ3o:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=9ge7sjX9TnU:xXFnXhHlJ3o:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=9ge7sjX9TnU:xXFnXhHlJ3o:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/9ge7sjX9TnU" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/_D-nRcajJnY/open-source-asp-net-3-5-ajax-portal-new-and-improved.aspx"&gt;Open Source ASP.NET 3.5 AJAX Portal - new and improved&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Monday, July 14, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;Last week I released a new version of Dropthings, my open source AJAX portal, that shows many fancy Web 2.0 features and showcases extensive use of ASP.NET 3.5, Workflow Foundation, C# 3.0 new language features, custom ASP.NET AJAX extenders, many performance and scalability techniques. I have written a book on these topics as well.&lt;br /&gt;&lt;br /&gt;The new version implements the following performance and scalability improvement techniques:&lt;br /&gt;&lt;br /&gt;10 ASP.NET Performance and Scalability Secrets  &lt;br /&gt;Fast ASP.NET page rendering by deferred script loading  &lt;br /&gt;Load large amount of Javascripts in batch and thus load AJAX sites a lot faster  &lt;br /&gt;Fast Streaming AJAX proxy that solves double downloading problems and continuously streams content from external domain  &lt;br /&gt;Making best use of cache for high performance website  &lt;br /&gt;On-demand UI loading on AJAX websites&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here&amp;#39;s how the new version looks:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Hope you like the new design and the performance and scalability techniques that can significantly boost your ASP.NET website&amp;#39;s quality. I highly recommend these techniques for ASP.NET websites. These are easy to implement and makes a world of difference in speed and smoothness for ASP.NET websites.&lt;br /&gt;&lt;br /&gt;I am thinking about making an ASP.NET MVC version of this portal using jQuery. Do you think it will be a hot area to explore?&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Share this post : &lt;br /&gt;  &lt;br /&gt;  &lt;br /&gt;  &lt;br /&gt;  &lt;br /&gt;  &lt;br /&gt;  &lt;br /&gt;  &lt;br /&gt;  &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=_D-nRcajJnY:X-jt_9AAMRg:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=_D-nRcajJnY:X-jt_9AAMRg:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=_D-nRcajJnY:X-jt_9AAMRg:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=_D-nRcajJnY:X-jt_9AAMRg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=_D-nRcajJnY:X-jt_9AAMRg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=_D-nRcajJnY:X-jt_9AAMRg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=_D-nRcajJnY:X-jt_9AAMRg:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=_D-nRcajJnY:X-jt_9AAMRg:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=_D-nRcajJnY:X-jt_9AAMRg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=_D-nRcajJnY:X-jt_9AAMRg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=_D-nRcajJnY:X-jt_9AAMRg:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/_D-nRcajJnY" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="entry"&gt;&lt;div class="title"&gt;&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/GQJNZFDVAkI/deploy-asp-net-mvc-on-iis-6-solve-404-compression-and-performance-problems.aspx"&gt;Deploy ASP.NET MVC on IIS 6, solve 404, compression and performance problems&lt;/a&gt;&lt;/div&gt;&lt;div class="moreinfo"&gt;&lt;span class="date"&gt;Monday, June 30, 2008&lt;/span&gt; &amp;nbsp;|&amp;nbsp; &lt;span class="source"&gt;From &lt;a target="_blank" href="http://feeds2.feedburner.com/OmarAlZabirBlog/?"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;There are several problems with ASP.NET MVC application when deployed on IIS 6.0:  Extensionless URLs give 404 unless some URL Rewrite module is used or wildcard mapping is enabled  IIS 6.0 built-in compression does not work for dynamic requests. As a result, ASP.NET pages are served uncompressed resulting in poor site load speed.  Mapping wildcard extension to ASP.NET introduces the following problems:   Slow performance as all static files get handled by ASP.NET and ASP.NET reads the file from file system on every call  Expires headers doesn&amp;#39;t work for static content as IIS does not serve them anymore. Learn about benefits of expires header from here. ASP.NET serves a fixed expires header that makes content expire in a day.  Cache-Control header does not produce max-age properly and thus caching does not work as expected. Learn about caching best practices from here.  After deploying on a domain as the root site, the homepage produces HTTP 404. Problem 1: Visiting your website&amp;#39;s homepage gives 404 when hosted on a domain &lt;br /&gt;You have done the wildcard mapping, mapped .mvc extention to ASP.NET ISAPI handler, written the route mapping for Default.aspx or default.aspx (lowercase), but still when you visit your homepage after deployment, you get: &lt;br /&gt;  &lt;br /&gt;You will find people banging their heads on the wall here:  http://forums.asp.net/t/1237051.aspx  http://forums.asp.net/t/1253599.aspx  http://forums.asp.net/p/1239943/2294813.aspx &lt;br /&gt;Solution is to capture hits going to &amp;quot;/&amp;quot; and then rewrite it to Default.aspx: &lt;br /&gt; &lt;br /&gt;You can apply this approach to any URL that ASP.NET MVC is not handling for you and it should handle. Just see the URL reported on the 404 error page and then rewrite it to a proper URL. Problem 2: IIS 6 compression is no longer working after wildcard mapping &lt;br /&gt;When you enable wildcard mapping, IIS 6 compression no longer works for extensionless URL because IIS 6 does not see any extension which is defined in IIS Metabase. You can learn about IIS 6 compression feature and how to configure it properly from my earlier post.  &lt;br /&gt;Solution is to use an HttpModule to do the compression for dynamic requests. Problem 3: ASP.NET ISAPI does not cache Static Files  &lt;br /&gt;When ASP.NET&amp;#39;s DefaultHttpHandler serves static files, it does not cache the files in-memory or in ASP.NET cache. As a result, every hit to static file results in a File read. Below is the decompiled code in DefaultHttpHandler when it handles a static file. As you see here, it makes a file read on every hit and it only set the expiration to one day in future. Moreover, it generates ETag for each file based on file&amp;#39;s modified date. For best caching efficiency, we need to get rid of that ETag, produce an expiry date on far future (like 30 days), and produce Cache-Control header which offers better control over caching. &lt;br /&gt;  &lt;br /&gt;So, we need to write a custom static file handler that will cache small files like images, Javascripts, CSS, HTML and so on in ASP.NET cache and serve the...&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;Visit my Blog for more details.&lt;div class="feedflare"&gt;&lt;br /&gt;&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=GQJNZFDVAkI:d67Tj_sZPcE:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=GQJNZFDVAkI:d67Tj_sZPcE:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=GQJNZFDVAkI:d67Tj_sZPcE:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=GQJNZFDVAkI:d67Tj_sZPcE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=GQJNZFDVAkI:d67Tj_sZPcE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=GQJNZFDVAkI:d67Tj_sZPcE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=GQJNZFDVAkI:d67Tj_sZPcE:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=GQJNZFDVAkI:d67Tj_sZPcE:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=GQJNZFDVAkI:d67Tj_sZPcE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=GQJNZFDVAkI:d67Tj_sZPcE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=GQJNZFDVAkI:d67Tj_sZPcE:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/GQJNZFDVAkI" height="1" width="1"/&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="accentbar"&gt;&lt;span class="left"&gt;&amp;nbsp;&lt;/span&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5 News Feed&lt;span class="right"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description><author>oazabir</author><pubDate>Sat, 13 Jun 2009 17:22:33 GMT</pubDate><guid isPermaLink="false">Updated Wiki: Home 20090613052233P</guid></item><item><title>Updated Wiki: Home</title><link>http://dropthings.codeplex.com/Wiki/View.aspx?title=Home&amp;version=28</link><description>&lt;div class="wikidoc"&gt;
&lt;b&gt;Project Description&lt;/b&gt;&lt;br /&gt;Ajax Web Portal built on Linq, Workflow Foundation and ASP.NET AJAX. Code is in Visual Studio 2008 using .NET 3.0 and .NET 3.5.&lt;br /&gt;&lt;b&gt;Production site&lt;/b&gt;&lt;br /&gt;&lt;a href="http://dropthings.omaralzabir.com" class="externalLink"&gt;http://dropthings.omaralzabir.com&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;For latest news and updates, visit my blog &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/omar/" class="externalLink"&gt;http://msmvps.com/blogs/omar/&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;b&gt;Source Code&lt;/b&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/dropthings/" class="externalLink"&gt;http://code.google.com/p/dropthings/&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt; &lt;br /&gt;&lt;b&gt;Book about this project&lt;/b&gt;&lt;br /&gt;&lt;img src="http://i3.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=dropthings&amp;amp;DownloadId=27511" alt="MyBook.jpg" /&gt;&lt;br /&gt;This book explains how this project has been built step by step. It also explains many advance AJAX concepts, development and production challenges for building and maintaining a high volume production website.&lt;br /&gt; &lt;br /&gt;Get it from Amazon:&lt;br /&gt;&lt;a href="http://www.amazon.com/Building-Web-2-0-Portal-ASP-NET/dp/0596510500" class="externalLink"&gt;http://www.amazon.com/Building-Web-2-0-Portal-ASP-NET/dp/0596510500&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt; &lt;br /&gt;&lt;b&gt;Technologies&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;
&lt;li&gt;ASP.NET 2.0&lt;/li&gt;&lt;li&gt;jQuery&lt;/li&gt;&lt;li&gt;ASP.NET AJAX (.NET 3.5)&lt;/li&gt;&lt;li&gt;Silverlight&lt;/li&gt;&lt;li&gt;Linq to Sql&lt;/li&gt;&lt;li&gt;Linq to Xml&lt;/li&gt;&lt;li&gt;Workflow Foundation (.NET 3.0)&lt;/li&gt;&lt;li&gt;Visual Studio 2008 and SQL Server 2005&lt;/li&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;b&gt;Features&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;
&lt;li&gt;Configure widgets for specific user roles.&lt;/li&gt;&lt;li&gt;Configure different default page setup for different roles - Managers get some widgets, Employees get different widgets and so on.&lt;/li&gt;&lt;li&gt;Ability to define page setup for anonymous users and different page setup for logged in users.&lt;/li&gt;&lt;li&gt;Multiple Tabs.&lt;/li&gt;&lt;li&gt;Customizable Widget Gallery.&lt;/li&gt;&lt;li&gt;Different column setup.&lt;/li&gt;&lt;li&gt;Build your own widgets using Silverlight, ASP.NET or plain Javascripts.&lt;/li&gt;&lt;li&gt;Host widgets on any page of your website&lt;/li&gt;&lt;li&gt;Easy to integrate Dropthings to your own website e.g. http://myoffice.bt.com is built on top of Dropthings.&lt;/li&gt;&lt;li&gt;Business Layer is entirely Workflow Foundation driven - easy to plug-in your own business logic as Activities.&lt;/li&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;b&gt;Join Us&lt;/b&gt;&lt;br /&gt;If you are a seasoned ASP.NET Developer and have ASP.NET AJAX skill, come and join us to make Dropthings a feature rich Ajax Web Portal. Please email me at &amp;quot;OmarALZabir&amp;quot; at gmail dot com.&lt;br /&gt; &lt;br /&gt;&lt;b&gt;What is an AJAX Portal&lt;/b&gt;&lt;br /&gt;A &lt;i&gt;Portal&lt;/i&gt; refers to a page that allows users to customize their own homepage by dragging and dropping &lt;i&gt;widgets&lt;/i&gt; onto the page. This approach gives users complete control over what content they see on their page, where they want to see it, and how they want to interact with it. &lt;br /&gt; &lt;br /&gt;A widget is a discrete piece on a Web page that performs a particular function and comes with its own UI and set of features. Examples of widgets include a to-do-list, an address book, a contact list, an RSS feed, or even a clock, calendar, playlist, stock ticker, weather report, traffic report, dictionary, game, or almost anything you can imagine that can be packaged up and dropped on a Web page. In a corporate environment, widgets can connect to internal systems, such as an Expense Tracker widget that interacts directly with the internal Accounting System. If you are familiar with Sharepoint Portal, then you already know about Widgets. They are called Web parts in Sharepoint’s term and also in ASP.NET 2.0. &lt;br /&gt; &lt;br /&gt;Portals are powerful RSS aggregation platform. You can put as many RSS widgets as you like on your page and get fresh content delivered to you as soon as it is published. Some Portal like Pageflakes archives RSS for a long time and thus you can go back in time and read older posts, save posts, and forward interesting articles to your friends.&lt;br /&gt; &lt;br /&gt;An Ajax-powered portal is specifically a portal that uses Ajax technologies to create richer experiences for its users. It is one step ahead of previous generation portals like My Yahoo or MSN.com, because it gives you state-of-the-art UI that behaves more like a Windows client application -- with widgets, animations, popups, client side data grids, and other effects not usually found on a non-Ajax Web portal . &lt;br /&gt; &lt;br /&gt;&lt;b&gt;How to run the project&lt;/b&gt;&lt;br /&gt;&lt;ol&gt;
&lt;li&gt;Download the latest source code from Google Code site &lt;a href="http://code.google.com/p/dropthings/" class="externalLink"&gt;http://code.google.com/p/dropthings/&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Follow the Readme.txt&lt;/li&gt;
&lt;/ol&gt; &lt;br /&gt;&lt;b&gt;How is ASP.NET AJAX used in this project?&lt;/b&gt;&lt;br /&gt;It is an N-tier application, with a user interface (UI) layer, a business layer, and a data access layer. I have used ASP.NET AJAX to implement the UI layer of the portal application which includes the homepage and the widgets’ UI. ASP.NET AJAX provides the framework for loading widgets onto the home page, updating widgets without doing any postbacks (via UpdatePanel), and changing page layout by dragging and dropping widgets on the page. It also provides a rich collection of Control Extenders, that add cool effects like fade in/fade out, smooth transitions, and client side animations . You can add to the rich clientside experience by providing auto-completion behavior on text boxes, asynchronous data loading via webservice  calls, and client side paging, sorting and many more.&lt;br /&gt; &lt;br /&gt;&lt;b&gt;How is .NET 3.5 used in this project&lt;/b&gt;&lt;br /&gt;The business layer of the application is built with the Workflow Foundation  in .NET 3.0 . Major operations like a first-time user visit, a subsequent user visit, adding a new widget, and creating a new page are all orchestrated using workflow . The workflows contain all the business rules and activities needed to complete each operation. For example, the &amp;quot;New User Visit&amp;quot; workflow creates the user account, populates the user profile with default values, creates some default pages, populates them with specific widgets, etc. Such compound operations are very easy to build with Workflows , which enables you to break the complete workflow operation into smaller chunks named Activities. Each Activity does a very small amount of work. It talks to the data access layer and performs the task. The data access layer is built with .NET 3.5 , utilizing LINQ to SQL .&lt;br /&gt;The web project and the widgets make good use of .NET 3.5 by utilizing lambda expressions , LINQ  to SQL, and LINQ to XML. You will use Linq queries to work with collections and database rows. Widgets make good use of Linq to Xml in order to consume XML from external data sources.&lt;br /&gt; &lt;br /&gt;Warning: Dropthings.com is a very simple, open-source example of what can be done with AJAX and Microsoft technologies.  It is intended for educational purposes only.  Dropthings.com has absolutely nothing to do with &lt;a href="http://www.pageflakes.com" class="externalLink"&gt;http://www.pageflakes.com&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;.  But this project does a good job to show you how all the new hot technologies work together in a working web application that's production ready.&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
My Blog
&lt;/h1&gt;---&lt;br /&gt;&lt;div class="rss"&gt;
	&lt;div class="accentbar"&gt;
		&lt;span class="left"&gt;&amp;nbsp;&lt;/span&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5 News Feed&lt;span class="right"&gt;&amp;nbsp;&lt;/span&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/i4nIiY2Tnqo/web-2-0-ajax-portal-using-jquery-asp-net-3-5-silverlight-linq-to-sql-wf-and-unity.aspx"&gt;Web 2.0 AJAX Portal using jQuery, ASP.NET 3.5, Silverlight, Linq to SQL, WF and Unity&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Wednesday, April 08, 2009&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds2.feedburner.com/OmarAlZabirBlog/?" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;Dropthings – my open source Web 2.0 Ajax Portal has gone through a technology overhauling. Previously it was built using ASP.NET AJAX, a little bit of Workflow Foundation and Linq to SQL. Now Dropthings boasts full jQuery front-end combined with ASP.NET AJAX UpdatePanel, Silverlight widget, full Workflow Foundation implementation on the business layer, 100% Linq to SQL Compiled Queries on the data access layer, Dependency Injection and Inversion of Control (IoC) using Microsoft Enterprise Library 4.1 and Unity. It also has a ASP.NET AJAX Web Test framework that makes it real easy to write Web Tests that simulates real user actions on AJAX web pages. This article will walk you through the challenges in getting these new technologies to work in an ASP.NET website and how performance, scalability, extensibility and maintainability has significantly improved by the new technologies. Dropthings has been licensed for commercial use by prominent companies including BT Business, Intel, Microsoft IS, Denmark Government portal for Citizens; Startups like Limead and many more. So, this is serious stuff! There’s a very cool open source implementation of Dropthings framework available at National University of Singapore portal.  
Visit: http://dropthings.omaralzabir.com  
  
I have published a new article on this on CodeProject:  
http://www.codeproject.com/KB/ajax/Web20Portal.aspx  Get the source code  
Latest source code is hosted at Google code:  
http://code.google.com/p/dropthings  
There’s a CodePlex site for documentation and issue tracking:  
http://www.codeplex.com/dropthings  
You will need Visual Studio 2008 Team Suite with Service Pack 1 and Silverlight 2 SDK in order to run all the projects. If you have only Visual Studio 2008 Professional, then you will have to remove the Dropthings.Test project.  New features introduced  
Dropthings new release has the following features:     Template users – you can define a user who’s pages and widgets are used as a template for new users. Whatever you put in that template user’s pages, it will be copied for every new user. Thus this is an easier way to define the default pages and widgets for new users. Similarly you can do the same for a registered user. The template users can be defined in the web.config.     Widget-to-Widget communication – Widgets can send message to each other. Widgets can subscribe to an Event Broker and exchange messages using a Pub-Sub pattern.     WidgetZone – you can create any number of zones in any shape on the page. You can have widgets laid in horizontal layout, you can have zones on different places on the page and so on. With this zone model, you are no longer limited to the Page-Column model where you could only have N vertical columns.     Role based widgets – now widgets are mapped to roles so that you can allow different users to see different widget list using ManageWidgetPersmission.aspx.     Role based page setup – you can define page setup for different roles. For...&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=i4nIiY2Tnqo:mYjpzi3TiFg:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=i4nIiY2Tnqo:mYjpzi3TiFg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=i4nIiY2Tnqo:mYjpzi3TiFg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=i4nIiY2Tnqo:mYjpzi3TiFg:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/i4nIiY2Tnqo" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/-LIRJgSGBXo/memory-leak-with-delegates-and-workflow-foundation.aspx"&gt;Memory Leak with delegates and workflow foundation&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Saturday, March 14, 2009&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds2.feedburner.com/OmarAlZabirBlog/?" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;Recently after Load Testing my open source project Dropthings, I encountered a lot of memory leak. I found lots of Workflow Instances and Linq Entities were left in memory and never collected. After profiling the web application using .NET Memory Profiler, it showed the real picture:  
  
It shows you that instances of the several types are being created but not being removed. You see the “New” column has positive value, but the “Remove” column has 0. That means new instances are being created, but not removed. Basically the way you do Memory Profiling is, you take two snapshots. Say you take one snapshot when you first visit your website. Then you do some action on the website that results in allocation of objects. Then you take another snapshot. When you compare both snapshots, you can see how many instances of classes were created between these two snapshots and how many were removed. If they are not equal, then you have leak. Generally in web application many objects are created on every page hit and the end of the request, all those objects are supposed to be released. If they are not released, then we have a problem. But that’s the scenario for desktop applications because in a desktop application, objects can remain in memory until app is closed. But you should know best from the code which objects were supposed to go out of scope and get released.  
For beginners, leak means objects are being allocated but not being freed because someone is holding reference to the objects. When objects leak, they remain in memory forever, until the process (or app domain) is closed. So, if you have a leaky website, your website is continuously taking up memory until it runs out of memory on the web server and thus crash. So, memory leak is a bad – it prevents you from running your product for long duration and requires frequent restart of app pool.   
So, the above screenshot shows Workflow and Linq related classes are not being removed, and thus leaking. This means somewhere workflow instances are not being released and thus all workflow related objects are remaining. You can see the number is same 48 for all workflow related objects. This is a good indication that, almost every instance of workflow is leaked because there were total 48 workflows created and ran. Moreover it indicates we have a leak from a top Workflow instance level, not in some specific Activity or somewhere deep in the code.  
As the workflows use Linq stuff, they held reference to the Linq stuffs and thus the Linq stuffs leaked as well. Sometimes you might be looking for why A is leaking. But you actually end up finding that since B was holding reference to A and B was leaking and thus A was leaking as well. This is sometimes tricky to figure out and you spend a lot of time looking at the wrong direction.  
Now let me show you the buggy code:  ManualWorkflowSchedulerService manualScheduler = 
  workflowRuntime.GetService&amp;lt;ManualWorkflowSchedulerService&amp;gt;();

WorkflowInstance...&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=-LIRJgSGBXo:uk3bMbquKhU:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=-LIRJgSGBXo:uk3bMbquKhU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=-LIRJgSGBXo:uk3bMbquKhU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/-LIRJgSGBXo" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/dddCH2jA0Qk/optimize-asp-net-membership-stored-procedures-for-greater-speed-and-scalability.aspx"&gt;Optimize ASP.NET Membership Stored Procedures for greater speed and scalability&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Friday, March 13, 2009&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds2.feedburner.com/OmarAlZabirBlog/?" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;Last year at Pageflakes, when we were getting millions of hits per day, we were having query timeout due to lock timeout and Transaction Deadlock errors. These locks were produced from aspnet_Users and aspnet_Membership tables. Since both of these tables are very high read (almost every request causes a read on these tables) and high write (every anonymous visit creates a row on aspnet_Users), there were just way too many locks created on these tables per second. SQL Counters showed thousands of locks per second being created. Moreover, we had queries that would select thousands of rows from these tables frequently and thus produced more locks for longer period, forcing other queries to timeout and thus throw errors on the website.

If you have read my last blog post, you know why such locks happen. Basically every table when it grows up to hold millions of records and becomes popular goes through this trouble. It&amp;rsquo;s just a part of scalability problem that is common to database. But we rarely take prevention about it in our early design.

The solution is simple, you should either have WITH (NOLOCK) or SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED before SELECT queries. Either of this will do. They tell SQL Server not to hold any lock on the table while it is reading the table. If some row is locked while the read is happening, it will just ignore that row. When you are reading a table thousand times per second, without these options, you are issuing lock on many places around the table thousand times per second. It not only makes read from table slower, but also so many lock prevents insert, update, delete from happening timely and thus queries timeout. If you have queries like &amp;ldquo;show the currently online users from last one hour based on LastActivityDate field&amp;rdquo;, that is going to issue such a wide lock that even other harmless select queries will timeout. And did I tell you that there&amp;rsquo;s no index on LastActivityDate on aspnet_Users table?

Now don&amp;rsquo;t blame yourself for not putting either of these options on your every stored proc and every dynamically generated SQL from the very first day. ASP.NET developers made the same mistake. You won&amp;rsquo;t see either of these used in any of the stored procs used by ASP.NET Membership. For example, the following stored proc gets called whenever you access Profile object:
ALTER PROCEDURE [dbo].[aspnet_Profile_GetProperties]
    @ApplicationName      nvarchar(256),
    @UserName             nvarchar(256),
    @CurrentTimeUtc       datetime
AS
BEGIN

    DECLARE @ApplicationId uniqueidentifier
    SELECT  @ApplicationId = NULL
    SELECT  @ApplicationId = ApplicationId FROM 
      dbo.aspnet_Applications WHERE LOWER(@ApplicationName) = LoweredApplicationName
    IF (@ApplicationId IS NULL)
        RETURN

    DECLARE @UserId uniqueidentifier
    DECLARE @LastActivityDate datetime
    SELECT  @UserId = NULL

    SELECT @UserId = UserId, @LastActivityDate = LastActivityDate
    FROM...&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=dddCH2jA0Qk:tbN1TJrDKSA:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=dddCH2jA0Qk:tbN1TJrDKSA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=dddCH2jA0Qk:tbN1TJrDKSA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/dddCH2jA0Qk" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/zpw40Zu0jms/linq-to-sql-solve-transaction-deadlock-and-query-timeout-problem-using-uncommitted-reads.aspx"&gt;Linq to SQL solve Transaction deadlock and Query timeout problem using uncommitted reads&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Saturday, March 07, 2009&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds2.feedburner.com/OmarAlZabirBlog/?" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;When your database tables start accumulating thousands of rows and many users start working on the same table concurrently, SELECT queries on the tables start producing lock contentions and transaction deadlocks. This is a common problem in any high volume website. As soon as you start getting several concurrent users hitting your website that results in SELECT queries on some large table like aspnet_users table that are also being updated very frequently, you end up having one of these errors:     
Transaction (Process ID ##) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.    
Or,     
Timeout Expired. The Timeout Period Elapsed Prior To Completion Of The Operation Or The Server Is Not Responding.    
The solution to these problems are – use proper index on the table and use transaction isolation level Read Uncommitted or WITH (NOLOCK) in your SELECT queries. So, if you had a query like this:  SELECT * FORM aspnet_users 
where ApplicationID =’xxx’ AND LoweredUserName = &amp;#39;someuser&amp;#39;


You should end up having any of the above errors under high load. There are two ways to solve this:

SET TRANSACTION LEVEL READ UNCOMMITTED;
SELECT * FROM aspnet_Users 
WHERE ApplicationID =’xxx’ AND LoweredUserName = &amp;#39;someuser&amp;#39;





Or use the WITH (NOLOCK):

SELECT * FROM aspnet_Users WITH (NOLOCK) 
WHERE ApplicationID =’xxx’ AND LoweredUserName = &amp;#39;someuser&amp;#39;


The reason for the errors are that since aspnet_users is a high read and high write table, during read, the table is partially locked and during write, it is also locked. So, when the locks overlap on each other from several queries and especially when there’s a query that’s trying to read a large number of rows and thus locking large number of rows, some of the queries either timeout or produce deadlocks.


Linq to Sql does not produce queries with the WITH (NOLOCK) option nor does it use READ UNCOMMITTED. So, if you are using Linq to SQL queries, you are going to end up with any of these problems on production pretty soon when your site becomes highly popular.


For example, here’s a very simple query:

using (var db = new DropthingsDataContext())
{
    var user = db.aspnet_Users.First();
    var pages = user.Pages.ToList();
}


DropthingsDataContext is a DataContext built from Dropthings database.


When you attach SQL Profiler, you get this:


 


You see none of the queries have READ UNCOMMITTED or WITH (NOLOCK). 


The fix is to do this:

using (var db = new DropthingsDataContext2())
{
    db.Connection.Open();
    db.ExecuteCommand(&amp;quot;SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;&amp;quot;);

    var user = db.aspnet_Users.First();
    var pages = user.Pages.ToList();
}


This will result in the following profiler output



 


As you see, both queries execute within the same connection and the isolation level is set before the queries execute. So, both queries enjoy the isolation level.


Now there’s a...&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=zpw40Zu0jms:EGhEU2SFyWQ:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=zpw40Zu0jms:EGhEU2SFyWQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=zpw40Zu0jms:EGhEU2SFyWQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/zpw40Zu0jms" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/nOzECG83psk/strongly-typed-workflow-input-and-output-arguments.aspx"&gt;Strongly typed workflow input and output arguments&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Saturday, December 27, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds2.feedburner.com/OmarAlZabirBlog/?" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;When you run a Workflow using Workflow Foundation, you pass arguments to the workflow in a Dictionary form where the type of Dictionary is Dictionary&amp;lt;string, object&amp;gt;. This means you miss the strong typing features of .NET languages. You have to know what arguments the workflow expects by looking at the Workflow public properties. Moreover, there’s no way to make arguments required. You pass parameter, expect it to run, if it throws exception, you pass more arguments, hope it works now. Similarly, if you are running workflow synchronously using ManualWorkflowSchedulerService, you expect return arguments from the Workflow immediately, but there again, you have to rely on the Dictionary key and value pair. No strong typing there as well.  
In order to solve this, so that you could pass Workflow arguments as strongly typed classes, you can establish a format that every Workflow has only two arguments named &amp;quot;Request” and “Response” and none other. Whatever needs to be passed to the Workflow and expected out of it, must be passed via Request and must be expected via Response properties. Now the type of these arguments can be workflow specific, it can be any class with one or more parameters. This way, you could write code like this:  
  
The advantages of these strongly typed approach are:      Compile time validation of input parameters passed to workflow. No risk of passing unexpected object in Dictionary’s object type value.    Enforce required values by creating Request objects with non-default constructor.    Establish a fixed contract for Workflow input and output via the strongly typed Request and Response classes or interfaces.    Validate input arguments for the Workflow directly from the Request class, without going through the overhead of running a workflow.   
If we follow this approach, we create workflows with only two DependencyProperty, one for Request and one for Response. Showing you an example from my open source project Dropthings, which uses Workflow for the entire Business Layer. Below you see the Workflow that executes when a new user visits Dropthings.com, creates a new user and setups all the pages and widgets for the user. It has only two Dependency property – Request and Response.  
   
The Request parameters is of type IUserVisitWorkflowRequest. So, you can pass any class as Request argument that implements the interface.   
   
Here I have used fancy inheritance to create Request object hierarchy. You don’t need to do that. Just remember, you can pass any class. You don’t even need to use interface for Request parameter. It can be a class directly. I use all these interfaces in order to facilitate Dependency Inversion.  
Similarly, the Response object is also a class.  
  
The Response returns quite some properties. So, it’s kinda handy to wrap them all in one property.  
So, there you have it, strongly typed Workflow arguments. You can attach properties of the Request object to any activity directly form the...&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=nOzECG83psk:ZkqK3QKQmqM:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=nOzECG83psk:ZkqK3QKQmqM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=nOzECG83psk:ZkqK3QKQmqM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=nOzECG83psk:ZkqK3QKQmqM:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/nOzECG83psk" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/R5QvBFRfDKc/99-99-available-asp-net-and-sql-server-saas-production-architecture.aspx"&gt;99.99% available ASP.NET and SQL Server SaaS Production Architecture&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Wednesday, December 10, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds2.feedburner.com/OmarAlZabirBlog/?" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;You have a hot ASP.NET+SQL Server product, growing at thousand users per day and you have hit the limit of your own garage hosting capability. Now that you have enough VC money in your pocket, you are planning to go out and host on some real hosting facility, maybe a colocation or managed hosting. So, you are thinking, how to design a physical architecture that will ensure performance, scalability, security and availability of your product? How can you achieve four-nine (99.99%) availability? How do you securely let your development team connect to production servers? How do you choose the right hardware for web and database server? Should you use Storage Area Network (SAN) or just local disks on RAID? How do you securely connect your office computers to production environment?

Here I will answer all these queries. Let me first show you a diagram that I made for Pageflakes where we ensured we get four-nine availability. Since Pageflakes is a Level 3 SaaS, it&amp;rsquo;s absolutely important that we build a high performance, highly available product that can be used from anywhere in the world 24/7 and end-user gets quick access to their content with complete personalization and customization of content and can share it with others and to the world. So, you can take this production architecture as a very good candidate for Level 3 SaaS: 



Here&amp;rsquo;s a CodeProject article that explains all the ideas:

99.99% available ASP.NET and SQL Server SaaS Production Architecture

Hope you like it. Appreciate your vote.













&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=R5QvBFRfDKc:mqCjLkXCtpI:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=R5QvBFRfDKc:mqCjLkXCtpI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=R5QvBFRfDKc:mqCjLkXCtpI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=R5QvBFRfDKc:mqCjLkXCtpI:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/R5QvBFRfDKc" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/YXw8_xnXYOs/linq-to-sql-delete-an-entity-using-primary-key-only.aspx"&gt;Linq to SQL: Delete an entity using Primary Key only&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Thursday, October 30, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds2.feedburner.com/OmarAlZabirBlog/?" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;Linq to Sql does not come with a function like .Delete(ID) which allows you to delete an entity using it&amp;rsquo;s primary key. You have to first get the object that you want to delete and then call .DeleteOnSubmit(obj) to queue it for delete. Then you have to call DataContext.SubmitChanges() to play the delete queries on database. So, how to delete object without getting them from database and avoid database roundtrip?

 

You can call this function using DeleteByPK&amp;lt;Employee, int&amp;gt;(10, dataContext);

First type is the entity type and second one is the type of the primary key. If your object&amp;rsquo;s primary key is a Guid field, specify Guid instead of int.

How it works:

It figures out the table name and the primary key field name from the entity 
Then it uses the table name and primary key field name to build a DELETE query 


Figuring out the table name and primary key field name is a bit hard. There&amp;rsquo;s some reflection involved. The GetTableDef&amp;lt;TSource&amp;gt;() returns the table name and primary key field name for an entity.

Every Linq Entity class is decorated with a Table attribute that has the table name:

 

Then the primary key field is decorated with a Column attribute with IsPrimaryKey = true.

 

So, using reflection we can figure out the table name and the primary key property and the field name.

Here&amp;rsquo;s the code that does it:

 

Before you scream &amp;ldquo;Reflection is SLOW!!!!&amp;rdquo; the definition is cached. So, reflection is used only once per appDomain per entity. Subsequent call is just a dictionary lookup away, which is as fast as it can get.

You can also delete a collection of object without ever getting any one of them. The the following function to delete a whole bunch of objects:

 

The code is available here:

http://code.msdn.microsoft.com/DeleteEntitiesLinq









&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=YXw8_xnXYOs:SIiDuFmSUOc:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=YXw8_xnXYOs:SIiDuFmSUOc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=YXw8_xnXYOs:SIiDuFmSUOc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=YXw8_xnXYOs:SIiDuFmSUOc:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/YXw8_xnXYOs" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/fvJttJrO18w/how-to-convince-developers-and-management-to-use-automated-unit-test-for-ajax-websites.aspx"&gt;How to convince developers and management to use automated unit test for AJAX websites&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Monday, October 27, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds2.feedburner.com/OmarAlZabirBlog/?" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;Everyone agrees that unit testing is a good thing, we should all write unit tests. We read articles and blogs to keep us up-to-date on what’s going on in the unit test world so that we can sound cool talking to peers at lunch. But when we really sit down and try to write unit tests ourselves – “Naaah, this is waste of time, let’s ask my QA to test it; that’s much more reliable and guaranteed way to test this. What’s the point testing these functions when there are so many other functions that we should unit test first?” Had such moment yourself or with someone else? Read on.  
I had a conversation with our development lead Mike (using a highly generic name since my last post caused some trouble), who runs “the show” in our engineering team. As usual there was reservation in introducing unit test to regular development schedule. Mike also had valid points about lack of powerful tools for doing unit test on AJAX websites. He also had confusion on ‘what’ and ‘how’ to unit test our code so that we aren’t just testing database failures but real user actions that executes both business and rendering logics. So, the discussion has a lot of useful information, that will help you take the right decision when you want to sell unit test to your ASP.NET and/or AJAX development team and finally to higher management so that you can buy enough time for the effort.  
Friday, Jan 2007 – hallway      
Omar: Hey Mike, we need to start doing unit testing at least on our web services. We are wasting way too much time on manual QA. Since we are an AJAX shop, unit testing all our web services should give us pretty well coverage.   
Mike: Sure, that sounds fun. I will do some feasibility check and see how can we chip this in into our next sprint.  
Friday, Feb 2007 – washroom&amp;#160; 
Omar: Hey Mike, let’s start doing unit tests. I haven’t seen any tests last month. Can we start from this sprint?  
Mike: Sure, we can surely start from this sprint. Let me find out which tool is the right one for us.  
Friday, March 2007 – meeting room     
Omar: Hey Mike, haven’t seen any unit tests in the solution so far. Let’s seriously start writing unit tests. Did you make any plan how you want to start unit testing the webservices?  
Mike: Yeah, I did some digging around and found some tools. But most of them are for non-AJAX sites where you can programmatically hit a URL or programmatically do HTTP POST on a URL. You can also record button clicks and form posts from the browser. There’s Visual Studio’s Web Test, which does pretty good job recording regular ASP.NET site, but poor on AJAX sites. Moreover, you need to buy Team Suite edition to get that Web Test feature. Besides, recording tests and playing them back really does not help us because all those tests contain hard coded data. We can’t repeat a particular step many times with random data, at least not using any off-the-shelf tools. We need to test things carefully and systematically using random data set and sometimes use...&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=fvJttJrO18w:kiUnSE-1Xxg:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=fvJttJrO18w:kiUnSE-1Xxg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=fvJttJrO18w:kiUnSE-1Xxg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=fvJttJrO18w:kiUnSE-1Xxg:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/fvJttJrO18w" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/Nc-bH9JpSO0/solving-common-problems-with-compiled-queries-in-linq-to-sql-for-high-demand-asp-net-websites.aspx"&gt;Solving common problems with Compiled Queries in Linq to Sql for high demand ASP.NET websites&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Monday, October 27, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds2.feedburner.com/OmarAlZabirBlog/?" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;If you are using Linq to SQL, instead of writing regular Linq Queries, you should be using Compiled Queries. if you are building an ASP.NET web application that&amp;rsquo;s going to get thousands of hits per hour, the execution overhead of Linq queries is going to consume too much CPU and make your site slow. There&amp;rsquo;s a runtime cost associated with each and every Linq Query you write. The queries are parsed and converted to a nice SQL Statement on *every* hit. It&amp;rsquo;s not done at compile time because there&amp;rsquo;s no way to figure out what you might be sending as the parameters in the queries during runtime. So, if you have common Linq to Sql statements like the following one throughout your growing web application, you are soon going to have scalability nightmares:

var query = from widget in dc.Widgets
                where widget.ID == id &amp;amp;&amp;amp; widget.PageID == pageId
                select widget;

var widget = query.SingleOrDefault();


There&amp;rsquo;s a nice blog post by JD Conley that shows how evil Linq to Sql queries are:



You see how many times SqlVisitor.Visit is called to convert a Linq Query to its SQL representation? The runtime cost to convert a Linq query to its SQL Command representation is just way too high.

Rico Mariani has a very informative performance comparison of regular Linq queries vs Compiled Linq queries performance:



Compiled Query wins on every case.

So, now you know about the benefits of compiled queries. If you are building ASP.NET web application that is going to get high traffic and you have a lot of Linq to Sql queries throughout your project, you have to go for compiled queries. Compiled Queries are built for this specific scenario. 

In this article, I will show you some steps to convert regular Linq to Sql queries to their Compiled representation and how to avoid the dreaded exception &amp;ldquo;Compiled queries across DataContexts with different LoadOptions not supported.&amp;rdquo;

Here are some step by step instruction on converting a Linq to Sql query to its compiled form:

First we need to find out all the external decision factors in a query. It mostly means parameters in the WHERE clause. Say, we are trying to get a user from aspnet_users table using Username and Application ID:
 

Here, we have two external decision factor &amp;ndash; one is the Username and another is the Application ID. So, first think this way, if you were to wrap this query in a function that will just return this query as it is, what would you do? You would create a function that takes the DataContext (dc named here), then two parameters named userName and applicationID, right?

So, be it. We create one function that returns just this query:



Next step is to replace this function with a Func&amp;lt;&amp;gt; representation that returns the query. This is the hard part. If you haven&amp;rsquo;t dealt with Func&amp;lt;&amp;gt; and Lambda expression before, then I suggest you read this and this and then continue.

So, here&amp;rsquo;s the delegate...&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Nc-bH9JpSO0:QPjYis-Ap2U:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Nc-bH9JpSO0:QPjYis-Ap2U:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Nc-bH9JpSO0:QPjYis-Ap2U:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Nc-bH9JpSO0:QPjYis-Ap2U:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/Nc-bH9JpSO0" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/vBOI7L_fwcw/tips-and-tricks-to-rescue-overdue-projects.aspx"&gt;Tips and tricks to rescue overdue projects&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Monday, October 20, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds2.feedburner.com/OmarAlZabirBlog/?" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;One of my friends, who runs his own offshore development shop, was having nightmare situation with one of his customers. He&amp;#39;s way overdue on a release, the customer is screaming everyday, he&amp;#39;s paying his team from his own pocket, customer is sending an ever increasing list of changes and so on. Here&amp;#39;s how we discussed some ideas to get out of such a situation and make sure it does not repeat in future:   
Kabir: Hey, can you help me? My customer is making us work for free for extra two months to fix bugs from our last delivery. We did what he said. But after he saw the output, he came up with hundred changes, which he somehow presents as bugs or missing features and make them look like they are all our fault and making us work for last two months for free. He is sending new changes every week. We have no idea when we will complete the iteration.   
Omar: I see. Did you get a signed list of requirements from customer before you started the development?   
Kabir: Of course, I did. He sent us a word document explaining what he wants and we sent him a task breakup with hour estimates and total duration of three months. Now after three months when we showed him the product, he said, it&amp;#39;s no where close to what he had expected. Then he sent a gigantic list of things to change.   
Omar: All of those are bugs?   
Kabir: Of course not. Most of them are new features.   
Omar: Then why don&amp;#39;t you say those are new features? You have the original word document to prove. Just ask him to show where in the word document did he said X needs to be done?   
Kabir: Well..., he&amp;#39;s tricky. He somehow makes things look like it is obvious that X needs to be done and he&amp;#39;s not going to accept a requirement as done until X is done. For example, he said there must be a complete login form in the homepage. So, we did a typical login form with user name, password and OK, Cancel button. Now he says where&amp;#39;s the email verification thing? We said, you did not ask for it. He said, &amp;quot;this is obvious, every login form has a forgot password and email verification; I said *complete* login form, not half-baked login form&amp;quot;. So, you see, we can&amp;#39;t really argue to keep our image. Then, we did the login form exactly how he said. Now he says, where the client side validations of proper email address, username length, password confirmation? We said, you never asked for it! He says, &amp;quot;come on, every single website nowadays has AJAX enabled client side validation, do I have to tell you every single thing? Aren&amp;#39;t you guys smart enough to figure this out? You are already doing this for the third time, can&amp;#39;t you do it really well this time?&amp;quot;   
Omar: OK, stop. I see what&amp;#39;s your problem. Some customer will always try to make you work more for less money. They will try to squeeze out every bit of development they can for their bucks. So, you have to be extra careful on how much you commit to them and make sure they cannot chip in more...&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=vBOI7L_fwcw:4pKN0lLk8FM:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=vBOI7L_fwcw:4pKN0lLk8FM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=vBOI7L_fwcw:4pKN0lLk8FM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=vBOI7L_fwcw:4pKN0lLk8FM:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/vBOI7L_fwcw" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/Fb5wVsfQIf4/an-agile-developer-s-workflow-when-scrum-is-used.aspx"&gt;An Agile Developer's workflow when SCRUM is used&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Saturday, October 11, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds2.feedburner.com/OmarAlZabirBlog/?" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;If you are planning to start SCRUM at your company, you might need to train developers and QA to get into the mindset of an Agile developer. SCRUM is only successful when the developers and QA get into the habit of following the principles of SCRUM by heart. So, sometimes you need to offer training or do trial sprints to give some room to your developers how to get used to the working fashion of SCRUM. Giving them a handy workflow diagram that shows how they should work helps soothe the steep learning curve required for non-super star developers. I made such a workflow while I was teaching SCRUM at my friend&amp;#39;s company. The following diagram was printed and hung over the desk of each and every developer to help them grasp the culture of SCRUM quickly:



We use Flyspray for issue tracking, so you will see the mention of it frequently. 

You will see the step to &amp;quot;Update Sprint backlog with remaining hours&amp;quot; is missing. This is done kinda verbally and scrum master (sometimes same person who is the product owner) keeps track of it.

Hope you find this useful.


&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Fb5wVsfQIf4:nPzXbpWOXEA:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Fb5wVsfQIf4:nPzXbpWOXEA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=Fb5wVsfQIf4:nPzXbpWOXEA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=Fb5wVsfQIf4:nPzXbpWOXEA:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/Fb5wVsfQIf4" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/gcjuL_ndnOA/asp-net-website-continuous-integration-deployment-using-cruisecontrol-net-subversion-msbuild-and-robocopy.aspx"&gt;ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Monday, October 06, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds2.feedburner.com/OmarAlZabirBlog/?" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;You can setup continuous integration and automated deployment for your web application using CruiseControl.NET, Subversion, MSBuild and Robocopy. I will show you how you can automatically build the entire solution, email build report to developers and QA, deploy latest code in IIS all using CruiseControl.NET every N minutes. 

First get the following:

CruiseControl.NET  
Subversion (install the command line tools and add the Subversion bin path to PATH environment variable)  
Robocopy (Windows Vista/2008 has it built-in, here&amp;#39;s the link for Windows 2003)  
Install .NET Framework. You need it for MSBuild. 


You will learn how I have configured Continuous Integration and Deployment for my open source AJAX Portal project www.Dropthings.com. The code is hosted at CodePlex. When some developer makes a commit, CruiseControl downloads the latest code, builds the entire solution, emails build report and then deploys the latest web site to IIS 6.0.

After installing CruiseControl.NET, go to Programs -&amp;gt; Cruise Control -&amp;gt; CruiseControl.NET Config.

Now keep copying and pasting the following XML blocks and make sure you understand each block and make necessary changes:


   1: &amp;lt;cruisecontrol&amp;gt;
   2:     &amp;lt;project name=&amp;quot;Dropthings&amp;quot; queue=&amp;quot;DropthingsQueue&amp;quot; queuePriority=&amp;quot;1&amp;quot;&amp;gt;
   3:         &amp;lt;!-- 
   4:         Path to the trunk folder where the full solution starts from. This is where
   5:         subversion checkout and incremental update is performed 
   6:         --&amp;gt;
   7:         &amp;lt;workingDirectory&amp;gt;d:\cc\dropthings\code\trunk\&amp;lt;/workingDirectory&amp;gt;
   8:         &amp;lt;!-- Some path where CCNet writes its logs and stuffs. It can be outside the log folder --&amp;gt;
   9:         &amp;lt;artifactDirectory&amp;gt;d:\cc\dropthings\artifact\&amp;lt;/artifactDirectory&amp;gt;
  10:         &amp;lt;category&amp;gt;Dropthings&amp;lt;/category&amp;gt;
  11:         &amp;lt;!-- CCNet installs a web dashboard. Enter the URL of that dashboard here --&amp;gt;
  12:         &amp;lt;webURL&amp;gt;http://localhost/ccnet/&amp;lt;/webURL&amp;gt;
  13:         &amp;lt;modificationDelaySeconds&amp;gt;60&amp;lt;/modificationDelaySeconds&amp;gt;
  14:         &amp;lt;labeller type=&amp;quot;defaultlabeller&amp;quot;&amp;gt;
  15:             &amp;lt;prefix&amp;gt;0.1.&amp;lt;/prefix&amp;gt;
  16:             &amp;lt;incrementOnFailure&amp;gt;true&amp;lt;/incrementOnFailure&amp;gt;
  17:             &amp;lt;labelFormat&amp;gt;000&amp;lt;/labelFormat&amp;gt;
  18:         &amp;lt;/labeller&amp;gt;
  19:         &amp;lt;state type=&amp;quot;state&amp;quot; directory=&amp;quot;State&amp;quot; /&amp;gt;



First change the working directory. It needs to be the path of the folder where you will have the solution downloaded. I generally create folder structure like this:

D:\CC - Root for all CC.NET enabled projects 

\ProjectName - Root project folder 

\Code - Code folder where code is downloaded from subversion 

\Artifact - CC.NET generates a lot of stuff. All goes here.






 Next comes the Subversion integration block:


   1: &amp;lt;sourcecontrol type=&amp;quot;svn&amp;quot;&amp;gt;
   2:    ...&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=gcjuL_ndnOA:0FVtpVe4JaA:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=gcjuL_ndnOA:0FVtpVe4JaA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=gcjuL_ndnOA:0FVtpVe4JaA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=gcjuL_ndnOA:0FVtpVe4JaA:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/gcjuL_ndnOA" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/kwIvli9E3gg/using-multiple-broadband-connections-without-using-any-special-router-or-software.aspx"&gt;Using multiple broadband connections without using any special router or software&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Sunday, October 05, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds2.feedburner.com/OmarAlZabirBlog/?" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;I have two broadband connections. One cheap connection, which I mostly use for browsing and downloading. Another very expensive connection that I use for voice chat, remote desktop connection etc. Now, using these two connections at the same time required two computers before. But I figured out a way to use both connections at the same time using the same computer. Here&amp;#39;s how: 
Connect the cheap internet connection that is used mostly for non-critical purpose like downloading, browsing to a wireless router. 
Connect the expensive connection that is used for network latency sensitive work like Voice Conference, Remote Desktop directly via LAN. 
When you want to establish a critical connection like starting voice conf app (Skype) or remote desktop client, momentarily disconnect the wireless. This will make your LAN connection the only available internet. So, all the new connections will be established over the LAN. Now you can start Skype and initiate a voice conference or use Remote Desktop client and connect to a computer. The connection will be established over LAN. 
Now turn on wireless. Wireless will now become the first preference for Windows to go to internet. So, now you can start Outlook, browser etc and they will be using the wireless internet connection. During this time, Skype and Terminal Client is still connected over the LAN connection. As they use persisted connection, they keep using the LAN connection and do not switch to the wireless.  
This way you get to use two broadband connections simultaneously. 
&amp;nbsp;  
Here you see I have data transfer going on through two different connection. The bottom one is the LAN which is maintaining a continuous voice data stream. The upper one is the wireless connection that sometimes consumes bandwidth when I browse. 
  
Using Sysinternal&amp;#39;s TCPView, I can see some connection is going through LAN and some through Belkin router. The selected ones - the terminal client and the MSN Messenger is using LAN where the Internet Explorer and Outlook is working over Wireless connection. &lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=kwIvli9E3gg:4yFKK3Xe42I:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=kwIvli9E3gg:4yFKK3Xe42I:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=kwIvli9E3gg:4yFKK3Xe42I:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=kwIvli9E3gg:4yFKK3Xe42I:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/kwIvli9E3gg" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/UFBs-Pp0Pp8/best-practices-for-creating-websites-in-iis-6-0.aspx"&gt;Best practices for creating websites in IIS 6.0&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Saturday, October 04, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds2.feedburner.com/OmarAlZabirBlog/?" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;Every time I create an IIS website, I do some steps, which I consider as best practice for creating any IIS website for better performance, maintainability, and scalability. Here&amp;#39; re the things I do: 
Create a separate application pool for each web application 
I always create separate app pool for each web app because I can select different schedule for app pool recycle. Some heavy traffic websites have long recycle schedule where low traffic websites have short recycle schedule to save memory. Moreover, I can choose different number of processes served by the app pool. Applications that are made for web garden mode can benefit from multiple process where applications that use in-process session, in memory cache needs to have single process serving the app pool. Hosting all my application under the DefaultAppPool does not give me the flexibility to control these per site. 
The more app pool you create, the more ASP.NET threads you make available to your application. Each w3wp.exe has it&amp;#39;s own thread pool. So, if some application is congesting particular w3wp.exe process, other applications can run happily on their separate w3wp.exe instance, running under separate app pool. Each app pool hosts its own w3wp.exe instance. 
So, my rule of thumb: Always create new app pool for new web applications and name the app pool based on the site&amp;#39;s domain name or some internal name that makes sense. For example, if you are creating a new website alzabir.com, name the app pool alzabir.com to easily identify it. 
Another best practice: Disable the DefaultAppPool so that you don&amp;#39;t mistakenly keep adding sites to DefaultAppPool. 
  
First you create a new application pool. Then you create a new Website or Virtual Directory, go to Properties -&amp;gt; Home Directory tab -&amp;gt; Select the new app pool. 
 
Customize Website properties for performance, scalability and maintainability 
First you map the right host headers to your website. In order to do this, go to WebSite tab and click on &amp;quot;Advanced&amp;quot; button. Add mapping for both domain.com and www.domain.com. Most of the time, people forget to map the domain.com. Thus many visitors skip typing the www prefix and get no page served. 
 
Next turn on some log entries: 
 
These are very handy for analysis. If you want to measure your bandwidth consumption for specific sites, you need the Bytes Sent. If you want to measure the execution time of different pages and find out the slow running pages, you need Time Taken. If you want to measure unique and returning visitors, you need the Cookie. If you need to know who is sending you most traffic - search engines or some websites, you need the Referer. Once these entries are turned on, you can use variety of Log Analysis tools to do the analysis. For example, open source AWStats.  
But if you are using Google Analytics or something else, you should have these turned off, especially the Cookie and Referer because they take quite some space on the log. If...&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=UFBs-Pp0Pp8:Rfar1v6i7ho:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=UFBs-Pp0Pp8:Rfar1v6i7ho:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=UFBs-Pp0Pp8:Rfar1v6i7ho:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=UFBs-Pp0Pp8:Rfar1v6i7ho:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/UFBs-Pp0Pp8" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/x8AlDh3RxXY/create-asp-net-mvc-controllers-under-namespace-and-specific-url.aspx"&gt;Create ASP.NET MVC Controllers under Namespace and specific URL&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Saturday, October 04, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds2.feedburner.com/OmarAlZabirBlog/?" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;When you have a lot of controllers, you need to organize them under Namespaces. Also, it is better to put controllers under subfolders in order to organize them properly and have some meaningful URL for them like /Admin/User where Admin is the subfolder and User is the controller. For example, you might have a lot of controllers that are APIs exposed by your web app, not regular pages. So, you might want to put them under /API/ folder. You also want to make sure no one can access those controllers from the root url. For example, no one must call /User/GetUserList instead they must call /API/User/GetUserList 
ASP.NET MVC default routing and Controller Factory is very greedy, it ignores the subfolders inside the &amp;quot;Controllers&amp;quot; folder. There&amp;#39;s a DefaultControllerFactory class in ASP.NET MVC which traverses all controllers under the &amp;quot;Controller&amp;quot; folder and creates a cache using just the class name as the key. So, it ignores any namespace or any subfolder where you have put the controller. So, I created a derivative of the default controller factory and created a new factory that checks if the requested controller belongs to any specific namespace and whether that controller must be inside a specific subfolder. You can map /Admin folder to respond to all controllers that are under then YourWebApp.Admin namespace. Similarly, you can map /API folder to respond to all controllers that are under the YourWebApp.API namespace. None of these controllers can be accessed outside the specified URL. Here&amp;#39;s the factory that does it: 
 
This controller checks the namespace of the controller being returned by ASP.NET MVC&amp;#39;s default implementation and ensures the requested URL is the right url where controllers from the namespace can be accessed. So, this means if the controller matches MvcWebAPI.API.UserController, it ensures the URL being requested must be /MvcWebAPI/API/User. It will return null if the URL was something else like /MvcWebAPI/User or /MvcWebAPI/SomeotherFolder/User. 
Here&amp;#39;s how you use it form Global.asax: 
  
You create a mapping for a Namespace and the subfolder it must belong to. Then you register the new Controller Factory as the default controller factory. 
Now the second catch is, the default Route for the {controller}/{action}/{id} won&amp;#39;t work for you. You need to create a specific router that starts with the subfolder name. For example, API/{controller}/{action} 
  
Here&amp;#39; two things to notice:  The use of PathStartWith routing constraint, which I will explain soon  The last parameter which tells the route to include the API namespace for this route. Otherwise it can&amp;#39;t find the controllers in the API namespace 
So, the PathStartsWith routing constraint ensures this route gets hit only when the requested URL is under the /API/ folder. For any other URL, it returns false and thus the routing handler skips this route. 
  
It just does a comparison on the AbsolutePath of the current request URL to...&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=x8AlDh3RxXY:zjEuKozKamc:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=x8AlDh3RxXY:zjEuKozKamc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=x8AlDh3RxXY:zjEuKozKamc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=x8AlDh3RxXY:zjEuKozKamc:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/x8AlDh3RxXY" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/n0CtjdX0MpY/create-rest-api-using-asp-net-mvc-that-speaks-both-json-and-plain-xml.aspx"&gt;Create REST API using ASP.NET MVC that speaks both Json and plain Xml&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Friday, October 03, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds2.feedburner.com/OmarAlZabirBlog/?" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;ASP.NET MVC Controllers can directly return objects and collections, without rendering a view, which makes it quite appealing for creating REST like API. The nice extensionless Url provided by MVC makes it handy to build REST services, which means you can create APIs with smart Url like &amp;quot;something.com/API/User/GetUserList&amp;quot; 
There are some challenges to solve in order to expose REST API:  Based on who is calling your API, you need to be able to speak both Json and plain old Xml (POX). If the call comes from an AJAX front-end, you need to return objects serialized as Json. If it&amp;#39;s coming from some other client, say a PHP website, you need to return plain Xml.  Similarly you need to be able to understand REST, Json and plain Xml calls. Someone can hit you using REST url, someone can post a Json payload or someone can post Xml payload. 
I have created an ObjectResult class which takes an object and generates Xml or Json output automatically looking at the Content-Type header of HttpRequest. AJAX calls send Content-Type=application/json. So, it generates Json as response in that case, but when Content-Type is something else, it does simple Xml Serialzation.  
 
Here&amp;#39;s the ObjectResult that you can use from Controllers to return objects and it takes care of proper serialization method. Above shows the Json serialization, which is quite simple. XmlSerialization is a bit complex though: 
 Things to note here:  You have to force UTF8 encoding. Otherwise it produces UTF16 output.  XML Declaration is skipped because that&amp;#39;s not quite necessary. Wastes bandwidth. If you need it, turn it on.  I have turned on indenting for better readability. You can turn it off to save bandwidth. 
Some of you might be boiling inside looking at my obscure coding style. I love this style! I am spoiled by jQuery. I wish there was a cQuery. I actually started writing one, but it never saw day light just like my hundred other open source attempts. 
Now back to Object Serialization, we got the serialization done. Now you can return objects from Controller easily: 
  
You can use the test web project to call these methods and see the result: 
  
So far you have seen simple object and list serialization. A best practice is to return a common result object that has some status, message and then the real payload. It&amp;#39;s handy when you only need to return some error but no object or list. I use a common Result object that has three properties - ErrorCode (0 by default means success), Message (a string data type) and Data which is the real object. 
  
When you want to return only a result with error message, you can do this: 
  
This produces a result like this: 
  
No payload here. So, the return format is always consistent. Those who are consuming service can write a common Xml or Json parsing code to consume both success and failure response. Those who are building API for their website, I humbly request you to return consistent response for both success and...&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=n0CtjdX0MpY:Bl6iaCPqcq4:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=n0CtjdX0MpY:Bl6iaCPqcq4:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=n0CtjdX0MpY:Bl6iaCPqcq4:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=n0CtjdX0MpY:Bl6iaCPqcq4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=n0CtjdX0MpY:Bl6iaCPqcq4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=n0CtjdX0MpY:Bl6iaCPqcq4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=n0CtjdX0MpY:Bl6iaCPqcq4:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=n0CtjdX0MpY:Bl6iaCPqcq4:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=n0CtjdX0MpY:Bl6iaCPqcq4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=n0CtjdX0MpY:Bl6iaCPqcq4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=n0CtjdX0MpY:Bl6iaCPqcq4:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/n0CtjdX0MpY" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/tv_cnv3oCV0/http-handler-to-combine-multiple-files-cache-and-deliver-compressed-output-for-faster-page-load.aspx"&gt;HTTP handler to combine multiple files, cache and deliver compressed output for faster page load&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Thursday, August 28, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds2.feedburner.com/OmarAlZabirBlog/?" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;It&amp;#39;s a good practice to use many small Javascript and CSS files instead of one large Javascript/CSS file for better code maintainability, but bad in terms of website performance. Although you should write your Javascript code in small files and break large CSS files into small chunks but when browser requests those javascript and css files, it makes one Http request per file. Every Http Request results in a network roundtrip form your browser to the server and the delay in reaching the server and coming back to the browser is called latency. So, if you have four javascripts and three css files loaded by a page, you are wasting time in seven network roundtrips. Within USA, latency is average 70ms. So, you waste 7x70 = 490ms, about half a second of delay. Outside USA, average latency is around 200ms. So, that means 1400ms of waiting. Browser cannot show the page properly until Css and Javascripts are fully loaded. So, the more latency you have, the slower page loads. 
Here&amp;#39;s a graph that shows how each request latency adds up and introduces significant delay in page loading: 
  
You can reduce the wait time by using a CDN. Read my previous blog post about using CDN. However, a better solution is to deliver multiple files over one request using an HttpHandler that combines several files and delivers as one output. So, instead of putting many &amp;lt;script&amp;gt; or &amp;lt;link&amp;gt; tag, you just put one &amp;lt;script&amp;gt; and one &amp;lt;link&amp;gt; tag, and point them to the HttpHandler. You tell the handler which files to combine and it delivers those files in one response. This saves browser from making many requests and eliminates the latency.  
  
Here you can see how much improvement you get if you can combine multiple javascripts and css into one. 
In a typical web page, you will see many javascripts referenced:&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;/Content/JScript/jquery.js&amp;quot;&amp;gt;
&amp;lt;/script&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;/Content/JScript/jDate.js&amp;quot;&amp;gt;
&amp;lt;/script&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;/Content/JScript/jQuery.Core.js&amp;quot;&amp;gt;
&amp;lt;/script&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;/Content/JScript/jQuery.Delegate.js&amp;quot;&amp;gt;
&amp;lt;/script&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;/Content/JScript/jQuery.Validation.js&amp;quot;&amp;gt;
&amp;lt;/script&amp;gt;

Instead of these individual &amp;lt;script&amp;gt; tags, you can use only one &amp;lt;script&amp;gt; tag to serve the whole set of scripts using an Http Handler:&amp;lt;script type=&amp;quot;text/javascript&amp;quot; 
    src=&amp;quot;HttpCombiner.ashx?s=jQueryScripts&amp;amp;t=text/javascript&amp;amp;v=1&amp;quot; &amp;gt;
&amp;lt;/script&amp;gt; 

The Http Handler reads the file names defined in a configuration and combines all those files and delivers as one response. It delivers the response as gzip compressed to save bandwidth. Moreover, it generates proper cache header to cache the response in browser cache, so that, browser does not request it...&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=tv_cnv3oCV0:S-Eph0b0y58:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=tv_cnv3oCV0:S-Eph0b0y58:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=tv_cnv3oCV0:S-Eph0b0y58:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=tv_cnv3oCV0:S-Eph0b0y58:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=tv_cnv3oCV0:S-Eph0b0y58:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=tv_cnv3oCV0:S-Eph0b0y58:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=tv_cnv3oCV0:S-Eph0b0y58:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=tv_cnv3oCV0:S-Eph0b0y58:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=tv_cnv3oCV0:S-Eph0b0y58:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=tv_cnv3oCV0:S-Eph0b0y58:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=tv_cnv3oCV0:S-Eph0b0y58:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/tv_cnv3oCV0" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/9ge7sjX9TnU/loading-static-content-in-asp-net-pages-from-different-domain-for-faster-parallel-download.aspx"&gt;Loading static content in ASP.NET pages from different domain for faster parallel download&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Friday, August 01, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds2.feedburner.com/OmarAlZabirBlog/?" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;Generally we put static content (images, css, js) of our website inside the same web project. Thus they get downloaded from the same domain like www.dropthings.com. There are three problems in this approach:  They occupy connections on the same domain www.dropthings.com and thus other important calls like Web service call do not get a chance to happen earlier as browser can only make two simultaneous connections per domain.  If you are using ASP.NET Forms Authentication, then you have that gigantic Forms Authentication cookie being sent with every single request on www.dropthings.com. This cookie gets sent for all images, CSS and JS files, which has no use for the cookie. Thus it wastes upload bandwidth and makes every request slower. Upload bandwidth is very limited for users compared to download bandwidth. Generally users with 1Mbps download speed has around 128kbps upload speed. So, adding another 100 bytes on the request for the unnecessary cookie results in delay in sending the request and thus increases your site load time and the site feels slow to respond.  It creates enormous IIS Logs as it records the cookies for each static content request. Moreover, if you are using Google Analytics to track hits to your site, it issues four big cookies that gets sent for each and every image, css and js files resulting in slower requests and even larger IIS log entries. 
Let&amp;#39;s see the first problem, browser&amp;#39;s two connection limit. See what happens when content download using two HTTP requests in parallel: 
 
This figure shows only two files are downloaded in parallel. All the hits are going to the same domain e.g. www.dropthings.com. As you see, only two call can execute at the same time. Moreover, due to browser&amp;#39;s way of handling script tags, once a script is being downloaded, browser does not download anything else until the script has downloaded and executed. 
Now, if we can download the images from different domain, which allows browser to open another two simultaneous connections, then the page loads a lot faster: 
 
You see, the total page downloads 40% faster. Here only the images are downloaded from a different domain e.g. &amp;quot;s.dropthings.com&amp;quot;, thus the calls for the script, CSS and webservices still go to main domain e.g. www.dropthings.com 
The second problem for loading static content from same domain is the gigantic forms authentication cookie or any other cookie being registered on the main domain e.g. www subdomain. Here&amp;#39;s how Pageflake&amp;#39;s website&amp;#39;s request looks like with the forms authentication cookie and Google Analytics cookies: 
  
You see a lot of data being sent on the request header which has no use for any static content. Thus it wastes bandwidth, makes request reach server slower and produces large IIS logs. 
You can solve this problem by loading static contents from different domain as we have done it at Pageflakes by loading static contents from a different domain e.g. flakepage.com. As the...&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=9ge7sjX9TnU:xXFnXhHlJ3o:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=9ge7sjX9TnU:xXFnXhHlJ3o:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=9ge7sjX9TnU:xXFnXhHlJ3o:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=9ge7sjX9TnU:xXFnXhHlJ3o:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=9ge7sjX9TnU:xXFnXhHlJ3o:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=9ge7sjX9TnU:xXFnXhHlJ3o:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=9ge7sjX9TnU:xXFnXhHlJ3o:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=9ge7sjX9TnU:xXFnXhHlJ3o:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=9ge7sjX9TnU:xXFnXhHlJ3o:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=9ge7sjX9TnU:xXFnXhHlJ3o:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=9ge7sjX9TnU:xXFnXhHlJ3o:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/9ge7sjX9TnU" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/_D-nRcajJnY/open-source-asp-net-3-5-ajax-portal-new-and-improved.aspx"&gt;Open Source ASP.NET 3.5 AJAX Portal - new and improved&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Monday, July 14, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds2.feedburner.com/OmarAlZabirBlog/?" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;Last week I released a new version of Dropthings, my open source AJAX portal, that shows many fancy Web 2.0 features and showcases extensive use of ASP.NET 3.5, Workflow Foundation, C# 3.0 new language features, custom ASP.NET AJAX extenders, many performance and scalability techniques. I have written a book on these topics as well.

The new version implements the following performance and scalability improvement techniques:

10 ASP.NET Performance and Scalability Secrets  
Fast ASP.NET page rendering by deferred script loading  
Load large amount of Javascripts in batch and thus load AJAX sites a lot faster  
Fast Streaming AJAX proxy that solves double downloading problems and continuously streams content from external domain  
Making best use of cache for high performance website  
On-demand UI loading on AJAX websites


Here&amp;#39;s how the new version looks:



Hope you like the new design and the performance and scalability techniques that can significantly boost your ASP.NET website&amp;#39;s quality. I highly recommend these techniques for ASP.NET websites. These are easy to implement and makes a world of difference in speed and smoothness for ASP.NET websites.

I am thinking about making an ASP.NET MVC version of this portal using jQuery. Do you think it will be a hot area to explore?

&amp;nbsp;

 



Share this post : 
  
  
  
  
  
  
  
  




&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=_D-nRcajJnY:X-jt_9AAMRg:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=_D-nRcajJnY:X-jt_9AAMRg:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=_D-nRcajJnY:X-jt_9AAMRg:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=_D-nRcajJnY:X-jt_9AAMRg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=_D-nRcajJnY:X-jt_9AAMRg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=_D-nRcajJnY:X-jt_9AAMRg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=_D-nRcajJnY:X-jt_9AAMRg:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=_D-nRcajJnY:X-jt_9AAMRg:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=_D-nRcajJnY:X-jt_9AAMRg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=_D-nRcajJnY:X-jt_9AAMRg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=_D-nRcajJnY:X-jt_9AAMRg:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/_D-nRcajJnY" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/GQJNZFDVAkI/deploy-asp-net-mvc-on-iis-6-solve-404-compression-and-performance-problems.aspx"&gt;Deploy ASP.NET MVC on IIS 6, solve 404, compression and performance problems&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Monday, June 30, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds2.feedburner.com/OmarAlZabirBlog/?" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;There are several problems with ASP.NET MVC application when deployed on IIS 6.0:  Extensionless URLs give 404 unless some URL Rewrite module is used or wildcard mapping is enabled  IIS 6.0 built-in compression does not work for dynamic requests. As a result, ASP.NET pages are served uncompressed resulting in poor site load speed.  Mapping wildcard extension to ASP.NET introduces the following problems:   Slow performance as all static files get handled by ASP.NET and ASP.NET reads the file from file system on every call  Expires headers doesn&amp;#39;t work for static content as IIS does not serve them anymore. Learn about benefits of expires header from here. ASP.NET serves a fixed expires header that makes content expire in a day.  Cache-Control header does not produce max-age properly and thus caching does not work as expected. Learn about caching best practices from here.  After deploying on a domain as the root site, the homepage produces HTTP 404. Problem 1: Visiting your website&amp;#39;s homepage gives 404 when hosted on a domain 
You have done the wildcard mapping, mapped .mvc extention to ASP.NET ISAPI handler, written the route mapping for Default.aspx or default.aspx (lowercase), but still when you visit your homepage after deployment, you get: 
  
You will find people banging their heads on the wall here:  http://forums.asp.net/t/1237051.aspx  http://forums.asp.net/t/1253599.aspx  http://forums.asp.net/p/1239943/2294813.aspx 
Solution is to capture hits going to &amp;quot;/&amp;quot; and then rewrite it to Default.aspx: 
 
You can apply this approach to any URL that ASP.NET MVC is not handling for you and it should handle. Just see the URL reported on the 404 error page and then rewrite it to a proper URL. Problem 2: IIS 6 compression is no longer working after wildcard mapping 
When you enable wildcard mapping, IIS 6 compression no longer works for extensionless URL because IIS 6 does not see any extension which is defined in IIS Metabase. You can learn about IIS 6 compression feature and how to configure it properly from my earlier post.  
Solution is to use an HttpModule to do the compression for dynamic requests. Problem 3: ASP.NET ISAPI does not cache Static Files  
When ASP.NET&amp;#39;s DefaultHttpHandler serves static files, it does not cache the files in-memory or in ASP.NET cache. As a result, every hit to static file results in a File read. Below is the decompiled code in DefaultHttpHandler when it handles a static file. As you see here, it makes a file read on every hit and it only set the expiration to one day in future. Moreover, it generates ETag for each file based on file&amp;#39;s modified date. For best caching efficiency, we need to get rid of that ETag, produce an expiry date on far future (like 30 days), and produce Cache-Control header which offers better control over caching. 
  
So, we need to write a custom static file handler that will cache small files like images, Javascripts, CSS, HTML and so on in ASP.NET cache and serve the...&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=GQJNZFDVAkI:d67Tj_sZPcE:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=GQJNZFDVAkI:d67Tj_sZPcE:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=GQJNZFDVAkI:d67Tj_sZPcE:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=GQJNZFDVAkI:d67Tj_sZPcE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=GQJNZFDVAkI:d67Tj_sZPcE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=GQJNZFDVAkI:d67Tj_sZPcE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=GQJNZFDVAkI:d67Tj_sZPcE:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=GQJNZFDVAkI:d67Tj_sZPcE:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=GQJNZFDVAkI:d67Tj_sZPcE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=GQJNZFDVAkI:d67Tj_sZPcE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=GQJNZFDVAkI:d67Tj_sZPcE:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/GQJNZFDVAkI" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="accentbar"&gt;
		&lt;span class="left"&gt;&amp;nbsp;&lt;/span&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5 News Feed&lt;span class="right"&gt;&amp;nbsp;&lt;/span&gt;
	&lt;/div&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;/div&gt;</description><author>oazabir</author><pubDate>Thu, 09 Apr 2009 14:51:08 GMT</pubDate><guid isPermaLink="false">Updated Wiki: Home 20090409025108P</guid></item><item><title>Updated Wiki: Home</title><link>http://dropthings.codeplex.com/Wiki/View.aspx?title=Home&amp;version=27</link><description>&lt;div class="wikidoc"&gt;
&lt;b&gt;Project Description&lt;/b&gt;&lt;br /&gt;Ajax Web Portal built on Linq, Workflow Foundation and ASP.NET AJAX. Code is in Visual Studio 2008 using .NET 3.0 and .NET 3.5.&lt;br /&gt;&lt;b&gt;Production site&lt;/b&gt;&lt;br /&gt;&lt;a href="http://dropthings.omaralzabir.com" class="externalLink"&gt;http://dropthings.omaralzabir.com&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;For latest news and updates, visit my blog &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/omar/" class="externalLink"&gt;http://msmvps.com/blogs/omar/&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;b&gt;Source Code&lt;/b&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/dropthings/" class="externalLink"&gt;http://code.google.com/p/dropthings/&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt; &lt;br /&gt;&lt;b&gt;Book about this project&lt;/b&gt;&lt;br /&gt;&lt;img src="http://i3.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=dropthings&amp;amp;DownloadId=27511" alt="MyBook.jpg" /&gt;&lt;br /&gt;This book explains how this project has been built step by step. It also explains many advance AJAX concepts, development and production challenges for building and maintaining a high volume production website.&lt;br /&gt; &lt;br /&gt;Get it from Amazon:&lt;br /&gt;&lt;a href="http://www.amazon.com/Building-Web-2-0-Portal-ASP-NET/dp/0596510500" class="externalLink"&gt;http://www.amazon.com/Building-Web-2-0-Portal-ASP-NET/dp/0596510500&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt; &lt;br /&gt;&lt;b&gt;Technologies&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;
&lt;li&gt;ASP.NET 2.0&lt;/li&gt;&lt;li&gt;jQuery&lt;/li&gt;&lt;li&gt;ASP.NET AJAX (.NET 3.5)&lt;/li&gt;&lt;li&gt;Silverlight&lt;/li&gt;&lt;li&gt;Linq to Sql&lt;/li&gt;&lt;li&gt;Linq to Xml&lt;/li&gt;&lt;li&gt;Workflow Foundation (.NET 3.0)&lt;/li&gt;&lt;li&gt;Visual Studio 2008 and SQL Server 2005&lt;/li&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;b&gt;Features&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;
&lt;li&gt;Configure widgets for specific user roles.&lt;/li&gt;&lt;li&gt;Configure different default page setup for different roles - Managers get some widgets, Employees get different widgets and so on.&lt;/li&gt;&lt;li&gt;Ability to define page setup for anonymous users and different page setup for logged in users.&lt;/li&gt;&lt;li&gt;Multiple Tabs.&lt;/li&gt;&lt;li&gt;Customizable Widget Gallery.&lt;/li&gt;&lt;li&gt;Different column setup.&lt;/li&gt;&lt;li&gt;Build your own widgets using Silverlight, ASP.NET or plain Javascripts.&lt;/li&gt;&lt;li&gt;Host widgets on any page of your website&lt;/li&gt;&lt;li&gt;Easy to integrate Dropthings to your own website e.g. http://myoffice.bt.com is built on top of Dropthings.&lt;/li&gt;&lt;li&gt;Business Layer is entirely Workflow Foundation driven - easy to plug-in your own business logic as Activities.&lt;/li&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;b&gt;Join Us&lt;/b&gt;&lt;br /&gt;If you are a seasoned ASP.NET Developer and have ASP.NET AJAX skill, come and join us to make Dropthings a feature rich Ajax Web Portal. Please email me at &amp;quot;OmarALZabir&amp;quot; at gmail dot com.&lt;br /&gt; &lt;br /&gt;&lt;b&gt;What is an AJAX Portal&lt;/b&gt;&lt;br /&gt;A &lt;i&gt;Portal&lt;/i&gt; refers to a page that allows users to customize their own homepage by dragging and dropping &lt;i&gt;widgets&lt;/i&gt; onto the page. This approach gives users complete control over what content they see on their page, where they want to see it, and how they want to interact with it. &lt;br /&gt; &lt;br /&gt;A widget is a discrete piece on a Web page that performs a particular function and comes with its own UI and set of features. Examples of widgets include a to-do-list, an address book, a contact list, an RSS feed, or even a clock, calendar, playlist, stock ticker, weather report, traffic report, dictionary, game, or almost anything you can imagine that can be packaged up and dropped on a Web page. In a corporate environment, widgets can connect to internal systems, such as an Expense Tracker widget that interacts directly with the internal Accounting System. If you are familiar with Sharepoint Portal, then you already know about Widgets. They are called Web parts in Sharepoint’s term and also in ASP.NET 2.0. &lt;br /&gt; &lt;br /&gt;Portals are powerful RSS aggregation platform. You can put as many RSS widgets as you like on your page and get fresh content delivered to you as soon as it is published. Some Portal like Pageflakes archives RSS for a long time and thus you can go back in time and read older posts, save posts, and forward interesting articles to your friends.&lt;br /&gt; &lt;br /&gt;An Ajax-powered portal is specifically a portal that uses Ajax technologies to create richer experiences for its users. It is one step ahead of previous generation portals like My Yahoo or MSN.com, because it gives you state-of-the-art UI that behaves more like a Windows client application -- with widgets, animations, popups, client side data grids, and other effects not usually found on a non-Ajax Web portal . &lt;br /&gt; &lt;br /&gt;&lt;b&gt;How to run the project&lt;/b&gt;&lt;br /&gt;&lt;ol&gt;
&lt;li&gt;Download the latest source code from Google Code site &lt;a href="http://code.google.com/p/dropthings/" class="externalLink"&gt;http://code.google.com/p/dropthings/&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Follow the Readme.txt&lt;/li&gt;
&lt;/ol&gt; &lt;br /&gt;&lt;b&gt;How is ASP.NET AJAX used in this project?&lt;/b&gt;&lt;br /&gt;It is an N-tier application, with a user interface (UI) layer, a business layer, and a data access layer. I have used ASP.NET AJAX to implement the UI layer of the portal application which includes the homepage and the widgets’ UI. ASP.NET AJAX provides the framework for loading widgets onto the home page, updating widgets without doing any postbacks (via UpdatePanel), and changing page layout by dragging and dropping widgets on the page. It also provides a rich collection of Control Extenders, that add cool effects like fade in/fade out, smooth transitions, and client side animations . You can add to the rich clientside experience by providing auto-completion behavior on text boxes, asynchronous data loading via webservice  calls, and client side paging, sorting and many more.&lt;br /&gt; &lt;br /&gt;&lt;b&gt;How is .NET 3.5 used in this project&lt;/b&gt;&lt;br /&gt;The business layer of the application is built with the Workflow Foundation  in .NET 3.0 . Major operations like a first-time user visit, a subsequent user visit, adding a new widget, and creating a new page are all orchestrated using workflow . The workflows contain all the business rules and activities needed to complete each operation. For example, the &amp;quot;New User Visit&amp;quot; workflow creates the user account, populates the user profile with default values, creates some default pages, populates them with specific widgets, etc. Such compound operations are very easy to build with Workflows , which enables you to break the complete workflow operation into smaller chunks named Activities. Each Activity does a very small amount of work. It talks to the data access layer and performs the task. The data access layer is built with .NET 3.5 , utilizing LINQ to SQL .&lt;br /&gt;The web project and the widgets make good use of .NET 3.5 by utilizing lambda expressions , LINQ  to SQL, and LINQ to XML. You will use Linq queries to work with collections and database rows. Widgets make good use of Linq to Xml in order to consume XML from external data sources.&lt;br /&gt; &lt;br /&gt;Warning: Dropthings.com is a very simple, open-source example of what can be done with AJAX and Microsoft technologies.  It is intended for educational purposes only.  Dropthings.com has absolutely nothing to do with &lt;a href="http://www.pageflakes.com" class="externalLink"&gt;http://www.pageflakes.com&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;.  But this project does a good job to show you how all the new hot technologies work together in a working web application that's production ready.&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
My Blog
&lt;/h1&gt;---&lt;br /&gt;&lt;div class="rss"&gt;
	&lt;div class="accentbar"&gt;
		&lt;span class="left"&gt;&amp;nbsp;&lt;/span&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5 News Feed&lt;span class="right"&gt;&amp;nbsp;&lt;/span&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/-LIRJgSGBXo/memory-leak-with-delegates-and-workflow-foundation.aspx"&gt;Memory Leak with delegates and workflow foundation&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Saturday, March 14, 2009&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds.feedburner.com/OmarAlZabirBlog" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;Recently after Load Testing my open source project Dropthings, I encountered a lot of memory leak. I found lots of Workflow Instances and Linq Entities were left in memory and never collected. After profiling the web application using .NET Memory Profiler, it showed the real picture:  
  
It shows you that instances of the several types are being created but not being removed. You see the “New” column has positive value, but the “Remove” column has 0. That means new instances are being created, but not removed. Basically the way you do Memory Profiling is, you take two snapshots. Say you take one snapshot when you first visit your website. Then you do some action on the website that results in allocation of objects. Then you take another snapshot. When you compare both snapshots, you can see how many instances of classes were created between these two snapshots and how many were removed. If they are not equal, then you have leak. Generally in web application many objects are created on every page hit and the end of the request, all those objects are supposed to be released. If they are not released, then we have a problem. But that’s the scenario for desktop applications because in a desktop application, objects can remain in memory until app is closed. But you should know best from the code which objects were supposed to go out of scope and get released.  
For beginners, leak means objects are being allocated but not being freed because someone is holding reference to the objects. When objects leak, they remain in memory forever, until the process (or app domain) is closed. So, if you have a leaky website, your website is continuously taking up memory until it runs out of memory on the web server and thus crash. So, memory leak is a bad – it prevents you from running your product for long duration and requires frequent restart of app pool.   
So, the above screenshot shows Workflow and Linq related classes are not being removed, and thus leaking. This means somewhere workflow instances are not being released and thus all workflow related objects are remaining. You can see the number is same 48 for all workflow related objects. This is a good indication that, almost every instance of workflow is leaked because there were total 48 workflows created and ran. Moreover it indicates we have a leak from a top Workflow instance level, not in some specific Activity or somewhere deep in the code.  
As the workflows use Linq stuff, they held reference to the Linq stuffs and thus the Linq stuffs leaked as well. Sometimes you might be looking for why A is leaking. But you actually end up finding that since B was holding reference to A and B was leaking and thus A was leaking as well. This is sometimes tricky to figure out and you spend a lot of time looking at the wrong direction.  
Now let me show you the buggy code:  ManualWorkflowSchedulerService manualScheduler = 
  workflowRuntime.GetService&amp;lt;ManualWorkflowSchedulerService&amp;gt;();

WorkflowInstance...&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=-LIRJgSGBXo:uk3bMbquKhU:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=-LIRJgSGBXo:uk3bMbquKhU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=-LIRJgSGBXo:uk3bMbquKhU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=-LIRJgSGBXo:uk3bMbquKhU:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/-LIRJgSGBXo" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/dddCH2jA0Qk/optimize-asp-net-membership-stored-procedures-for-greater-speed-and-scalability.aspx"&gt;Optimize ASP.NET Membership Stored Procedures for greater speed and scalability&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Friday, March 13, 2009&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds.feedburner.com/OmarAlZabirBlog" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;Last year at Pageflakes, when we were getting millions of hits per day, we were having query timeout due to lock timeout and Transaction Deadlock errors. These locks were produced from aspnet_Users and aspnet_Membership tables. Since both of these tables are very high read (almost every request causes a read on these tables) and high write (every anonymous visit creates a row on aspnet_Users), there were just way too many locks created on these tables per second. SQL Counters showed thousands of locks per second being created. Moreover, we had queries that would select thousands of rows from these tables frequently and thus produced more locks for longer period, forcing other queries to timeout and thus throw errors on the website.

If you have read my last blog post, you know why such locks happen. Basically every table when it grows up to hold millions of records and becomes popular goes through this trouble. It&amp;rsquo;s just a part of scalability problem that is common to database. But we rarely take prevention about it in our early design.

The solution is simple, you should either have WITH (NOLOCK) or SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED before SELECT queries. Either of this will do. They tell SQL Server not to hold any lock on the table while it is reading the table. If some row is locked while the read is happening, it will just ignore that row. When you are reading a table thousand times per second, without these options, you are issuing lock on many places around the table thousand times per second. It not only makes read from table slower, but also so many lock prevents insert, update, delete from happening timely and thus queries timeout. If you have queries like &amp;ldquo;show the currently online users from last one hour based on LastActivityDate field&amp;rdquo;, that is going to issue such a wide lock that even other harmless select queries will timeout. And did I tell you that there&amp;rsquo;s no index on LastActivityDate on aspnet_Users table?

Now don&amp;rsquo;t blame yourself for not putting either of these options on your every stored proc and every dynamically generated SQL from the very first day. ASP.NET developers made the same mistake. You won&amp;rsquo;t see either of these used in any of the stored procs used by ASP.NET Membership. For example, the following stored proc gets called whenever you access Profile object:
ALTER PROCEDURE [dbo].[aspnet_Profile_GetProperties]
    @ApplicationName      nvarchar(256),
    @UserName             nvarchar(256),
    @CurrentTimeUtc       datetime
AS
BEGIN

    DECLARE @ApplicationId uniqueidentifier
    SELECT  @ApplicationId = NULL
    SELECT  @ApplicationId = ApplicationId FROM 
      dbo.aspnet_Applications WHERE LOWER(@ApplicationName) = LoweredApplicationName
    IF (@ApplicationId IS NULL)
        RETURN

    DECLARE @UserId uniqueidentifier
    DECLARE @LastActivityDate datetime
    SELECT  @UserId = NULL

    SELECT @UserId = UserId, @LastActivityDate = LastActivityDate
    FROM...&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=dddCH2jA0Qk:tbN1TJrDKSA:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=dddCH2jA0Qk:tbN1TJrDKSA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=dddCH2jA0Qk:tbN1TJrDKSA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=dddCH2jA0Qk:tbN1TJrDKSA:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/dddCH2jA0Qk" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feedproxy.google.com/~r/OmarAlZabirBlog/~3/zpw40Zu0jms/linq-to-sql-solve-transaction-deadlock-and-query-timeout-problem-using-uncommitted-reads.aspx"&gt;Linq to SQL solve Transaction deadlock and Query timeout problem using uncommitted reads&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Saturday, March 07, 2009&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds.feedburner.com/OmarAlZabirBlog" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;When your database tables start accumulating thousands of rows and many users start working on the same table concurrently, SELECT queries on the tables start producing lock contentions and transaction deadlocks. This is a common problem in any high volume website. As soon as you start getting several concurrent users hitting your website that results in SELECT queries on some large table like aspnet_users table that are also being updated very frequently, you end up having one of these errors:     
Transaction (Process ID ##) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.    
Or,     
Timeout Expired. The Timeout Period Elapsed Prior To Completion Of The Operation Or The Server Is Not Responding.    
The solution to these problems are – use proper index on the table and use transaction isolation level Read Uncommitted or WITH (NOLOCK) in your SELECT queries. So, if you had a query like this:  SELECT * FORM aspnet_users 
where ApplicationID =’xxx’ AND LoweredUserName = &amp;#39;someuser&amp;#39;


You should end up having any of the above errors under high load. There are two ways to solve this:

SET TRANSACTION LEVEL READ UNCOMMITTED;
SELECT * FROM aspnet_Users 
WHERE ApplicationID =’xxx’ AND LoweredUserName = &amp;#39;someuser&amp;#39;





Or use the WITH (NOLOCK):

SELECT * FROM aspnet_Users WITH (NOLOCK) 
WHERE ApplicationID =’xxx’ AND LoweredUserName = &amp;#39;someuser&amp;#39;


The reason for the errors are that since aspnet_users is a high read and high write table, during read, the table is partially locked and during write, it is also locked. So, when the locks overlap on each other from several queries and especially when there’s a query that’s trying to read a large number of rows and thus locking large number of rows, some of the queries either timeout or produce deadlocks.


Linq to Sql does not produce queries with the WITH (NOLOCK) option nor does it use READ UNCOMMITTED. So, if you are using Linq to SQL queries, you are going to end up with any of these problems on production pretty soon when your site becomes highly popular.


For example, here’s a very simple query:

using (var db = new DropthingsDataContext())
{
    var user = db.aspnet_Users.First();
    var pages = user.Pages.ToList();
}


DropthingsDataContext is a DataContext built from Dropthings database.


When you attach SQL Profiler, you get this:


 


You see none of the queries have READ UNCOMMITTED or WITH (NOLOCK). 


The fix is to do this:

using (var db = new DropthingsDataContext2())
{
    db.Connection.Open();
    db.ExecuteCommand(&amp;quot;SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;&amp;quot;);

    var user = db.aspnet_Users.First();
    var pages = user.Pages.ToList();
}


This will result in the following profiler output



 


As you see, both queries execute within the same connection and the isolation level is set before the queries execute. So, both queries enjoy the isolation level.


Now there’s a...&lt;br/&gt;
&lt;br/&gt;
Visit my Blog for more details.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:D7DqB2pKExk"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=zpw40Zu0jms:EGhEU2SFyWQ:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=zpw40Zu0jms:EGhEU2SFyWQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:TzevzKxY174"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?i=zpw40Zu0jms:EGhEU2SFyWQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?a=zpw40Zu0jms:EGhEU2SFyWQ:l6gmwiTKsz0"&gt;&lt;img src="http://feeds2.feedburner.com/~ff/OmarAlZabirBlog?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/OmarAlZabirBlog/~4/zpw40Zu0jms" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feeds.feedburner.com/~r/OmarAlZabirBlog/~3/496361529/strongly-typed-workflow-input-and-output-arguments.aspx"&gt;Strongly typed workflow input and output arguments&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Saturday, December 27, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds.feedburner.com/OmarAlZabirBlog" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;&lt;p&gt;When you run a &lt;u&gt;Workflow&lt;/u&gt; using Workflow Foundation, you pass arguments to the workflow in a &lt;u&gt;Dictionary&lt;/u&gt; form where the type of Dictionary is &lt;u&gt;Dictionary&amp;lt;string, object&amp;gt;&lt;/u&gt;. This means you miss the strong typing features of .NET languages. You have to know what arguments the workflow expects by looking at the &lt;u&gt;Workflow&lt;/u&gt; public properties. Moreover, there’s no way to make arguments required. You pass parameter, expect it to run, if it throws exception, you pass more arguments, hope it works now. Similarly, if you are running workflow synchronously using &lt;u&gt;ManualWorkflowSchedulerService&lt;/u&gt;, you expect return arguments from the Workflow immediately, but there again, you have to rely on the &lt;u&gt;Dictionary&lt;/u&gt; key and value pair. No strong typing there as well.&lt;/p&gt;  &lt;p&gt;In order to solve this, so that you could pass Workflow arguments as strongly typed classes, you can establish a format that every &lt;u&gt;Workflow&lt;/u&gt; has only two arguments named &amp;quot;Request” and “Response” and none other. Whatever needs to be passed to the &lt;u&gt;Workflow&lt;/u&gt; and expected out of it, must be passed via Request and must be expected via Response properties. Now the type of these arguments can be workflow specific, it can be any class with one or more parameters. This way, you could write code like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_0C53CAC7.png"&gt;&lt;img title="Running workflow with strongly typed argument" style="border-right:0px;border-top:0px;display:inline;border-left:0px;border-bottom:0px;" height="100" alt="Running workflow with strongly typed argument" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_0166C3B2.png" width="657" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The advantages of these strongly typed approach are: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Compile time validation of input parameters passed to workflow. No risk of passing unexpected object in Dictionary’s &lt;u&gt;object&lt;/u&gt; type value.&lt;/li&gt;    &lt;li&gt;Enforce required values by creating Request objects with non-default constructor.&lt;/li&gt;    &lt;li&gt;Establish a fixed contract for Workflow input and output via the strongly typed Request and Response classes or interfaces.&lt;/li&gt;    &lt;li&gt;Validate input arguments for the Workflow directly from the Request class, without going through the overhead of running a workflow.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;If we follow this approach, we create workflows with only two &lt;u&gt;DependencyProperty&lt;/u&gt;, one for &lt;u&gt;Request&lt;/u&gt; and one for &lt;u&gt;Response&lt;/u&gt;. Showing you an example from my open source project &lt;a title="Dropthings - Open Source AJAX Start Page" href="http://www.codeplex.com/dropthings" target="_blank"&gt;Dropthings&lt;/a&gt;, which uses Workflow for the entire Business Layer. Below you see the Workflow that executes when a new user visits &lt;a title="Dropthings - an Open Source AJAX Start Page" href="http://www.dropthings.com" target="_blank"&gt;Dropthings.com&lt;/a&gt;, creates a new user and setups all the pages and widgets for the user. It has only two &lt;u&gt;Dependency&lt;/u&gt; property – Request and Response.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_4C29C31A.png"&gt;&lt;img title="image" style="display:inline;" height="547" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_1A4E5A2B.png" width="595" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;The Request parameters is of type &lt;u&gt;IUserVisitWorkflowRequest&lt;/u&gt;. So, you can pass any class as Request argument that implements the interface. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_65BD6215.png"&gt;&lt;img title="image" style="display:inline;" height="69" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_152BD0E2.png" width="637" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Here I have used fancy inheritance to create Request object hierarchy. You don’t need to do that. Just remember, you can pass any class. You don’t even need to use interface for Request parameter. It can be a class directly. I use all these interfaces in order to facilitate Dependency Inversion.&lt;/p&gt;  &lt;p&gt;Similarly, the Response object is also a class.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_366B2AE4.png"&gt;&lt;img title="image" style="display:inline;" height="117" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_23F2B462.png" width="656" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The Response returns quite some properties. So, it’s kinda handy to wrap them all in one property.&lt;/p&gt;  &lt;p&gt;So, there you have it, strongly typed Workflow arguments. You can attach properties of the Request object to any activity directly form the designer:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_6B37E487.png"&gt;&lt;img title="image" style="display:inline;" height="520" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_2B2E2875.png" width="534" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;There’s really no compromise to make in this approach. Everything works as before.&lt;/p&gt;  &lt;p&gt;In order to make workflow execution simpler, I use a helper method like the following, that takes the Request and Response object and creates the Dictionary for me. This Dictionary always contains one “Request” and one “Response” entry.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_066CEB31.png"&gt;&lt;img title="image" style="display:inline;" height="196" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_6A7BB638.png" width="498" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;This way, I can run Workflow in strongly typed fashion:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_6DA8C87A.png"&gt;&lt;img title="image" style="display:inline;" height="144" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_3DFA8421.png" width="646" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Here I can specify the Request, Response and Workflow type using strong typing. This way I get strongly typed return object as well as pass strongly type Request object. There’s no dictionary building, no risky string key and object type value passing.&amp;#160; You can ignore the &lt;u&gt;ObjectContainer.Resolve()&lt;/u&gt; stuff, because that’s just returning me an existing reference of &lt;u&gt;WorkflowRuntime&lt;/u&gt;.&lt;/p&gt;  &lt;p&gt;Hope you like this approach.&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="text-align:left;margin:0px;padding:4px 4px 4px 4px;"&gt;&lt;script type="text/javascript"&gt;var dzone_url = &amp;#39;http://msmvps.com/blogs/omar/archive/2008/12/27/strongly-typed-workflow-input-and-output-arguments.aspx&amp;#39;;&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = &amp;#39;Strongly typed workflow input and output arguments&amp;#39;;&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = &amp;#39;Strongly typed workflow input and output arguments&amp;#39;;&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = &amp;#39;2&amp;#39;;&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt; &lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1657833" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=YQGQo"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=YQGQo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=BGLLO"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=BGLLO" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=Wykfo"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=Wykfo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=lClvO"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=lClvO" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=HLyPO"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=HLyPO" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=ePnhO"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=ePnhO" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=G0P3o"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=G0P3o" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=OLt9O"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=OLt9O" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OmarAlZabirBlog/~4/496361529" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feeds.feedburner.com/~r/OmarAlZabirBlog/~3/480637227/99-99-available-asp-net-and-sql-server-saas-production-architecture.aspx"&gt;99.99% available ASP.NET and SQL Server SaaS Production Architecture&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Wednesday, December 10, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds.feedburner.com/OmarAlZabirBlog" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;&lt;p&gt;You have a hot ASP.NET+SQL Server product, growing at thousand users per day and you have hit the limit of your own garage hosting capability. Now that you have enough VC money in your pocket, you are planning to go out and host on some real hosting facility, maybe a colocation or managed hosting. So, you are thinking, how to design a physical architecture that will ensure performance, scalability, security and availability of your product? How can you achieve four-nine (99.99%) availability? How do you securely let your development team connect to production servers? How do you choose the right hardware for web and database server? Should you use Storage Area Network (SAN) or just local disks on RAID? How do you securely connect your office computers to production environment?&lt;/p&gt;
&lt;p&gt;Here I will answer all these queries. Let me first show you a diagram that I made for &lt;a href="http://www.pageflakes.com"&gt;Pageflakes&lt;/a&gt; where we ensured we get four-nine availability. Since Pageflakes is a &lt;a href="http://en.wikipedia.org/wiki/Software_as_a_service"&gt;Level 3 SaaS&lt;/a&gt;, it&amp;rsquo;s absolutely important that we build a high performance, highly available product that can be used from anywhere in the world 24/7 and end-user gets quick access to their content with complete personalization and customization of content and can share it with others and to the world. So, you can take this production architecture as a very good candidate for Level 3 SaaS: &lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/Hosting_5F00_environment_5F00_7C36AD9E.png"&gt;&lt;img title="Hosting_environment" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Hosting_environment" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/Hosting_5F00_environment_5F00_thumb_5F00_45D55FC2.png" border="0" height="832" width="600" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a CodeProject article that explains all the ideas:&lt;/p&gt;
&lt;p&gt;&lt;a title="99.99% available ASP.NET and SQL Server SaaS Production Architecture" href="http://www.codeproject.com/KB/aspnet/ProdArch.aspx" target="_blank"&gt;99.99% available ASP.NET and SQL Server SaaS Production Architecture&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hope you like it. Appreciate your vote.&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="scid:B3E14793-948F-49af-A347-D19C374A7C4F:25404c3d-2014-4892-a108-bf1cfc5d1ff8" style="padding-right:0px;display:inline;padding-left:0px;float:none;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;
&lt;/div&gt;
&lt;div class="wlWriterHeaderFooter" style="text-align:left;margin:0px;padding:4px 4px 4px 4px;"&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f12%2f10%2f99-99-available-asp-net-and-sql-server-saas-production-architecture.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f12%2f10%2f99-99-available-asp-net-and-sql-server-saas-production-architecture.aspx" alt="kick it on DotNetKicks.com" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1656383" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=1JfSo"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=1JfSo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=keukO"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=keukO" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=SorCo"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=SorCo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=mD4pO"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=mD4pO" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=Pis8O"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=Pis8O" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=VfdAO"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=VfdAO" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=uvMeo"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=uvMeo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=w6DfO"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=w6DfO" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OmarAlZabirBlog/~4/480637227" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feeds.feedburner.com/~r/OmarAlZabirBlog/~3/436611189/linq-to-sql-delete-an-entity-using-primary-key-only.aspx"&gt;Linq to SQL: Delete an entity using Primary Key only&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Thursday, October 30, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds.feedburner.com/OmarAlZabirBlog" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;&lt;p&gt;Linq to Sql does not come with a function like &lt;span style="text-decoration:underline;"&gt;.Delete(ID)&lt;/span&gt; which allows you to delete an entity using it&amp;rsquo;s primary key. You have to first get the object that you want to delete and then call &lt;span style="text-decoration:underline;"&gt;.DeleteOnSubmit(obj)&lt;/span&gt; to queue it for delete. Then you have to call &lt;span style="text-decoration:underline;"&gt;DataContext.SubmitChanges()&lt;/span&gt; to play the delete queries on database. So, how to delete object without getting them from database and avoid database roundtrip?&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_600F7C48.png"&gt;&lt;img title="Delete an object without getting it - Linq to Sql" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Delete an object without getting it - Linq to Sql" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_7AABF294.png" border="0" height="168" width="486" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;You can call this function using &lt;span style="text-decoration:underline;"&gt;DeleteByPK&amp;lt;Employee, int&amp;gt;(10, dataContext);&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;First type is the entity type and second one is the type of the primary key. If your object&amp;rsquo;s primary key is a &lt;span style="text-decoration:underline;"&gt;Guid&lt;/span&gt; field, specify &lt;span style="text-decoration:underline;"&gt;Guid&lt;/span&gt; instead of &lt;span style="text-decoration:underline;"&gt;int&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;How it works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It figures out the table name and the primary key field name from the entity &lt;/li&gt;
&lt;li&gt;Then it uses the table name and primary key field name to build a DELETE query &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Figuring out the table name and primary key field name is a bit hard. There&amp;rsquo;s some reflection involved. The &lt;span style="text-decoration:underline;"&gt;GetTableDef&amp;lt;TSource&amp;gt;()&lt;/span&gt; returns the table name and primary key field name for an entity.&lt;/p&gt;
&lt;p&gt;Every Linq Entity class is decorated with a &lt;span style="text-decoration:underline;"&gt;Table&lt;/span&gt; attribute that has the table name:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_3E337DEA.png"&gt;&lt;img title="Lint entity declaration" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Lint entity declaration" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_3AD1E642.png" border="0" height="67" width="551" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Then the primary key field is decorated with a &lt;span style="text-decoration:underline;"&gt;Column&lt;/span&gt; attribute with &lt;span style="text-decoration:underline;"&gt;IsPrimaryKey = true&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_7C1CE8DB.png"&gt;&lt;img title="Primary Key field has Column attribute with IsPrimaryKey = true" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Primary Key field has Column attribute with IsPrimaryKey = true" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_031BD9BA.png" border="0" height="77" width="709" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;So, using reflection we can figure out the table name and the primary key property and the field name.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the code that does it:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_600B6849.png"&gt;&lt;img title="Using reflection find the Table attribute and the Column attribute" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Using reflection find the Table attribute and the Column attribute" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_722FCF72.png" border="0" height="615" width="685" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Before you scream &amp;ldquo;Reflection is SLOW!!!!&amp;rdquo; the definition is cached. So, reflection is used only once per appDomain per entity. Subsequent call is just a dictionary lookup away, which is as fast as it can get.&lt;/p&gt;
&lt;p&gt;You can also delete a collection of object without ever getting any one of them. The the following function to delete a whole bunch of objects:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_57CF1AB4.png"&gt;&lt;img title="Delete a list of objects using Linq to SQL" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Delete a list of objects using Linq to SQL" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_3925043E.png" border="0" height="398" width="553" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;The code is available here:&lt;/p&gt;
&lt;p&gt;&lt;a title="http://code.msdn.microsoft.com/DeleteEntitiesLinq" href="http://code.msdn.microsoft.com/DeleteEntitiesLinq"&gt;http://code.msdn.microsoft.com/DeleteEntitiesLinq&lt;/a&gt;&lt;/p&gt;
&lt;div class="wlWriterHeaderFooter" style="text-align:left;margin:0px;padding:4px 4px 4px 4px;"&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f10%2f30%2flinq-to-sql-delete-an-entity-using-primary-key-only.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f10%2f30%2flinq-to-sql-delete-an-entity-using-primary-key-only.aspx" alt="kick it on DotNetKicks.com" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1652462" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=vrwqm"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=vrwqm" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=ZAMvM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=ZAMvM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=NPYcm"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=NPYcm" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=60PIM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=60PIM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=hnxWM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=hnxWM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=9j9nM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=9j9nM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=NBG3m"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=NBG3m" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=NILoM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=NILoM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OmarAlZabirBlog/~4/436611189" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feeds.feedburner.com/~r/OmarAlZabirBlog/~3/433614202/how-to-convince-developers-and-management-to-use-automated-unit-test-for-ajax-websites.aspx"&gt;How to convince developers and management to use automated unit test for AJAX websites&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Monday, October 27, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds.feedburner.com/OmarAlZabirBlog" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;&lt;p&gt;Everyone agrees that unit testing is a good thing, we should all write unit tests. We read articles and blogs to keep us up-to-date on what’s going on in the unit test world so that we can sound cool talking to peers at lunch. But when we really sit down and try to write unit tests ourselves – “Naaah, this is waste of time, let’s ask my QA to test it; that’s much more reliable and guaranteed way to test this. What’s the point testing these functions when there are so many other functions that we should unit test first?” Had such moment yourself or with someone else? Read on.&lt;/p&gt;  &lt;p&gt;I had a conversation with our development lead Mike (using a highly generic name since my &lt;a title="Tips and Tricks to rescue overdue projects" href="http://msmvps.com/blogs/omar/archive/2008/10/20/tips-and-tricks-to-rescue-overdue-projects.aspx"&gt;last post&lt;/a&gt; caused some trouble), who runs “the show” in our engineering team. As usual there was reservation in introducing unit test to regular development schedule. Mike also had valid points about lack of powerful tools for doing unit test on AJAX websites. He also had confusion on ‘what’ and ‘how’ to unit test our code so that we aren’t just testing database failures but real user actions that executes both business and rendering logics. So, the discussion has a lot of useful information, that will help you take the right decision when you want to sell unit test to your ASP.NET and/or AJAX development team and finally to higher management so that you can buy enough time for the effort.&lt;/p&gt;  &lt;p&gt;&lt;u&gt;Friday, Jan 2007 – hallway&lt;/u&gt;&lt;strong&gt;      &lt;br /&gt;Omar&lt;/strong&gt;: Hey Mike, we need to start doing unit testing at least on our web services. We are wasting way too much time on manual QA. Since we are an AJAX shop, unit testing all our web services should give us pretty well coverage. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: Sure, that sounds fun. I will do some feasibility check and see how can we chip this in into our next sprint.&lt;/p&gt;  &lt;p&gt;&lt;u&gt;Friday, Feb 2007 – washroom&lt;/u&gt;&amp;#160; &lt;br /&gt;&lt;strong&gt;Omar&lt;/strong&gt;: Hey Mike, let’s start doing unit tests. I haven’t seen any tests last month. Can we start from this sprint?&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: Sure, we can surely start from this sprint. Let me find out which tool is the right one for us.&lt;/p&gt;  &lt;p&gt;&lt;u&gt;Friday, March 2007 – meeting room&lt;/u&gt;     &lt;br /&gt;&lt;strong&gt;Omar&lt;/strong&gt;: Hey Mike, haven’t seen any unit tests in the solution so far. Let’s seriously start writing unit tests. Did you make any plan how you want to start unit testing the webservices?&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: Yeah, I did some digging around and found some tools. But most of them are for non-AJAX sites where you can programmatically hit a URL or programmatically do HTTP POST on a URL. You can also record button clicks and form posts from the browser. There’s &lt;a title="Introduction to Visual Studio Web Test" href="http://msdn.microsoft.com/en-us/library/ms364077.aspx"&gt;Visual Studio’s Web Test&lt;/a&gt;, which does pretty good job recording regular ASP.NET site, but poor on AJAX sites. Moreover, you need to buy Team Suite edition to get that Web Test feature. Besides, recording tests and playing them back really does not help us because all those tests contain hard coded data. We can’t repeat a particular step many times with random data, at least not using any off-the-shelf tools. We need to test things carefully and systematically using random data set and sometimes use real data from database. For example, a common scenario is loading 100 random user accounts from database and programmatically log those users into their portal and test whether the portal shows those users’ personalized data. All these need to be done from AJAX, without using any browser redirect or form post, because there’s one page that allows user to login using Ajax call and then dynamically renders the portal on the same page after successful login. The UI is rendered by Javascript, so only a real browser can render it and we have to test the output looking at the browser.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: I see, so you can’t use Visual Studio Web Test to run unit tests on a browser because it does not let you access the html that browser renders. You can only test the html that’s returned by webserver. As we are AJAX website, most of our stuffs are done by Javascripts – they call Webservice and they render the UI. Hmm, thinking how we can do this using VS. We can at least hit the webservices and see if they are returning the right JSON. This way we can pretty much test the entire webservice, business and data access layer. But it does not really replace the need&amp;#160; for manual QA since there’s a lot of rendering logic in Javascript.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: Now there’s a new project called &lt;a title="Watin - browser based web test" href="http://watin.sourceforge.net/"&gt;Watin&lt;/a&gt; that seems promising. You can write C# code to instruct a browser to do stuffs like click on a button, run some javascript and then you can check what the browser rendered in its DOM and run your tests. But still, it’s in its infancy. So, there’s really no good tool for unit testing AJAX sites. Let’s stick to manual QA, which is proven to be more accurate than anything developers can come up with. We can handover a set of data to QA and ask them to enter and check the result.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: We definitely need to figure out ways to reduce our dependency on manual QA. It simply does not scale. Every sprint, we have to freeze code and then hand over to QA. They run their gigantic test scripts for a whole day. Then next day, we get bug reports to fix. If there’s severe regression bug we have to either cancel sprint or work whole night to fix it and run overnight QA to meet deployment date. For last one year, every sprint we ended up having some bug that made dev and QA work over night. We have to empower our developers with automated unit test tool so that they can run the whole regression test script automatically.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: You are talking about a very long project then. Writing so many unit tests for complete regression test is going to be more than a month long project. We have to find the right set of tool, plan what areas to unit test and how, then engage both dev and QA to work together and prepare the right tests. And then we have to keep the test suite up-to-date after every sprint to catch the new bugs and features.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: Yes, this is certainly a complex project. We have to get to a stage that can empower a developer to run automated unit tests and not ask QA to test every task for regression bugs. In fact, we should have automated build that runs all unit tests and does the regression test for us automatically after every checkin. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: We have automated build and deploy. So, that’s done. We need to add automated unit test to it. Seriously, given our product size, this is absolutely impossible to engage in writing so many unit tests so that we can do the entire regression test automatically. It’s not worth the time and money. Our QA team is doing fine. They can take one day leave after deployment when they do overnight work.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: Actually QA team is at the edge of quitting. They seem to have endless work load. After deployment, they have to do manual regression test on production site to ensure nothing broke on production. While they are at it, they have to participate in sprint initiation meetings and write test plans. When they are about to complete that, devs checkin stuffs and ask for regression test of different modules. Before they can finish that , we reach code freeze and they have to finish all those task level tests as well as the entire regression test. So, they end up working round-the-clock several days every sprint. They simply can’t take it anymore.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: How is it different than our life? After spending sleepless night on the deployment date, next day we have to attend 8 hours long sprint planning meeting. Then we have to immediately start working on the tasks from the next day and have to reach code-freeze within a week. Then QA comes up with so many bugs at the last moment. We have to work round-the-clock last 3 days of sprint to get those bugs fixed. Then after a nerve wrecking deployment day, we have to stay up at night to wait for QA to report any critical bug and fix it immediately on production. We are at the brink of destruction as well.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: That’s understood. The whole team is surely getting pushed to their limit. So, that’s why we urgently need automated test so that it addresses the problems of both dev and QA team. Dev will get tests done at a faster rate so that they don’t get bug reports at the very end and then work over-night to fix them. Similarly, we offload QA team’s continuous overwork by letting the system do the bulk of their test. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: This is going to kill the team for sure. We have so many product features and bug fixes to do every sprint. Now, if we ask everyone to start writing unit tests for every task they do, it’s a lot of burden. We can’t do both at the same time.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: Agree. We have to cut down product features or bug fixes. We have to make room in every sprint to write unit tests.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: Good luck with that. Let’s see how you convince product team.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: First let me convince you. Are you convinced that we should do it.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: Not yet. I don’t really see its fruit in near future, even after two months. There’s so many features we have to do and so many customers to ship to, we just can’t do enough unit tests that will really shed off QA load. It’ll just be a distraction and delay in every sprint, heck, in every task.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: Let me show you a graph which I believe is going to make an impact:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Howtowriteusefulunittest.NETAJAXwebsites_5F00_A4C6/image_5F00_2.png"&gt;&lt;img title="image" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="241" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Howtowriteusefulunittest.NETAJAXwebsites_5F00_A4C6/image_5F00_thumb.png" width="387" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;So, you see the more automates test we write, the less time spent on Manual QA. That time can be spent on doing new tests or task level tests and increase quality of every new feature shipped and drastically reduce new bugs shipped to production. Thus we get less and less bugs after every successful sprint.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: Ya, I get it, you don’t need to convince me for this. But I don’t see the benefit from overall gain perspective. Are we shipping better product faster over next two months? We aren’t. We are shipping less features and bug fixes by spending a lot of time on writing unit tests that has no impact on end-user. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: Let me see if your assumption is correct:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Howtowriteusefulunittest.NETAJAXwebsites_5F00_A4C6/image_5F00_4.png"&gt;&lt;img title="image" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="244" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Howtowriteusefulunittest.NETAJAXwebsites_5F00_A4C6/image_5F00_thumb_5F00_1.png" width="453" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;You see here, the more automated tests kick in, the more time QA can spend on new features or new bugs. I agree that the speed of testing new features/bugs decrease first one or two sprints, but then they gradually get picked up and get even better. In the beginning, there’s a big overhead of getting started with automated test. But as sprints go by, the number of unit tests to write gradually gets stable and soon it becomes proportional to new features/bugs. No more time spent on writing tests for old stuff. So, the number of unit tests you write after four sprints is exactly what needed for the new tasks you did on that sprint.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: Let’s see what if we just don’t do any automated test and keep things manual. How does the graph look like?&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Howtowriteusefulunittest.NETAJAXwebsites_5F00_A4C6/image_5F00_10.png"&gt;&lt;img title="image" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="277" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Howtowriteusefulunittest.NETAJAXwebsites_5F00_A4C6/image_5F00_thumb_5F00_4.png" width="423" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: The future looks quite gloomy. We will be spending so much time on regression test as we keep adding stuffs to the product that at some point QA will end up doing regression test full time. They will not spend time on new features and we will end up having a lot more new bugs slipped from QA to production due to lack of attention from QA.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: OK, how do we start?&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: First step is to get the regression tests done so that we can get rid of that 24 hour long marathon QA period end of every sprint. Moreover, I see too many devs asking QA to do regression test here and there after they commit some tasks. So, QA is always doing regression tests from the beginning to the end of each sprint. They should only test new things for which automated test is not yet written and let the automated test do the existing tests. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: This will be hard to sell to management. We are going to say “Look for next one month, we will be half productive because we want to spend time automating our QA process so that from second month, we can do tests automatically and QA can have more free time.”&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: No, we say it like this, “We are going to spend 50% of our time automating QA for next oen month so that QA can spend 50% more time on testing new features. This will prevent 50% new bugs from occurring every sprint. This will give developers 50% more time to build new features after one month.” We show them this graph:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Howtowriteusefulunittest.NETAJAXwebsites_5F00_A4C6/image_5F00_12.png"&gt;&lt;img title="image" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="279" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Howtowriteusefulunittest.NETAJAXwebsites_5F00_A4C6/image_5F00_thumb_5F00_5.png" width="406" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: Seems like this will sell. But for first couple of sprints, we will be so dead slow that some of us might get fired. Think about it, from management point of view, the development team has suddenly become half productive. They aren’t building only few new features and bugs are not getting fixed as fast rate. Customer are screaming, investors asking for money back. It’s going to get really dirty. Do you want to take this risk? &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: I can see that this decision is a very hard decision to take. I know what CEO will say, “We need to be double productive from tomorrow, otherwise we might as well pack our bags and go home. Tell me something that will make us double productive from tomorrow, not half productive.” But you can see what will happen after couple of months. Situation will be so bad that doing this after couple of months will be out of question. We won’t be in a position to even propose this. Now, at least we can argue and they still have the mind to listen to long term ideas. But in future, when our QA team is doing full time regression test, new buggy features going to production, ratio of new bugs increasing after every release, more customers screaming, half baked features running on the production – we might have to shut down the company to save our life. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: We should have started doing automated tests from day one.&lt;/p&gt;  &lt;p&gt;Omar: Yes, unfortunately we haven’t and the more we delay, the harder it is going to get. I am sure we will write automated tests from day one in our next project, but we have to rescue this project.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: OK, I am sold. How do we start? We surely need to unit test the business and data access layer. Do we start writing unit test for every function in DAL and Business layer?&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: Writing unit test for DAL seems pointless to me. Remember, we have very little time. We will get max two sprints to automate unit tests. After that, we won’t get the luxury to spend half of our time writing unit tests. We will have to go back to our feature and bug fix mode. So, let’s spend the time wisely. How about we only test the business layer function?&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: So, we test functions like CreateCustomer, EditCustomer, DeleteCustomer, AddNewOrder in business layer?&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: Is that the final layer in business layer? Is there another high level layer that aggregates such CRUD like functions?&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: For many areas, it’s like CRUD, a dumb wrapper on DAL with some minor validation and exception handling. But there are places where there are complex functions that do a lot of different DAL call. For example, UpdateCustomerBalance – that calls a lot of DAL classes to figure out customer’s current balance. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: Does webservices call multiple business classes? Do they act like another level that aggregates business layer?&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: Yes, webservices are called mostly from user actions and they generally call multiple business layer classes to get the job done.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: Where’s the caching done?&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: Webservice layer.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: That sounds like a good place to start unit testing. We will write small number of unit tests and still test majority of business layer and data access classes and we ensure validation, caching, exception handling code are working fine.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: But there are other tools and services that call the business layer. For example, we have a windows service running that directly calls the business layer. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: Can we refactor it to call webservices instead?&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: No, that’ll be like creating 10 more webservices. A lot more development effort. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: OK, let’s write unit tests for those business layer classes separately then. I suppose there will be some overlap. Some webservice call will test those business classes as well. But that’s fine. We *should be* unit testing from business layer. But we don’t have time, so we are starting from one level up. Webservices aren’t really “unit” but you have to do what you have to do. At least testing webservices will give us guarantee that we covered all user actions under unit test.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: Yes, testing webservices will at least ensure user actions are tested. The background windows service is not much of our headache. Now how do we test presentation logic? We have ASP.NET pages and there’s all those Javascript rendering code.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: Let’s use Watin for that. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: How to make that part of a unit test suite?&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: Watin integrates nicely with NUnit, mbUnit. mbUnit is pretty good. I used it before. It has more test attributes and Assert functions than NUnit.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: OK, so how do we unit test UI? A test function will click on Login link, fill up the email, password box and click “OK”. Then wait for one sec and then see if Javascript has rendered the UI correctly?&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: Something like that. We can discuss later exactly how we test it. But how do you test if UI is rendered correctly?&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: We check from browser’s DOM for user’s data like name, email, balance etc are available in browser’s HTML.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: Does that really test presentation logic? What if the data is misplaced? What if due to CSS error, it does not render correctly.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: Well, there’s really no way to figure it out if things are rendered correctly. We can ask the QA guys to keep watching the UI while Watin runs the tests on the browser. You can see on the browser what Watin is doing.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: OK, that’s one way and certainly faster than QA doing the whole step. But can it be done automatically like matching browser’s screen with some screenshot?&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: Yeah, we need AI for that.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: Seriously, can we write a simple UI capture and comparison tool? Say we take a screenshot of correct output and then clear up some areas which can vary. Then Watin runs the test, it takes the screenshot of current browser’s view and then matches with some screenshot? Here’s the idea:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Howtowriteusefulunittest.NETAJAXwebsites_5F00_A4C6/image_5F00_14.png"&gt;&lt;img title="image" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="308" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Howtowriteusefulunittest.NETAJAXwebsites_5F00_A4C6/image_5F00_thumb_5F00_6.png" width="586" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Say this is a template screenshot that we want to match with the browser. We are testing Google’s search result page to ensure the page always returns a particular result when we provide some predefined query. So, when Watin runs the test and takes browser to Google search result page, it takes a screenshot and ignores whatever is on those gray area. Then it does a pixel by pixel match on the rest of the template. So, no matter what the search query is and no matter what ad Google serves on top of results, as long as the first result is the one we are looking for, test passes.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: As I said, this is AI stuff. Some highly sophisticated being will be matching two screenshots to say, Yah, they more or less match, test pass.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: I think a pretty dumb bitmap matching will work in many cases. Just an idea, think about it. This way we can test if CSS is giving us pixel perfect result. QA takes a screenshot of expected output and then let the automated test to match with browser’s actual output.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: OK, all good ideas. Let’s see how much we can do. We will be starting from webservice unit testing. Then we will gradually move to Watin based testing. Now it’s time to sell this proposal to product team and then to management team.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: Yep, at least get the webservices tested, that will catch a lot of bugs before QA spends time on testing. Goal is to get as much testing done by developers, really fast, automatically then letting QA spend time on them.&amp;#160; Also we can run those webservice unit tests in a load test suite and load test the entire webservice layer. That’ll give us guaranty our code is production quality and it can survive the high traffic.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: Understood, see ya.&lt;/p&gt;  &lt;p&gt;. . .&lt;/p&gt;  &lt;p&gt;&lt;u&gt;March 2008, Friday - The Code Freeze Day&lt;/u&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: Hey Mike, how are we doing this sprint?&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Mike&lt;/strong&gt;: Pretty good. 3672 unit tests out of 3842 passed. We know why some of them failed. We can get them fixed pretty soon and run the complete regression tests once during lunch and once before we leave. QA has completed testing new features pretty well yesterday and they can check again today. We got some of the new features covered by unit tests as well. Rest we can finish next sprint, no worries. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Omar&lt;/strong&gt;: Excellent. Enjoy your weekend. See you on Monday.&lt;/p&gt;  &lt;p&gt;------------------------------&lt;/p&gt;  &lt;p&gt;Suggested Reading:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a title="Web Application testing in .Net - WatiN" href="http://watin.sourceforge.net/"&gt;Web Application testing in .Net - WatiN&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a title="Data Driven Web Testing With Visual Studio 2008 Team System" href="http://www.codeproject.com/KB/aspnet/VS08DataDrivenWebTests.aspx"&gt;Data Driven Web Testing With Visual Studio 2008 Team System&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a title="Sean Lumley’s blog on Visual Studio Web Test and Load Test" href="http://blogs.msdn.com/slumley/"&gt;Sean Lumley’s blog on Visual Studio Web Test and Load Test&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a title="Ed Gla’s Blog on VSTS Load Testing" href="http://blogs.msdn.com/edglas/"&gt;Ed Gla’s Blog on VSTS Load Testing&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a title="Bill Barnett’s Blog on Visual Studio Web Test and Load Test" href="http://blogs.msdn.com/billbar/"&gt;Bill Barnett’s Blog on Visual Studio Web Test and Load Test&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;&lt;div class="wlWriterHeaderFooter" style="text-align:left;margin:0px;padding:4px 4px 4px 4px;"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http://msmvps.com/blogs/omar/archive/2008/10/27/how-to-convince-developers-and-management-to-use-automated-unit-test-for-ajax-websites.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http://msmvps.com/blogs/omar/archive/2008/10/27/how-to-convince-developers-and-management-to-use-automated-unit-test-for-ajax-websites.aspx&amp;amp;bgcolor=0080C0&amp;amp;fgcolor=FFFFFF&amp;amp;border=000000&amp;amp;cbgcolor=D4E1ED&amp;amp;cfgcolor=000000" alt="DotNetKicks Image" border="0/" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1652113" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=h8uZm"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=h8uZm" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=w4MgM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=w4MgM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=5a2Bm"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=5a2Bm" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=xBMHM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=xBMHM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=isUFM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=isUFM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=rUhFM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=rUhFM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=iY3Hm"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=iY3Hm" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=2pc2M"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=2pc2M" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OmarAlZabirBlog/~4/433614202" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feeds.feedburner.com/~r/OmarAlZabirBlog/~3/436611190/solving-common-problems-with-compiled-queries-in-linq-to-sql-for-high-demand-asp-net-websites.aspx"&gt;Solving common problems with Compiled Queries in Linq to Sql for high demand ASP.NET websites&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Monday, October 27, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds.feedburner.com/OmarAlZabirBlog" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;&lt;p&gt;If you are using Linq to SQL, instead of writing regular Linq Queries, you should be using &lt;a href="http://linqinaction.net/blogs/jwooley/archive/2007/09/04/linq-to-sql-compiled-queries.aspx"&gt;Compiled Queries&lt;/a&gt;. if you are building an ASP.NET web application that&amp;rsquo;s going to get thousands of hits per hour, the execution overhead of Linq queries is going to consume too much CPU and make your site slow. There&amp;rsquo;s a runtime cost associated with each and every Linq Query you write. The queries are parsed and converted to a nice SQL Statement on *every* hit. It&amp;rsquo;s not done at compile time because there&amp;rsquo;s no way to figure out what you might be sending as the parameters in the queries during runtime. So, if you have common Linq to Sql statements like the following one throughout your growing web application, you are soon going to have scalability nightmares:&lt;/p&gt;
&lt;div&gt;
&lt;pre class="csharpcode"&gt;var query = from widget &lt;span class="kwrd"&gt;in&lt;/span&gt; dc.Widgets&lt;br /&gt;                &lt;span class="kwrd"&gt;where&lt;/span&gt; widget.ID == id &amp;amp;&amp;amp; widget.PageID == pageId&lt;br /&gt;                select widget;&lt;br /&gt;&lt;br /&gt;var widget = query.SingleOrDefault();&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;There&amp;rsquo;s &lt;a href="http://www.jdconley.com/blog/archive/2007/11/28/linq-to-sql-surprise-performance-hit.aspx"&gt;a nice blog post by JD Conley&lt;/a&gt; that shows how evil Linq to Sql queries are:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_03BBB56F.png"&gt;&lt;img title="image" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_481BA6AE.png" border="0" height="389" width="654" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You see how many times &lt;span style="text-decoration:underline;"&gt;SqlVisitor.Visit&lt;/span&gt; is called to convert a Linq Query to its SQL representation? The runtime cost to convert a Linq query to its SQL Command representation is just way too high.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/ricom/archive/2008/01/14/performance-quiz-13-linq-to-sql-compiled-query-cost-solution.aspx"&gt;Rico Mariani has a very informative performance comparison&lt;/a&gt; of regular Linq queries vs Compiled Linq queries performance:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_6C608B30.png"&gt;&lt;img title="image" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_3BEA06BA.png" border="0" height="252" width="531" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Compiled Query wins on every case.&lt;/p&gt;
&lt;p&gt;So, now you know about the benefits of compiled queries. If you are building ASP.NET web application that is going to get high traffic and you have a lot of Linq to Sql queries throughout your project, you have to go for compiled queries. Compiled Queries are built for this specific scenario. &lt;/p&gt;
&lt;p&gt;In this article, I will show you some steps to convert regular Linq to Sql queries to their Compiled representation and how to avoid the dreaded exception &amp;ldquo;&lt;b&gt;Compiled queries across DataContexts with different LoadOptions not supported.&amp;rdquo;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Here are some step by step instruction on converting a Linq to Sql query to its compiled form:&lt;/p&gt;
&lt;p&gt;First we need to find out all the external decision factors in a query. It mostly means parameters in the WHERE clause. Say, we are trying to get a user from &lt;span style="text-decoration:underline;"&gt;aspnet_users&lt;/span&gt; table using Username and Application ID:&lt;/p&gt;
&lt;div&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_674E27B4.png"&gt;&lt;img title="Query to get a user from aspnet_users table" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Query to get a user from aspnet_users table" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_66098ED5.png" border="0" height="57" width="544" /&gt;&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;Here, we have two external decision factor &amp;ndash; one is the Username and another is the Application ID. So, first think this way, if you were to wrap this query in a function that will just return this query as it is, what would you do? You would create a function that takes the &lt;span style="text-decoration:underline;"&gt;DataContext&lt;/span&gt; (dc named here), then two parameters named &lt;span style="text-decoration:underline;"&gt;userName&lt;/span&gt; and &lt;span style="text-decoration:underline;"&gt;applicationID,&lt;/span&gt; right?&lt;/p&gt;
&lt;p&gt;So, be it. We create one function that returns just this query:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_443DB644.png"&gt;&lt;img title="Converting a LInq Query to a function" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Converting a LInq Query to a function" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_4F1A978C.png" border="0" height="103" width="693" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Next step is to replace this function with a &lt;span style="text-decoration:underline;"&gt;Func&amp;lt;&amp;gt;&lt;/span&gt; representation that returns the query. This is the hard part. If you haven&amp;rsquo;t dealt with &lt;span style="text-decoration:underline;"&gt;Func&amp;lt;&amp;gt;&lt;/span&gt; and Lambda expression before, then I suggest you read &lt;a title="Lambda Expression" href="http://blogs.msdn.com/ericwhite/pages/Lambda-Expressions.aspx"&gt;this&lt;/a&gt; and &lt;a title="Lambda Expression" href="http://blah.winsmarts.com/2006/05/19/demystifying-c-30--part-4-lambda-expressions.aspx"&gt;this&lt;/a&gt; and then continue.&lt;/p&gt;
&lt;p&gt;So, here&amp;rsquo;s the delegate representation of the above function:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_262F8283.png"&gt;&lt;img title="Creating a delegate out of Linq Query" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Creating a delegate out of Linq Query" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_4F571AC1.png" border="0" height="114" width="573" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Couple of things to note here. I have declared the delegate as &lt;span style="text-decoration:underline;"&gt;static readonly&lt;/span&gt; because a compiled query is declared only once and reused by all threads. If you don&amp;rsquo;t declare Compiled Queries as static, then you don&amp;rsquo;t get the performance gain because compiling queries everytime when needed is even worse than regular Linq queries. &lt;/p&gt;
&lt;p&gt;Then there&amp;rsquo;s the complex &lt;span style="text-decoration:underline;"&gt;Func&amp;lt;DropthingsDataContext, string, Guid, IQueryable&amp;lt;aspnet_User&amp;gt;&amp;gt;&lt;/span&gt; thing. Basically the generic &lt;span style="text-decoration:underline;"&gt;Func&amp;lt;&amp;gt;&lt;/span&gt; is declared to have three parameters from the &lt;span style="text-decoration:underline;"&gt;GetQuery&lt;/span&gt; function and a return type of &lt;span style="text-decoration:underline;"&gt;IQueryable&amp;lt;aspnet_User&amp;gt;&lt;/span&gt;. Here the parameter types are specified so that the delegate is created strongly typed. &lt;span style="text-decoration:underline;"&gt;Func&amp;lt;&amp;gt;&lt;/span&gt; allows up to 4 parameters and 1 return type. &lt;/p&gt;
&lt;p&gt;Next comes the real business, compiling the query. Now that we have the query in delegate form, we can pass this to &lt;span style="text-decoration:underline;"&gt;CompiledQuery.Compile&lt;/span&gt; function which compiles the delegate and returns a handle to us. Instead of directly assigning the lambda expression to the func, we will pass the expression through the &lt;span style="text-decoration:underline;"&gt;CompiledQuery.Compile&lt;/span&gt; function.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_0D703573.png"&gt;&lt;img title="Converting a Linq Query to Compiled Query" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Converting a Linq Query to Compiled Query" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_093637E1.png" border="0" height="133" width="677" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s where head starts to spin. This is so hard to read and maintain. Bear with me. I just wrapped the lambda expression on the right side inside the &lt;span style="text-decoration:underline;"&gt;CompiledQuery.Compile&lt;/span&gt; function. Basically that&amp;rsquo;s the only change. Also, when you call &lt;span style="text-decoration:underline;"&gt;CompiledQuery.Compile&amp;lt;&amp;gt;&lt;/span&gt;, the generic types must match and be in exactly the same order as the &lt;span style="text-decoration:underline;"&gt;Func&amp;lt;&amp;gt;&lt;/span&gt; declaration.&lt;/p&gt;
&lt;p&gt;Fortunately, calling a compiled query is as simple as calling a function:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_42D8D1CB.png"&gt;&lt;img title="Running Compiled Query" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Running Compiled Query" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_3F773A23.png" border="0" height="89" width="716" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;There you have it, a lot faster Linq Query execution. The hard work of converting all your queries into Compiled Query pays off when you see the performance difference.&lt;/p&gt;
&lt;p&gt;Now, there are some challenges to Compiled Queries. Most common one is, what do you do when you have more than 4 parameters to supply to a Compiled Query? You can&amp;rsquo;t declare a &lt;span style="text-decoration:underline;"&gt;Func&amp;lt;&amp;gt;&lt;/span&gt; with more than 4 types. Solution is to use a &lt;span style="text-decoration:underline;"&gt;struct&lt;/span&gt; to encapsulate all the parameters. Here&amp;rsquo;s an example:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_2F87F55F.png"&gt;&lt;img title="Using struct in compiled query as parameter" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Using struct in compiled query as parameter" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_7CF4721F.png" border="0" height="245" width="736" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Calling the query is quite simple:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_7660F28F.png"&gt;&lt;img title="Calling compiled query with struct parameter" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Calling compiled query with struct parameter" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_575ACEF1.png" border="0" height="55" width="674" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now to the dreaded challenge of using &lt;span style="text-decoration:underline;"&gt;LoadOptions&lt;/span&gt; with Compiled Query. You will notice that the following code results in an exception:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_039755D6.png"&gt;&lt;img title="Using DataLoadOptions with Compiled Query" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Using DataLoadOptions with Compiled Query" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_2D4AAAFC.png" border="0" height="133" width="647" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The above &lt;span style="text-decoration:underline;"&gt;DataLoadOption&lt;/span&gt; runs perfectly when you use regular Linq Queries. But it does not work with compiled queries. When you run this code and the query hits the second time, it produces an exception:&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Compiled queries across DataContexts with different LoadOptions not supported&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;A compiled query remembers the &lt;span style="text-decoration:underline;"&gt;DataLoadOption&lt;/span&gt; once its called. It does not allow executing the same compiled query with a different &lt;span style="text-decoration:underline;"&gt;DataLoadOption&lt;/span&gt; again. Although you are creating the same &lt;span style="text-decoration:underline;"&gt;DataLoadOption&lt;/span&gt; with the same &lt;span style="text-decoration:underline;"&gt;LoadWith&amp;lt;&amp;gt;&lt;/span&gt; calls, it still produces exception because it remembers the exact instance that was used when the compiled query was called for the first time. Since next call creates a new instance of &lt;span style="text-decoration:underline;"&gt;DataLoadOptions&lt;/span&gt;, it does not match and the exception is thrown. You can read details about the problem in &lt;a title="Compiled Queries cannot take same DataLoadOption" href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2558764&amp;amp;SiteID=1"&gt;this forum post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The solution is to use a static &lt;span style="text-decoration:underline;"&gt;DataLoadOption&lt;/span&gt;. You cannot create a local &lt;span style="text-decoration:underline;"&gt;DataLoadOption&lt;/span&gt; instance and use in compiled queries. It needs to be &lt;span style="text-decoration:underline;"&gt;static&lt;/span&gt;. Here&amp;rsquo;s how you can do it:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_240E6FBB.png"&gt;&lt;img title="image" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_08F5A0AD.png" border="0" height="146" width="589" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Basically the idea is to construct a &lt;span style="text-decoration:underline;"&gt;static&lt;/span&gt; instance of &lt;span style="text-decoration:underline;"&gt;DataLoadOptions&lt;/span&gt; using a static function. As writing function for every single &lt;span style="text-decoration:underline;"&gt;DataLoadOptions&lt;/span&gt; combination is painful, I created a static delegate here and executed it right on the declaration line. This is in interesting way to declare a variable that requires more than one statement to prepare it. &lt;/p&gt;
&lt;p&gt;Using this option is very simple:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_4DC1C4E1.png"&gt;&lt;img title="image" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_4A602D39.png" border="0" height="73" width="670" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Now you can use &lt;span style="text-decoration:underline;"&gt;DataLoadOptions&lt;/span&gt; with compiled queries. &lt;/p&gt;
&lt;div class="wlWriterHeaderFooter" style="text-align:left;margin:0px;padding:4px 4px 4px 4px;"&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f10%2f27%2fsolving-common-problems-with-compiled-queries-in-linq-to-sql-for-high-demand-asp-net-websites.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f10%2f27%2fsolving-common-problems-with-compiled-queries-in-linq-to-sql-for-high-demand-asp-net-websites.aspx" alt="kick it on DotNetKicks.com" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1652150" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=IcGfm"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=IcGfm" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=mQVvM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=mQVvM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=WIsdm"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=WIsdm" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=srfuM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=srfuM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=CEraM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=CEraM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=mmKOM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=mmKOM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=FYqgm"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=FYqgm" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=bsFtM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=bsFtM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OmarAlZabirBlog/~4/436611190" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feeds.feedburner.com/~r/OmarAlZabirBlog/~3/426673960/tips-and-tricks-to-rescue-overdue-projects.aspx"&gt;Tips and tricks to rescue overdue projects&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Monday, October 20, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds.feedburner.com/OmarAlZabirBlog" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;&lt;p&gt;One of my friends, who runs his own offshore development shop, was having nightmare situation with one of his customers. He&amp;#39;s way overdue on a release, the customer is screaming everyday, he&amp;#39;s paying his team from his own pocket, customer is sending an ever increasing list of changes and so on. Here&amp;#39;s how we discussed some ideas to get out of such a situation and make sure it does not repeat in future: &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: Hey, can you help me? My customer is making us work for free for extra two months to fix bugs from our last delivery. We did what he said. But after he saw the output, he came up with hundred changes, which he somehow presents as bugs or missing features and make them look like they are all our fault and making us work for last two months for free. He is sending new changes every week. We have no idea when we will complete the iteration. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: I see. Did you get a signed list of requirements from customer before you started the development? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: Of course, I did. He sent us a word document explaining what he wants and we sent him a task breakup with hour estimates and total duration of three months. Now after three months when we showed him the product, he said, it&amp;#39;s no where close to what he had expected. Then he sent a gigantic list of things to change. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: All of those are bugs? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: Of course not. Most of them are new features. &lt;/p&gt;  &lt;p&gt;Omar: Then why don&amp;#39;t you say those are new features? You have the original word document to prove. Just ask him to show where in the word document did he said X needs to be done? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: Well..., he&amp;#39;s tricky. He somehow makes things look like it is obvious that X needs to be done and he&amp;#39;s not going to accept a requirement as done until X is done. For example, he said there must be a complete login form in the homepage. So, we did a typical login form with user name, password and OK, Cancel button. Now he says where&amp;#39;s the email verification thing? We said, you did not ask for it. He said, &amp;quot;this is obvious, every login form has a forgot password and email verification; I said *complete* login form, not half-baked login form&amp;quot;. So, you see, we can&amp;#39;t really argue to keep our image. Then, we did the login form exactly how he said. Now he says, where the client side validations of proper email address, username length, password confirmation? We said, you never asked for it! He says, &amp;quot;come on, every single website nowadays has AJAX enabled client side validation, do I have to tell you every single thing? Aren&amp;#39;t you guys smart enough to figure this out? You are already doing this for the third time, can&amp;#39;t you do it really well this time?&amp;quot; &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: OK, stop. I see what&amp;#39;s your problem. Some customer will always try to make you work more for less money. They will try to squeeze out every bit of development they can for their bucks. So, you have to be extra careful on how much you commit to them and make sure they cannot chip in more requirements while development is going on or when you deliver a version. Mockups are one good way to make sure things are crystal clear between you and customer.&amp;#160; Did you not show him mockups of the features that you will be building and make him sign those mockups? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: Yes, I made some mockups. But they were simple mockups. I did not show the validations or all those side jobs like sending verification emails. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: Did you run those mockups through your engineers? They could have told you about those details. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: No, I did not because developers don&amp;#39;t work on the project until I get a signoff from client. So, I prepare all the mockups myself to save cost.&lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: So, this is the first problem. The mockups were as ambiguous as the customer&amp;#39;s word document. Basically the mockups just reflected the sentences in word document. Mockups did not really show all possible navigations (ok, cancel, forgot, signup), system messages, system actions behind the scene, workflows etc. Are you getting what I am saying? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: Yes. Come on, I am not a developer. I can&amp;#39;t think of every single details. That&amp;#39;s what developers do when they start working on it. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: But you provide estimates based on your mockups right? So, if mockup shows there&amp;#39;s only a simple login form and change password link, you charge 5 hours for it. But then when you realize you have to send email for change password, email needs to contain a tokenized URL, that URL needs to show a change password form, where you need to validate using CAPTCHA etc, it becomes 20 hours of work. Right? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: Well yes. Generally I multiply all estimates by 1.5 just to be safe. But things have gone 3X to 10X off original estimate. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: Yes, I just gave you an example how a login form estimate can go 4X off when the mockup is not run through an engineer and the important issues are not addressed. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: So, you are saying I have to prepare all mockup with an engineer? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: In general, yes, since you aren&amp;#39;t good enough to figure those out yourself; no offence. You will get good enough after you build couple of products and get your a** kicked couple of times, like mine. Mine got kicked about 17 times. After that it became so hard that when I sit on it, I produce really good mockups. After some more kicks, I hope to get 100% perfect in my mockups. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: Ok, so the process is, I get word doc from customer. I produce mockups from it. Then I run them through engineers to add more details to them. Then after review with customer, I run them through engineers again to estimate. Then I ask customer to sign-off on the mockups and the estimate, correct?&lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: Well, first let me say, you don&amp;#39;t do a three month long iteration since you are far away from your customer. You do short two weeks sprints. Do you know SCRUM? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: Yes, one of our team does it. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: I assume the team that got their a** kicked don&amp;#39;t do it? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: right, they don&amp;#39;t. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: OK, then first you start doing SCRUM. I won&amp;#39;t teach you details. You can study about SCRUM online. Now, you collect &amp;#39;user stories&amp;#39; from customer. If customer does not give you user stories, just vague paras of requirements, you break the requirements into small user stories. Understood? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: No, give example. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: OK, say customer wants a *complete* login form. You break it into couple of stories like: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;User clicks on &amp;quot;login&amp;quot; link from homepage so that user can login to the system      &lt;ul&gt;       &lt;li&gt;User enters username (min 5, max 255 chars, only alphanumeric) in the username text field &lt;/li&gt;        &lt;li&gt;User enters password (min 5, max 50 chars, only alphanumeric) in the password field &lt;/li&gt;        &lt;li&gt;User clicks on &amp;quot;OK&amp;quot; button after entering username and password. &lt;/li&gt;        &lt;li&gt;System validates username and password and shows the secure portal if credential is valid and user has permission to login and account is not locked. &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Understood what user stories are? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: Yes, but you are missing all the validations that we also overlooked and now we are working two months for free. This “user stories” do not help at all. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: Hold on, you just saw basic steps of a user story. Now you describe each user story with the following: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;All possible inputs of user and their valid format &lt;/li&gt;    &lt;li&gt;All possible system generated messages for invalid input &lt;/li&gt;    &lt;li&gt;All possible alternate navigation from the main user story. For example, while entering password, user can click on a help icon so that user can see what kind of passwords are allowed. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Got it? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: Now it&amp;#39;s starting to make sense. Then what? Show these user stories to customers? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: No, show them to your lead engineer who has enough experience to identify if you missed something. Your Engr should point out all the alternative system actions at least. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: What if my Engr can&amp;#39;t figure them out? What if he&amp;#39;s just as dumb as me? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: Fire him. Get a pay cut for yourself. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: Seriously, what do I do if that&amp;#39;s the case? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: Your engineers will *always* come up with issues with your mockups. You should always use another pair of eyes to verify your mockups and add more details to it. You aren&amp;#39;t the only smart guy in the world you know? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: I thought I was, ok. What&amp;#39;s next? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: File those user stories in your issue tracking system in some special category. Say &amp;quot;User Stories&amp;quot; category. What do you use for your issue tracking system? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: Flyspray &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: Good enough. Create a new project in Filespray named &amp;quot;User Stories&amp;quot;. File tasks for user stories. Each story, one task. Attach the mockup to the tasks. Then create one account for your customer so that customer can login and see the user stories, make comments, suggest changes etc. You will get the conversation with your customer recorded as comments in the task. This comes handy for engineers and for resolving dispute later on. Moreover, get your customer to prioritize the tasks properly. Understood? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: I don&amp;#39;t think customer will go through that trouble. Customer will ask for some word document that has all the user stories and she will write in the document what are the changes. I will have to reflect them in Flyspray. Is it really necessary to file user stories in Flysrpay? Can&amp;#39;t I just maintain one word doc with customer? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: Absolutely not. Word documents suffer from versioning problem. You have one version, your customer has another version, your engineers have another version. it becomes a nightmare to move around with word docs which has many user stories in it and keep them in sync all the time. Moreover, referencing a particular use case also becomes a problem. Say at later stage of the project, there&amp;#39;s a bug which needs to refer to User Story #123. You will have to say User Story #123 in &lt;a&gt;\\centralserver\fileshare\user&lt;/a&gt; stories1.doc. Now if &lt;a&gt;\\centralserver&lt;/a&gt; dies, or you put it somewhere else, all these references are gone. Don&amp;#39;t go for word doc. Keep everything on the web that you can refer to it using a URL or small number. Another problem is numbering stories in Word Doc. Word won&amp;#39;t produce unique ID for you. You will end up with duplicate user story numbers. If you use Flyspray, it&amp;#39;s will generate unique ID for you. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: OK, let me see how I convince my customer to use Flyspray. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: Yes, you should. If Flyspray is hard for customers, use some simple issue tracking system that&amp;#39;s a no-brainer for non-engineers. Some fancy AJAX based todolist site will be good enough if it has picture attachment feature and auto task number feature. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: OK, I will find such a website. So, I got the user stories done. Now I show them to customer, review, make changes. Finally I get customer to sign off on User story #X to #Y for a two weeks sprint. Then what happens? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: On your first day of sprint, you do a sprint planning meeting where you present those user stories to your engineers and ask them to break each story into small tasks and estimate each task. Make sure no engineer put 1 day or 2 day for any task. Break them into even smaller tasks like 4 hours of tasks. This will force your engineers to give enough thought into the stories and identify possible problems upfront. Generally when someone says this is going to take a day or two, s/he has no idea how to do it. S/he has not thought about the steps need to be done to complete that task. Your are getting an estimate that&amp;#39;s either overestimated or underestimated. Forcing an engineer to allocate tasks in less than 4 hours slot makes an engineer think about the steps carefully.&amp;#160; &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: If engineers do this level of estimate, they will think about each task for at least an hour. This is going to take days to finish estimating so many tasks. How do you do it in a day? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: We do 4 hours Planning meeting where Product Owner explains the stories to engineers and then after 30 mins break, another 4 hours meeting where engineers pickup stories and breaks them into tasks and estimate on-the-fly. This 4 hours deadline is strictly maintained. If Product team cannot explain the tasks for a sprint in 4 hours, we don&amp;#39;t do the tasks in the sprint. If the tasks are so complex or there are so many tasks that they cannot be explained in 4 hours, engineers unlikely to do them within one/two week long sprint. Similarly if engineers cannot estimate the tasks in their 4 hours slot, the tasks are just too complex to estimate and thus have high probability of not getting done in the sprint. So, we drop them as well. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: This is impossible! No one&amp;#39;s going to attend 8 hours meeting on a day. Besides, telling them to estimate a task on the spot is super inefficient. They won&amp;#39;t produce more than 60% correct estimates. They will give some lump sum estimate and then go away. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: Incorrect, if engineers cannot make estimates of a task in 10 to 20 minutes, they don&amp;#39;t have the capability of estimating at all. If your engineers are habituated to take a task from you for estimating and then go to their office, talk to their friends on the phone, drink soda, walk around, gossip with colleagues and end of the day if they have the mood to sit and think about the estimate then open a new mail, write some numbers and email it to you; they better learn to do this on-demand, when requested, within time constraint. It&amp;#39;s a discipline that they need to learn and implement in their life. Estimates are something they do from the moment they wake up to the moment they go to sleep. Besides, the planning meeting is the best place to estimate tasks - all engineers are there, product team is there, your architects should be there, QA team is there. It&amp;#39;s easy to ask questions, get ideas and helps from others. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: I have engineers who just can&amp;#39;t do well under pressure. They need some undisturbed moment, where they can sit and think about tasks without anyone staring at them. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: Train them to learn how to keep their head cool and do their job in the midst of attention. Anyway, let&amp;#39;s stop talking about these auxiliary issues and talk about the most important issues. Where were we? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;:About dropping tasks, I already negotiated with customer that we are going to do story A, B, C in this sprint. Now after the sprint planning meetings, engineers say they can&amp;#39;t do B. Problem is I have already committed to deliver A, B, and C to customer within 2 weeks and sent him the invoice. How do I handle this? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: How do you commit when you don&amp;#39;t know how long A, B, and C are going to take? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: Customer tells me to do A, B, C within two weeks. And after doing some preliminary discussion with engineers, I commit to customer and then do the sprint planning meeting. I can’t wait until the sprint meeting is done and developers have given me estimates of all the tasks.&lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: Wrong. You commit to customer after the sprint planning meeting is done. Before that, you give customer just a list of things that you believe you can try to do in following two weeks. Tell customer that you will be able to confirm after the sprint planning meeting. The time to do a sprint meeting is only 8 hours = a day. So, end of the day, you have some concrete stuff to commit to customer. From your model where you give engineers days to estimate, it won’t work. You have to finish planning within a day and end of the day, commit to customer. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: What if customer does not agree? What if he says, &amp;quot;I must get A, B and C in two weeks, otherwise I am going somewhere else?&amp;quot; &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: This is a hard situation. I am tempted to say that you tell your customer, &amp;quot;Go away!&amp;quot;, but in reality you can&amp;#39;t. You have to negotiate and come to a mutual agreement. You cannot just obey customer and say &amp;quot;Yes Mi Lord, we will do whatever you say&amp;quot; because you clearly cannot do it. The fact is, end of the sprint, you *will* get only A and C done and B not done. Then customer will Fedex you his shoes so that you can ask someone to kick you with it. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: Correct, so what do I do? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: There are tricky solutions and non-tricky honest solutions to this. Tricky solution is, say you engaged 5 engineers in the project who can get A and C done in time. But you realize you need another engineer to do B, otherwise there&amp;#39;s no way you can finish A, B and C in two weeks. So, you invoice customer with 6 engineers and get A, B and C done. Now customer may not agree with you paying for the 6th engineer. Then you do a clever trick. You engage the 6th engineer free of cost in this sprint. Don&amp;#39;t tell customer that there&amp;#39;s an extra head working in the project. Or you can tell customer that out of good will, you want to engage another engineer free of cost to make sure customer gets a timely delivery. This boosts your image. Later on, when you get a sprint that&amp;#39;s more or less relaxed and 4 engineers can do the job, you secretly engage one engineer to some other project but still charge for 5 engineers to your customer. This way&amp;#160; you cover the cost for the 6th engineer that you secretly engaged earlier sprint. This is dirty. But when you have so hard a** customer who&amp;#39;s forcing you &amp;quot;what&amp;quot;, &amp;quot;when&amp;quot; and &amp;quot;how&amp;quot; all at the same time and not open to negotiation, you have no choice but to do these dirty tricks. You can also add extra one hour to every task for every engineer in a sprint or add some vague tasks like &amp;quot;Refactor User object to allow robust login&amp;quot;. This way you will get quite some amount of extra hours that will compensate for the hidden free engineer that you engage. You get the idea right? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: Ingenious! And what&amp;#39;s the honest and clear way to do these? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: You negotiate with customer. You tell your customer that he or she can only have any two choices from Money-Scope-Time. This is called the project management triangle. Do you know about this? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: Googling... &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: Read this article: &lt;/p&gt;  &lt;p&gt;&lt;a href="http://office.microsoft.com/en-us/project/HA010211801033.aspx"&gt;http://office.microsoft.com/en-us/project/HA010211801033.aspx&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;It shows a triangle like this: &lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Whathappensbeforeasprintstarts_5F00_11338/clip_5F00_image002_5F00_2.gif"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="141" alt="clip_image002" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Whathappensbeforeasprintstarts_5F00_11338/clip_5F00_image002_5F00_thumb.gif" width="171" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;So, your customer can specify any two. If customer specifies Scope and Time (&amp;quot;what&amp;quot; and &amp;quot;when&amp;quot;), then customer must be flexible on Money or &amp;quot;how&amp;quot; you do it within those two constraints. If customer specifies Money and Scope, then you are free to decide on time. You engage lower resource and take more time to get things done. Got the idea? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: Yes, understood. Nice, I can show this to customer and educate him. Is there any book for the evil tricks that you just gave me? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: No, I might write one soon. I will name it &amp;quot;Customers are evil, so be you&amp;quot;. &lt;/p&gt;  &lt;p&gt;Raisul: Hey, I have fixed people engaged in a project. I can&amp;#39;t change the number of people sprint-to-sprint to compensate for change in money. So, the triangle does not work for me. What do I do here? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: Right. I also made a slightly different version of it. Here&amp;#39;s my take: &lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Whathappensbeforeasprintstarts_5F00_11338/image_5F00_10.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="196" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Whathappensbeforeasprintstarts_5F00_11338/image_5F00_thumb_5F00_4.png" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;This is for situation where you have fixed resource engaged for a particular customer. In that case, you cannot reduce people on-demand because you cannot reassign them. Such a case requires different strategy. If customer forces you Quality and Time, customer must be willing to sacrifice Quantity. Customer cannot say, produce perfect login form in 2 weeks and add cool ajax effects to it. Customer has to sacrifice cool ajax effects, or sacrifice *perfection* of login form, or sacrifice number of days. &lt;/p&gt;  &lt;p&gt;From the above two triangles, which one&amp;#39;s more appropriate for you? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: Second one because customer hires 5 engineers from me. I cannot take one away and engage in a different project. Well, not openly of course. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: OK, sounds fair. What else do you need from me? &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Kabir&lt;/u&gt;: Let me think about all these. This is definitely worth thinking. I have to figure out whether to play fair or play clever. End of the day, I need to produce great product, so that, I get good recommendation and future projects from customer. So, I need to do whatever it takes. It&amp;#39;s hard to run an offshore dev shop where we kinda have to work like slaves and like a bunch of zombies mumble every 10 mins - &amp;quot;Customer is always right&amp;quot;. You are very lucky to have your own company. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Omar&lt;/u&gt;: I had two offshore dev shops before &lt;a href="http://www.pageflakes.com"&gt;Pageflakes&lt;/a&gt;. I know how it feels. Wish you good luck. I have seen your product, you guys are building a great ASP.NET MVC+jQuery application. Release it. It&amp;#39;s worth showcasing. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;Raisul&lt;/u&gt;: Thank you very much. See ya...&lt;/p&gt;  &lt;p&gt;(End of chat) &lt;/p&gt;  &lt;p&gt;This is the diagram my friend produced, which shows the steps to do before a sprint is started:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Whathappensbeforeasprintstarts_5F00_11338/image_5F00_2.png" target="_blank"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="399" alt="Workflow for Product Manager" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Whathappensbeforeasprintstarts_5F00_11338/image_5F00_thumb.png" width="620" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Handy for Product Managers. Enlightening for developers.&lt;/p&gt; &lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f10%2f20%2ftips-and-tricks-to-rescue-overdue-projects.aspx"&gt;&lt;img alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f10%2f20%2ftips-and-tricks-to-rescue-overdue-projects.aspx" border="0" /&gt;&lt;/a&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1651416" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=Yosmm"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=Yosmm" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=9sYnM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=9sYnM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=Q66lm"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=Q66lm" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=2gy6M"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=2gy6M" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=jcXAM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=jcXAM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=ocJPM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=ocJPM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=pqg5m"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=pqg5m" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=GzgHM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=GzgHM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OmarAlZabirBlog/~4/426673960" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feeds.feedburner.com/~r/OmarAlZabirBlog/~3/417762427/an-agile-developer-s-workflow-when-scrum-is-used.aspx"&gt;An Agile Developer's workflow when SCRUM is used&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Saturday, October 11, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds.feedburner.com/OmarAlZabirBlog" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;&lt;p&gt;If you are planning to start SCRUM at your company, you might need to train developers and QA to get into the mindset of an Agile developer. SCRUM is only successful when the developers and QA get into the habit of following the principles of SCRUM by heart. So, sometimes you need to offer training or do trial sprints to give some room to your developers how to get used to the working fashion of SCRUM. Giving them a handy workflow diagram that shows how they should work helps soothe the steep learning curve required for non-super star developers. I made such a workflow while I was teaching SCRUM at my friend&amp;#39;s company. The following diagram was printed and hung over the desk of each and every developer to help them grasp the culture of SCRUM quickly:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.AnAgileDevelopersworkflowwhenSCRUMisused_5F00_10FF6/image_5F00_2.png"&gt;&lt;img border="0" width="604" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.AnAgileDevelopersworkflowwhenSCRUMisused_5F00_10FF6/image_5F00_thumb.png" alt="image" height="1045" style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We use Flyspray for issue tracking, so you will see the mention of it frequently. &lt;/p&gt;
&lt;p&gt;You will see the step to &amp;quot;Update Sprint backlog with remaining hours&amp;quot; is missing. This is done kinda verbally and scrum master (sometimes same person who is the product owner) keeps track of it.&lt;/p&gt;
&lt;p&gt;Hope you find this useful.&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f10%2f11%2fan-agile-developer-s-workflow-when-scrum-is-used.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f10%2f11%2fan-agile-developer-s-workflow-when-scrum-is-used.aspx" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1650562" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=ijcsm"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=ijcsm" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=6BP1M"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=6BP1M" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=CTj3m"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=CTj3m" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=FGccM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=FGccM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=tJ15M"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=tJ15M" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=JFtVM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=JFtVM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=SBSvm"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=SBSvm" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/OmarAlZabirBlog?a=JC7LM"&gt;&lt;img src="http://feeds.feedburner.com/~f/OmarAlZabirBlog?i=JC7LM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/OmarAlZabirBlog/~4/417762427" height="1" width="1"/&gt;&lt;/p&gt;
	&lt;/div&gt;&lt;div class="entry"&gt;
		&lt;div class="title"&gt;
			&lt;a href="http://feeds.feedburner.com/~r/OmarAlZabirBlog/~3/412778260/asp-net-website-continuous-integration-deployment-using-cruisecontrol-net-subversion-msbuild-and-robocopy.aspx"&gt;ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy&lt;/a&gt;
		&lt;/div&gt;&lt;div class="moreinfo"&gt;
			&lt;span class="date"&gt;Monday, October 06, 2008&lt;/span&gt; &amp;nbsp;| &amp;nbsp;&lt;span class="source"&gt;From &lt;a href="http://feeds.feedburner.com/OmarAlZabirBlog" target="_blank"&gt;Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5&lt;/a&gt;&lt;/span&gt;
		&lt;/div&gt;&lt;p&gt;&lt;p&gt;You can setup continuous integration and automated deployment for your web application using CruiseControl.NET, Subversion, MSBuild and Robocopy. I will show you how you can automatically build the entire solution, email build report to developers and QA, deploy latest code in IIS all using CruiseControl.NET every N minutes. &lt;/p&gt;
&lt;p&gt;First get the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://ccnet.thoughtworks.com/"&gt;CruiseControl.NET&lt;/a&gt;  &lt;/li&gt;
&lt;li&gt;&lt;a href="http://msmvps.com/controlpanel/blogs/posteditor.aspx/subversion.tigris.org"&gt;Subversion&lt;/a&gt; (install the command line tools and add the Subversion bin path to PATH environment variable)  &lt;/li&gt;
&lt;li&gt;Robocopy (Windows Vista/2008 has it built-in, here&amp;#39;s the link for &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=9d467a69-57ff-4ae7-96ee-b18c4790cffd"&gt;Windows 2003&lt;/a&gt;)  &lt;/li&gt;
&lt;li&gt;Install .NET Framework. You need it for MSBuild. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You will learn how I have configured Continuous Integration and Deployment for my open source AJAX Portal project &lt;a href="http://www.Dropthings.com"&gt;www.Dropthings.com&lt;/a&gt;. The code is hosted at CodePlex. When some developer makes a commit, CruiseControl downloads the latest code, builds the entire solution, emails build report and then deploys the latest web site to IIS 6.0.&lt;/p&gt;
&lt;p&gt;After installing CruiseControl.NET, go to &lt;span style="text-decoration:underline;"&gt;Programs -&amp;gt; Cruise Control -&amp;gt; CruiseControl.NET Config&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Now keep copying and pasting the following XML blocks and make sure you understand each block and make necessary changes:&lt;/p&gt;
&lt;div style="border-right:gray 1px solid;padding-right:4px;border-top:gray 1px solid;padding-left:4px;font-size:8pt;padding-bottom:4px;margin:20px 0px 10px;overflow:auto;border-left:gray 1px solid;width:94.58%;cursor:text;max-height:200px;line-height:12pt;padding-top:4px;border-bottom:gray 1px solid;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;height:301px;background-color:#f4f4f4;"&gt;
&lt;div style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   1:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;cruisecontrol&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   2:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;project&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Dropthings&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;queue&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;DropthingsQueue&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;queuePriority&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;1&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   3:&lt;/span&gt;         &lt;span style="color:#008000;"&gt;&amp;lt;!-- &lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   4:&lt;/span&gt; &lt;span style="color:#008000;"&gt;        Path to the trunk folder where the full solution starts from. This is where&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   5:&lt;/span&gt; &lt;span style="color:#008000;"&gt;        subversion checkout and incremental update is performed &lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   6:&lt;/span&gt; &lt;span style="color:#008000;"&gt;        --&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   7:&lt;/span&gt;         &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;workingDirectory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;d:\cc\dropthings\code\trunk\&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;workingDirectory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   8:&lt;/span&gt;         &lt;span style="color:#008000;"&gt;&amp;lt;!-- Some path where CCNet writes its logs and stuffs. It can be outside the log folder --&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   9:&lt;/span&gt;         &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;artifactDirectory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;d:\cc\dropthings\artifact\&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;artifactDirectory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  10:&lt;/span&gt;         &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;category&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;Dropthings&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;category&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  11:&lt;/span&gt;         &lt;span style="color:#008000;"&gt;&amp;lt;!-- CCNet installs a web dashboard. Enter the URL of that dashboard here --&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  12:&lt;/span&gt;         &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;webURL&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;http://localhost/ccnet/&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;webURL&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  13:&lt;/span&gt;         &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;modificationDelaySeconds&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;60&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;modificationDelaySeconds&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  14:&lt;/span&gt;         &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;labeller&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;type&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;defaultlabeller&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  15:&lt;/span&gt;             &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;prefix&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;0.1.&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;prefix&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  16:&lt;/span&gt;             &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;incrementOnFailure&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;true&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;incrementOnFailure&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  17:&lt;/span&gt;             &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;labelFormat&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;000&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;labelFormat&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  18:&lt;/span&gt;         &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;labeller&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  19:&lt;/span&gt;         &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;state&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;type&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;state&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;directory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;State&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;First change the working directory. It needs to be the path of the folder where you will have the solution downloaded. I generally create folder structure like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;D:\CC - Root for all CC.NET enabled projects 
&lt;ul&gt;
&lt;li&gt;\ProjectName - Root project folder 
&lt;ul&gt;
&lt;li&gt;\Code - Code folder where code is downloaded from subversion 
&lt;/li&gt;
&lt;li&gt;\Artifact - CC.NET generates a lot of stuff. All goes here.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; Next comes the Subversion integration block:&lt;/p&gt;
&lt;div style="border-right:gray 1px solid;padding-right:4px;border-top:gray 1px solid;padding-left:4px;font-size:8pt;padding-bottom:4px;margin:20px 0px 10px;overflow:auto;border-left:gray 1px solid;width:97.5%;cursor:text;max-height:200px;line-height:12pt;padding-top:4px;border-bottom:gray 1px solid;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;background-color:#f4f4f4;"&gt;
&lt;div style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   1:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;sourcecontrol&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;type&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;svn&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   2:&lt;/span&gt;     &lt;span style="color:#008000;"&gt;&amp;lt;!-- Subversion trunk repository to keep checking for latest code --&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   3:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;trunkUrl&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;http://localhost:8081/tfs02.codeplex.com/dropthings/trunk&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;trunkUrl&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   4:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;workingDirectory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;workingDirectory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   5:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;username&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;***** SUBVERSION USER NAME *****&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;username&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   6:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;password&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;***** SUBVERSION PATH *****&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;password&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   7:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;sourcecontrol&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here specify the subversion location where you want to download code to the working folder. You should download the entire solution because you will be building the entire solution using MSBuild soon.&lt;/p&gt;
&lt;p&gt;I left &lt;span style="text-decoration:underline;"&gt;&amp;lt;workingDirectory&amp;gt;&lt;/span&gt; empty. This means whatever is specified earlier in the &lt;span style="text-decoration:underline;"&gt;&amp;lt;workingDirectory&amp;gt;&lt;/span&gt; is used. Otherwise you can put some relative folder path here or any absolute folder.&lt;/p&gt;
&lt;p&gt;Now we start building the tasks that CC.NET executes - Build, Email, and Deploy.&lt;/p&gt;
&lt;div style="border-right:gray 1px solid;padding-right:4px;border-top:gray 1px solid;padding-left:4px;font-size:8pt;padding-bottom:4px;margin:20px 0px 10px;overflow:auto;border-left:gray 1px solid;width:97.5%;cursor:text;max-height:200px;line-height:12pt;padding-top:4px;border-bottom:gray 1px solid;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;background-color:#f4f4f4;"&gt;
&lt;div style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   1:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;tasks&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   2:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;artifactcleanup&lt;/span&gt;   &lt;span style="color:#ff0000;"&gt;cleanUpMethod&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;KeepLastXBuilds&amp;quot;&lt;/span&gt;   &lt;span style="color:#ff0000;"&gt;cleanUpValue&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;5&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monosp