<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://msmvps.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5 : asp.net</title><link>http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx</link><description>Tags: asp.net</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP2 (Build: 40407.4157)</generator><item><title>7 tips for for loading Javascript rich Web 2.0-like sites significantly faster</title><link>http://msmvps.com/blogs/omar/archive/2009/09/25/7-tips-for-for-loading-javascript-rich-web-2-0-like-sites-significantly-faster.aspx</link><pubDate>Fri, 25 Sep 2009 14:46:19 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1726818</guid><dc:creator>omar</dc:creator><slash:comments>9</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1726818</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2009/09/25/7-tips-for-for-loading-javascript-rich-web-2-0-like-sites-significantly-faster.aspx#comments</comments><description>&lt;h2&gt;Introduction&lt;/h2&gt;  &lt;p&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 &lt;strong&gt;not&lt;/strong&gt; 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;/p&gt;  &lt;p&gt;You must have noticed Microsoft’s new tool &lt;a title="Doloto download optimizer" href="http://research.microsoft.com/en-us/projects/doloto/"&gt;Doloto&lt;/a&gt; which helps solve the following problem:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&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;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Microsoft Research looked at this problem and published &lt;a title="Doloto Research Papper" href="http://research.microsoft.com/en-us/projects/doloto/fse08.pdf"&gt;this research paper in 2008&lt;/a&gt;, 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 &lt;a title="Web 2.0 Start Page" href="http://www.pageflakes.com"&gt;Pageflakes&lt;/a&gt; and reported:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;2.2.2 Dynamic Loading: Pageflakes      &lt;br /&gt;A contrast to Bunny Hunt is the &lt;a title="Pageflakes Web 2.0 start page" href="http://www.pageflakes.com"&gt;Pageflakes&lt;/a&gt; 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 application’s performance.       &lt;br /&gt;However, designing an application architecture that is       &lt;br /&gt;amenable to dynamic code loading requires careful consideration       &lt;br /&gt;of JavaScript language issues such as function closures, scoping,       &lt;br /&gt;etc. Moreover, an optimal decomposition of code into dynamically       &lt;br /&gt;loaded components often requires developers to set aside the semantic       &lt;br /&gt;groupings of code and instead primarily consider the execution       &lt;br /&gt;order of functions. Of course, evolving code and changing       &lt;br /&gt;user workloads make both of these issues a software maintenance       &lt;br /&gt;nightmare.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Back in 2007, I was looking at ways to improve the initial load time and reduce user dropout. The number of users who would not wait for the page to load and go away was growing day by day as we introduced new and cool features. It was a surprise. We thought new features will keep more users on our site but the opposite happened. Analysis concluded it was the initial loading time that caused more dropout than it retained users. So, all our hard work was essentially going to drain and we had to come up with something ground breaking to solve the problem. Of course we had already tried all the basic stuffs – &lt;a title="IIS 6 compression setup quick and easy way" href="http://msmvps.com/blogs/omar/archive/2006/08/10/iis-6-compression-quickest-and-effective-way-to-do-it-for-asp-net-compression.aspx"&gt;IIS compression&lt;/a&gt;, &lt;a title="Making best use of cache for faster page loading" href="http://msmvps.com/blogs/omar/archive/2006/08/10/iis-6-compression-quickest-and-effective-way-to-do-it-for-asp-net-compression.aspx"&gt;browser caching&lt;/a&gt;, &lt;a title="Ensure - loading javascript, css, html on demand" href="http://www.codeplex.com/ensure"&gt;on-demand loading of JavaScript, css and html&lt;/a&gt; when user does something, &lt;a title="Deferred Javascript Execution" href="http://ajaxian.com/archives/gmail-mobile-latency"&gt;deferred JavaScript execution&lt;/a&gt; – but nothing helped. The frameworks and our own hand coded framework was just too large. So, the idea tricked me, what if we could load functions inside a class in two steps. First step will load the class with absolutely essential functions and second step will inject more functions to the existing classes.&lt;/p&gt;  &lt;p&gt;I published a codeproject article which shows you 7 tricks to significantly improve page load time even if you have large amount of Javascript used on the page.&lt;/p&gt;  &lt;p&gt;&lt;a title="7 Tips for Loading JavaScript Rich Web 2.0-like Sites Significantly Faster" href="http://www.codeproject.com/KB/ajax/fastjavascript.aspx"&gt;7 Tips for Loading JavaScript Rich Web 2.0-like Sites Significantly Faster&lt;/a&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Use Doloto &lt;/li&gt;    &lt;li&gt;Split a Class into Multiple JavaScript Files &lt;/li&gt;    &lt;li&gt;Stub the Functions Which Aren&amp;#39;t Called During Initial Load &lt;/li&gt;    &lt;li&gt;JavaScript Code in Text &lt;/li&gt;    &lt;li&gt;Break UI Loading into Multiple Stages &lt;/li&gt;    &lt;li&gt;Always Grow Content from Top to Bottom, Never Shrink or Jump &lt;/li&gt;    &lt;li&gt;Deliver Browser Specific Script from Server &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;If you like these tricks, please vote for me!&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px;padding:0px 0px 0px 0px;"&gt;&lt;a href="http://dotnetburner.com/vote?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2009%2f09%2f25%2f7-tips-for-for-loading-javascript-rich-web-2-0-like-sites-significantly-faster.aspx" rev="vote-for"&gt;&lt;img src="http://dotnetburner.com/image.axd?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2009%2f09%2f25%2f7-tips-for-for-loading-javascript-rich-web-2-0-like-sites-significantly-faster.aspx" style="border:0px;" alt="Burn!" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2009%2f09%2f25%2f7-tips-for-for-loading-javascript-rich-web-2-0-like-sites-significantly-faster.aspx" rev="vote-for"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2009%2f09%2f25%2f7-tips-for-for-loading-javascript-rich-web-2-0-like-sites-significantly-faster.aspx" style="border:0px;" alt="kick it" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2009%2f09%2f25%2f7-tips-for-for-loading-javascript-rich-web-2-0-like-sites-significantly-faster.aspx"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2009%2f09%2f25%2f7-tips-for-for-loading-javascript-rich-web-2-0-like-sites-significantly-faster.aspx" style="border:0px;" /&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=1726818" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx">performance</category><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/javascript/default.aspx">javascript</category><category domain="http://msmvps.com/blogs/omar/archive/tags/ajax/default.aspx">ajax</category><category domain="http://msmvps.com/blogs/omar/archive/tags/optimize/default.aspx">optimize</category></item><item><title>ASP.NET AJAX testing made easy using Visual Studio 2008 Web Test</title><link>http://msmvps.com/blogs/omar/archive/2009/05/25/asp-net-ajax-testing-made-easy-using-visual-studio-2008-web-test.aspx</link><pubDate>Mon, 25 May 2009 11:44:32 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1693085</guid><dc:creator>omar</dc:creator><slash:comments>7</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1693085</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2009/05/25/asp-net-ajax-testing-made-easy-using-visual-studio-2008-web-test.aspx#comments</comments><description>&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 &lt;u&gt;ctrl00_UpdatePanel003_SubmitButton002”&lt;/u&gt;, 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 &lt;u&gt;UpdatePanel&lt;/u&gt; and then based on the server returned response, you want to make further AJAX calls or post the refreshed &lt;u&gt;UpdatePanel&lt;/u&gt;, 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 &lt;u&gt;UpdatePanel&lt;/u&gt;s 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 &lt;u&gt;UpdatePanel&lt;/u&gt; rich web pages. There are several &lt;u&gt;ExtractionRule&lt;/u&gt; and &lt;u&gt;ValidationRule&lt;/u&gt; available in the library which makes testing Cookies, Response Headers, JSON output, discovering all &lt;u&gt;UpdatePanel&lt;/u&gt; in a page, finding controls in the response body, finding controls inside some &lt;u&gt;UpdatePanel&lt;/u&gt; all very easy.&lt;/p&gt;  &lt;p&gt;First, let me give you an example of what can be tested using this library. My open source project &lt;a href="http://dropthings.omaralzabir.com/"&gt;Dropthings&lt;/a&gt; produces a Web 2.0 Start Page where the page is composed of widgets. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_6E1BF0AF.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="354" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_293FA6AE.png" width="573" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Each widget is composed of two &lt;u&gt;UpdatePanel&lt;/u&gt;. There’s a header area in each widget which is one &lt;u&gt;UpdatePanel&lt;/u&gt; and the body area is another &lt;u&gt;UpdatePanel&lt;/u&gt;. 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;/p&gt;  &lt;p&gt;See the web test I did:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_2505A91C.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="541" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_1C552AC3.png" width="585" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;This test simulates an anonymous user visit. When anonymous user visits Dropthings for the first time, two pages are created with some default widgets. You can also add new widgets on the page, you can drag &amp;amp; drop widgets, you can delete a widget that you don’t like. &lt;/p&gt;  &lt;p&gt;This Web Test simulates these behaviors automatically:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Visit the homepage &lt;/li&gt;    &lt;li&gt;Show the widget list which is an &lt;u&gt;UpdatePanel&lt;/u&gt;. It checks if the &lt;u&gt;UpdatePanel&lt;/u&gt; contains the BBC World widget. &lt;/li&gt;    &lt;li&gt;Then it clicks on the “Edit” link of the “How to of the day” widget which brings up some options dynamically inside an &lt;u&gt;UpdatePanel&lt;/u&gt;. Then it tries to change the Dropdown value inside the &lt;u&gt;UpdatePanel&lt;/u&gt; to 10. &lt;/li&gt;    &lt;li&gt;Adds a new widget from the Widget List. Ensures that the &lt;u&gt;UpdatePanel&lt;/u&gt; postback successfully renders the new widget. &lt;/li&gt;    &lt;li&gt;Deletes the newly added widget and ensures the widget is gone. &lt;/li&gt;    &lt;li&gt;Logs user out. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;If you want to learn details about the project, read my codeproject article:&lt;/p&gt; &lt;a title="ASP.NET AJAX testing made easy using Visual Studio 2008 Web Test" href="http://www.codeproject.com/KB/aspnet/aspnetajaxtesting.aspx"&gt;http://www.codeproject.com/KB/aspnet/aspnetajaxtesting.aspx&lt;/a&gt;   &lt;p&gt;Please vote if you find this useful.&lt;/p&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/2009/05/25/asp-net-ajax-testing-made-easy-using-visual-studio-2008-web-test.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http://msmvps.com/blogs/omar/archive/2009/05/25/asp-net-ajax-testing-made-easy-using-visual-studio-2008-web-test.aspx&amp;amp;bgcolor=0080C0&amp;amp;fgcolor=FFFFFF&amp;amp;border=000000&amp;amp;cbgcolor=808080&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=1693085" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/ajax/default.aspx">ajax</category><category domain="http://msmvps.com/blogs/omar/archive/tags/testing/default.aspx">testing</category></item><item><title>Web 2.0 AJAX Portal using jQuery, ASP.NET 3.5, Silverlight, Linq to SQL, WF and Unity</title><link>http://msmvps.com/blogs/omar/archive/2009/04/08/web-2-0-ajax-portal-using-jquery-asp-net-3-5-silverlight-linq-to-sql-wf-and-unity.aspx</link><pubDate>Wed, 08 Apr 2009 18:16:22 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1685991</guid><dc:creator>omar</dc:creator><slash:comments>11</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1685991</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2009/04/08/web-2-0-ajax-portal-using-jquery-asp-net-3-5-silverlight-linq-to-sql-wf-and-unity.aspx#comments</comments><description>&lt;p&gt;&lt;a title="Dropthings Web 2.0 style AJAX portal" href="http://dropthings.omaralzabir.com" target="_blank"&gt;Dropthings&lt;/a&gt; – my &lt;a title="Dropthings - Open Source AJAX Portal" href="http://www.codeplex.com/dropthings" target="_blank"&gt;open source&lt;/a&gt; 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 &lt;strong&gt;jQuery&lt;/strong&gt; front-end combined with ASP.NET AJAX &lt;code&gt;UpdatePanel&lt;/code&gt;, &lt;strong&gt;Silverlight widget&lt;/strong&gt;, full &lt;strong&gt;Workflow Foundation&lt;/strong&gt; implementation on the business layer, 100% &lt;strong&gt;Linq to SQL Compiled Queries&lt;/strong&gt; on the data access layer, Dependency Injection and Inversion of Control (IoC) using &lt;strong&gt;Microsoft Enterprise Library 4.1&lt;/strong&gt; and &lt;strong&gt;Unity&lt;/strong&gt;. 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 &lt;a title="AJAX Portal at National University of Singapore" href="http://nexus.nus.edu.sg/apicta" target="_blank"&gt;National University of Singapore&lt;/a&gt; portal.&lt;/p&gt;  &lt;p&gt;Visit: &lt;a href="http://dropthings.omaralzabir.com"&gt;http://dropthings.omaralzabir.com&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_57907290.png"&gt;&lt;img title="Dropthings AJAX Portal" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="529" alt="Dropthings AJAX Portal" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_37551A39.png" width="600" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;I have published a new article on this on CodeProject:&lt;/p&gt;  &lt;p&gt;&lt;a title="Web 2.0 AJAX Portal using jQuery, ASP.NET 3.5, Silverlight, Linq to SQL, WF and Unity" href="http://www.codeproject.com/KB/ajax/Web20Portal.aspx"&gt;http://www.codeproject.com/KB/ajax/Web20Portal.aspx&lt;/a&gt;&lt;/p&gt;  &lt;h2&gt;Get the source code&lt;/h2&gt;  &lt;p&gt;Latest source code is hosted at Google code:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://code.google.com/p/dropthings"&gt;http://code.google.com/p/dropthings&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;There’s a CodePlex site for documentation and issue tracking:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.codeplex.com/dropthings"&gt;http://www.codeplex.com/dropthings&lt;/a&gt;&lt;/p&gt;  &lt;p&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.&lt;/p&gt;  &lt;h2&gt;New features introduced&lt;/h2&gt;  &lt;p&gt;Dropthings new release has the following features:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;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 &lt;code&gt;web.config&lt;/code&gt;. &lt;/li&gt;    &lt;li&gt;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. &lt;/li&gt;    &lt;li&gt;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. &lt;/li&gt;    &lt;li&gt;Role based widgets – now widgets are mapped to roles so that you can allow different users to see different widget list using &lt;code&gt;ManageWidgetPersmission.aspx.&lt;/code&gt; &lt;/li&gt;    &lt;li&gt;Role based page setup – you can define page setup for different roles. For ex, Managers see different pages and widgets than Employees. &lt;/li&gt;    &lt;li&gt;Widget maximize – you can maximize a widget to take full screen. Handy for widgets with lots of content. &lt;/li&gt;    &lt;li&gt;Free form resize – you can freely resize widgets vertically. &lt;/li&gt;    &lt;li&gt;Silverlight Widgets – You can now make widgets in Silverlight! &lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;Why the technology overhauling&lt;/h2&gt;  &lt;p&gt;Performance, Scalability, Maintainability and Extensibility – four key reasons for the overhauling. Each new technology solved one of more of these problems. &lt;/p&gt;  &lt;p&gt;First, jQuery was used to replace my personal hand-coded large amount of Javascript code that offered the client side drag &amp;amp; drop and other UI effects. jQuery already has a rich set of library for Drag &amp;amp; Drop, Animations, Event handling, cross browser javascript framework and so on. So, using jQuery means opening the door to thousands of jQuery plugins to be offered on Dropthings. This made Dropthings highly extensible on the client side. Moreover, jQuery is very light. Unlike AJAX Control Toolkit jumbo sized framework and heavy control extenders, jQuery is very lean. So, total javascript size decreased significantly resulting in improved page load time. In total, the jQuery framework, AJAX basic framework, all my stuffs are total 395KB, sweet! Performance is key; it makes or breaks a product.&lt;/p&gt;  &lt;p&gt;Secondly, Linq to SQL queries are replaced with Compiled Queries. Dropthings did not survive a load test when regular lambda expressions were used to query database. I could only reach up to 12 Req/Sec using 20 concurrent users without burning up web server CPU on a Quad Core DELL server. &lt;/p&gt;  &lt;p&gt;Thirdly, Workflow Foundation is used to build operations that require multiple Data Access Classes to perform together in a single transaction. Instead of writing large functions with many if…else conditions, for…loops, it’s better to write them in a Workflow because you can visually see the flow of execution and you can reuse Activities among different Workflows. Best of all, architects can design workflows and developers can fill-in code inside Activities. So, I could design a complex operations in a workflow without writing the real code inside Activities and then ask someone else to implement each Activity. It is like handing over a design document to developers to implement each unit module, only that here everything is strongly typed and verified by compiler. If you strictly follow Single Responsibility Principle for your Activities, which is a smart way of saying one Activity does only one and very simple task, you end up with a highly reusable and maintainable business layer and a very clean code that’s easily extensible.&lt;/p&gt;  &lt;p&gt;Fourthly, &lt;a title="Unity Dependency Injection framework" href="http://www.codeplex.com/unity" target="_blank"&gt;Unity&lt;/a&gt; Dependency Injection (DI) framework is used to pave the path for unit testing and dependency injection. It offers Inversion of Control (IoC), which enables testing individual classes in isolation. Moreover, it has a handy feature to control lifetime of objects. Instead of creating instance of commonly used classes several times within the same request, you can make instances thread level, which means only one instance is created per thread and subsequent calls reuse the same instance. Are these going over your head? No worries, continue reading, I will explain later on.&lt;/p&gt;  &lt;p&gt;Fifthly, enabling API for Silverlight widgets allows more interactive widgets to be built using Silverlight. HTML and Javascripts still have limitations on smooth graphics and continuous transmission of data from web server. Silverlight solves all of these problems.&lt;/p&gt;  &lt;p&gt;Read the article for details on how all these improvements were done and how all these hot techs play together in a very useful open source project for enterprises.&lt;/p&gt;  &lt;p&gt;&lt;a title="Web 2.0 AJAX Portal using jQuery, ASP.NET 3.5, Silverlight, Linq to SQL, WF and Unity" href="http://www.codeproject.com/KB/ajax/Web20Portal.aspx"&gt;http://www.codeproject.com/KB/ajax/Web20Portal.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Don’t forget to vote for me if you like it.&lt;/p&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/2009/04/08/web-2-0-ajax-portal-using-jquery-asp-net-3-5-silverlight-linq-to-sql-wf-and-unity.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http://msmvps.com/blogs/omar/archive/2009/04/08/web-2-0-ajax-portal-using-jquery-asp-net-3-5-silverlight-linq-to-sql-wf-and-unity.aspx&amp;amp;bgcolor=0080C0&amp;amp;fgcolor=FFFFFF&amp;amp;border=000000&amp;amp;cbgcolor=808080&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=1685991" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/linq/default.aspx">linq</category><category domain="http://msmvps.com/blogs/omar/archive/tags/workflow/default.aspx">workflow</category><category domain="http://msmvps.com/blogs/omar/archive/tags/javascript/default.aspx">javascript</category><category domain="http://msmvps.com/blogs/omar/archive/tags/ajax/default.aspx">ajax</category><category domain="http://msmvps.com/blogs/omar/archive/tags/.net/default.aspx">.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/silverlight/default.aspx">silverlight</category></item><item><title>Optimize ASP.NET Membership Stored Procedures for greater speed and scalability</title><link>http://msmvps.com/blogs/omar/archive/2009/03/13/optimize-asp-net-membership-stored-procedures-for-greater-speed-and-scalability.aspx</link><pubDate>Fri, 13 Mar 2009 13:23:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1678004</guid><dc:creator>omar</dc:creator><slash:comments>8</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1678004</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2009/03/13/optimize-asp-net-membership-stored-procedures-for-greater-speed-and-scalability.aspx#comments</comments><description>&lt;p&gt;Last year at &lt;a href="http://www.pageflakes.com" title="Pageflakes - Web 2.0 AJAX portal" target="_blank"&gt;Pageflakes&lt;/a&gt;, 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 &lt;code&gt;aspnet_Users&lt;/code&gt; and &lt;code&gt;aspnet_Membership&lt;/code&gt; 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 &lt;code&gt;aspnet_Users&lt;/code&gt;), 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;/p&gt;
&lt;p&gt;If you have &lt;a href="http://msmvps.com/blogs/omar/archive/2009/03/07/linq-to-sql-solve-transaction-deadlock-and-query-timeout-problem-using-uncommitted-reads.aspx" title="Solve Transaction Deadlock and Lock Contention in Linq to Sql" target="_blank"&gt;read my last blog post&lt;/a&gt;, 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;/p&gt;
&lt;p&gt;The solution is simple, you should either have &lt;code&gt;WITH (NOLOCK)&lt;/code&gt; or &lt;code&gt;SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED&lt;/code&gt; 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 &lt;code&gt;LastActivityDate&lt;/code&gt; 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 &lt;code&gt;LastActivityDate&lt;/code&gt; on &lt;code&gt;aspnet_Users&lt;/code&gt; table?&lt;/p&gt;
&lt;p&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 &lt;code&gt;Profile&lt;/code&gt; object:&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;ALTER PROCEDURE &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;[dbo]&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;[aspnet_Profile_GetProperties]&lt;br /&gt;    @ApplicationName      &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;nvarchar&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#8acccf;"&gt;256&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;),&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserName             &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;nvarchar&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#8acccf;"&gt;256&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;),&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@CurrentTimeUtc       &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;datetime&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;&lt;br /&gt;    DECLARE &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;uniqueidentifier&lt;br /&gt;    SELECT  &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;NULL&lt;br /&gt;    SELECT  &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;FROM &lt;br /&gt;&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;      dbo&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;aspnet_Applications &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;WHERE LOWER&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@ApplicationName&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;) = &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;LoweredApplicationName&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;IF &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;IS NULL&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;)&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;RETURN&lt;br /&gt;&lt;br /&gt;    DECLARE &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;uniqueidentifier&lt;br /&gt;    DECLARE &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@LastActivityDate &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;datetime&lt;br /&gt;    SELECT  &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;NULL&lt;br /&gt;&lt;br /&gt;    SELECT &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;UserId&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@LastActivityDate &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;LastActivityDate&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;FROM   &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;dbo&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;aspnet_Users &lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;WHERE  &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;AND &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;LoweredUserName &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;LOWER&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserName&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;)&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;IF &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;IS NULL&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;)&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;RETURN&lt;br /&gt;    SELECT TOP &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#8acccf;"&gt;1 &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;PropertyNames&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;PropertyValuesString&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;PropertyValuesBinary&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;FROM         &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;dbo&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;aspnet_Profile&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;WHERE        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;IF &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@@ROWCOUNT &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#8acccf;"&gt;0&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;)&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;BEGIN&lt;br /&gt;        UPDATE &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;dbo&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;aspnet_Users&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;SET    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;LastActivityDate&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;=&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@CurrentTimeUtc&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;WHERE  &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;END&lt;br /&gt;END&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;There are two SELECT operations that hold lock on two very high read tables &amp;ndash; &lt;code&gt;aspnet_Users&lt;/code&gt; and &lt;code&gt;aspnet_Profile&lt;/code&gt;. Moreover, there&amp;rsquo;s a nasty UPDATE statement. It tries to update the &lt;code&gt;LastActivityDate&lt;/code&gt; of a user whenever you access &lt;code&gt;Profile&lt;/code&gt; object for the first time within a http request. &lt;/p&gt;
&lt;p&gt;This stored proc alone is enough to bring your site down. It did to us because we are using &lt;code&gt;Profile&lt;/code&gt; Provider everywhere. This stored proc was called around 300 times/sec. We were having nightmarish slow performance on the website and many lock timeouts and transaction deadlocks. So, we added the transaction isolation level and we also modified the UPDATE statement to only perform an update when the &lt;code&gt;LastActivityDate&lt;/code&gt; is over an hour. So, this means, the same user&amp;rsquo;s &lt;code&gt;LastActivityDate&lt;/code&gt; won&amp;rsquo;t be updated if the user hits the site within the same hour.&lt;/p&gt;
&lt;p&gt;So, after the modifications, the stored proc looked like this:&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;ALTER PROCEDURE &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;[dbo]&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;[aspnet_Profile_GetProperties]&lt;br /&gt;    @ApplicationName      &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;nvarchar&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#8acccf;"&gt;256&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;),&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserName             &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;nvarchar&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#8acccf;"&gt;256&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;),&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@CurrentTimeUtc       &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;datetime&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#7f9f7f;"&gt;-- 1. Please no more locks during reads&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;;&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;DECLARE &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;uniqueidentifier&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#7f9f7f;"&gt;--SELECT  @ApplicationId = NULL&lt;br /&gt;    --SELECT  @ApplicationId = ApplicationId FROM dbo.aspnet_Applications &lt;br /&gt;    WHERE LOWER(@ApplicationName) = LoweredApplicationName&lt;br /&gt;    --IF (@ApplicationId IS NULL)&lt;br /&gt;    --    RETURN&lt;br /&gt;    &lt;br /&gt;    -- 2. No more call to Application table. We have only one app dude!&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;SET &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;dbo&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;udfGetAppId&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;()&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;DECLARE &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;uniqueidentifier&lt;br /&gt;    DECLARE &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@LastActivityDate &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;datetime&lt;br /&gt;    SELECT  &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;NULL&lt;br /&gt;&lt;br /&gt;    SELECT &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;UserId&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@LastActivityDate &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;LastActivityDate&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;FROM   &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;dbo&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;aspnet_Users &lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;WHERE  &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;AND &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;LoweredUserName &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;LOWER&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserName&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;)&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;IF &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;IS NULL&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;)&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;RETURN&lt;br /&gt;    SELECT TOP &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#8acccf;"&gt;1 &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;PropertyNames&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;PropertyValuesString&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;PropertyValuesBinary&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;FROM         &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;dbo&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;aspnet_Profile&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;WHERE        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;IF &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@@ROWCOUNT &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#8acccf;"&gt;0&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;)&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;BEGIN&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#7f9f7f;"&gt;-- 3. Do not update the same user within an hour&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;IF DateDiff&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;n&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@LastActivityDate&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@CurrentTimeUtc&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;) &amp;gt; &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#8acccf;"&gt;60&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;BEGIN&lt;br /&gt;            &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#7f9f7f;"&gt;-- 4. Use ROWLOCK to lock only a row since we know this query&lt;br /&gt;            -- is highly selective&lt;br /&gt;            &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;UPDATE &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;dbo&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;aspnet_Users &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;WITH&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;ROWLOCK&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;)&lt;br /&gt;            &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;SET    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;LastActivityDate&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;=&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@CurrentTimeUtc&lt;br /&gt;            &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;WHERE  &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;END&lt;br /&gt;    END&lt;br /&gt;END&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;The changes I made are numbered and commented. No need for further explanation. The only tricky thing here is, I have eliminate call to Application table just to get the ApplicationID from ApplicationName. Since there&amp;rsquo;s only one application in a database (ever heard of multiple applications storing their user separately on the same database and the same table?), we don&amp;rsquo;t need to look up the ApplicationID on every call to every Membership stored proc. We can just get the ID and hard code it in a function.&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;CREATE FUNCTION &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;dbo&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;udfGetAppId&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;()&lt;br /&gt;&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;RETURNS uniqueidentifier&lt;br /&gt;WITH EXECUTE AS &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;CALLER&lt;br /&gt;&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;    RETURN CONVERT&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;uniqueidentifier&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#c89191;"&gt;&amp;#39;fd639154-299a-4a9d-b273-69dc28eb6388&amp;#39;&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;)&lt;br /&gt;&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;END&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;This UDF returns the &lt;code&gt;ApplicationID&lt;/code&gt; that I have hardcoded copying from the Application table. Thus it eliminates the need for quering on the Application table. &lt;/p&gt;
&lt;p&gt;Similarly you should do the changes in all other stored procedures that belong to Membership Provider. All the stroc procs are missing proper locking, issues aggressive lock during update and too frequent updates than practical need. Most of them also try to resolve ApplicationID from ApplicationName, which is unnecessary when you have only one web application per database. Make these changes and enjoy lock contention free super performance from Membership Provider!&lt;/p&gt;
&lt;div class="wlWriterHeaderFooter" style="margin:0px;padding:4px;text-align:left;"&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 src="http://widgets.dzone.com/widgets/zoneit.js" language="javascript"&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%2f2009%2f03%2f14%2foptimize-asp-net-membership-stored-procedures-for-greater-speed-and-scalability.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2009%2f03%2f14%2foptimize-asp-net-membership-stored-procedures-for-greater-speed-and-scalability.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=1678004" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/sql+server/default.aspx">sql server</category><category domain="http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx">performance</category><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/.net/default.aspx">.net</category></item><item><title>99.99% available ASP.NET and SQL Server SaaS Production Architecture</title><link>http://msmvps.com/blogs/omar/archive/2008/12/10/99-99-available-asp-net-and-sql-server-saas-production-architecture.aspx</link><pubDate>Wed, 10 Dec 2008 08:39:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1656383</guid><dc:creator>omar</dc:creator><slash:comments>4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1656383</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/12/10/99-99-available-asp-net-and-sql-server-saas-production-architecture.aspx#comments</comments><description>&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;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/sql+server/default.aspx">sql server</category><category domain="http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx">performance</category><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/pageflakes/default.aspx">pageflakes</category><category domain="http://msmvps.com/blogs/omar/archive/tags/production/default.aspx">production</category><category domain="http://msmvps.com/blogs/omar/archive/tags/architecture/default.aspx">architecture</category></item><item><title>ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy</title><link>http://msmvps.com/blogs/omar/archive/2008/10/06/asp-net-website-continuous-integration-deployment-using-cruisecontrol-net-subversion-msbuild-and-robocopy.aspx</link><pubDate>Mon, 06 Oct 2008 06:59:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1649873</guid><dc:creator>omar</dc:creator><slash:comments>16</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1649873</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/10/06/asp-net-website-continuous-integration-deployment-using-cruisecontrol-net-subversion-msbuild-and-robocopy.aspx#comments</comments><description>&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, 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;modificationWriter&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;filename&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;mods.xml&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;filename&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;path&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;path&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;modificationWriter&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;&amp;nbsp; &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;!-- MSBuild task to build a .msbuild file that basically builds a .sln file --&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;msbuild&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;executable&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;C:\windows\Microsoft.NET\Framework64\v3.5\MSBuild.exe&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;executable&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:#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:#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;projectFile&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;Dropthings.msbuild&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;projectFile&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;targets&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;Build&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;targets&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;timeout&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;300&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;timeout&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;logger&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;C:\Program Files (x86)\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;logger&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;msbuild&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;This block first says, keep artifacts for last 5 build and remove olders. Artifacts are like build reports, logs etc. You can increase the value for longer history.&lt;/p&gt;
&lt;p&gt;Then the most important &lt;span style="text-decoration:underline;"&gt;&amp;lt;msbuild&amp;gt;&lt;/span&gt; task. The executable path is to the MSBuild.exe. I am using .NET 3.5 Framework 64bit edition. You might have .NET 2.0 and 32bit version. So, set the right path here for the MSbuild.exe.&lt;/p&gt;
&lt;p&gt;&lt;span style="text-decoration:underline;"&gt;&amp;lt;projectFile&amp;gt;&lt;/span&gt; maps to a MSBuild file. It&amp;#39;s a skeleton MSBuild file which basically says build this Visual Studio solution file. Here&amp;#39;s how the msbuild file looks like:&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Project&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;DefaultTargets&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Build&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;xmlns&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;http://schemas.microsoft.com/developer/msbuild/2003&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Target&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Build&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:#008000;"&gt;&amp;lt;!-- Rebuild entire solution --&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;MSBuild&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Projects&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Dropthings.sln&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Targets&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Rebuild&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:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Target&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:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Project&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;The &lt;span style="text-decoration:underline;"&gt;Dropthings.msbuild&lt;/span&gt; and &lt;span style="text-decoration:underline;"&gt;Dropthings.sln&lt;/span&gt; file exists in the same trunk folder. This file says - build Dropthings.sln and do a rebuild.&lt;/p&gt;
&lt;p&gt;Now you got the build done. Next is to deploy it. You will be using robocopy to copy files from the code folder to a destination folder which is mapped in IIS to a website. Robocopy will do a synchronization of the directories. It will add new files, overwrite old files and removes files from destination folder which no longer exists in the source folder. &lt;/p&gt;
&lt;p&gt;Before you can deploy, you need to stop the website or restart IIS. Otherwise some files may be in use and you will not be able to delete or overwrite the files. Here&amp;#39;s how to stop IIS using the &lt;span style="text-decoration:underline;"&gt;iisreset&lt;/span&gt; command line tool:&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:#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:#008000;"&gt;Stop IIS before copying over the latest web project files so that there&amp;#39;s no write lock and IIS does not&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:#008000;"&gt;start restarting the site half way through&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:#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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;exec&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;executable&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;iisreset&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;executable&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;buildArgs&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;/stop&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;buildArgs&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:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;exec&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;If you do not want to stop the entire IIS, instead just stop a website and recycle an application pool, you can use the iisweb.vbs script for stopping a website and iisapp.vbs script for recycling application pool. Here&amp;#39;s an example:&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;exec&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;executable&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;iisweb&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;executable&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;buildArgs&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;/stop &amp;quot;Dropthings&amp;quot;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;buildArgs&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:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;exec&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;&amp;nbsp;&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;exec&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;executable&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;iisapp&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;executable&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;buildArgs&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt; /a &amp;quot;Dropthings&amp;quot; /r&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;buildArgs&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:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;exec&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;You need to first register &lt;span style="text-decoration:underline;"&gt;cscript&lt;/span&gt; as the default script runtime. In order to do this, go to command line and enter iisweb. It will tell you that it cannot use wscript to run this script and it needs to make cscript default. Let it make cscript as default.&lt;/p&gt;
&lt;p&gt;Now the time to do the deployment of latest web site files. The following task launches robocopy to do the deployment:&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:#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:#008000;"&gt;Sync the web project folder with the deployment folder. The deployment folder is where IIS&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:#008000;"&gt;is mapped to serve the site. The deployment folder is at the buildArgs node. The robocopy &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:#008000;"&gt;utility does an exact sync, adding new files, updating old files, deleting files that no longer&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:#008000;"&gt;exist.&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:#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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;exec&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:#008000;"&gt;&amp;lt;!--&amp;lt;executable&amp;gt;C:\Program Files (x86)\Windows Resource Kits\Tools\robocopy.exe&amp;lt;/executable&amp;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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;executable&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;robocopy.exe&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;executable&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;baseDirectory&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;baseDirectory&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;buildArgs&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;.\ d:\cc\Dropthings\Deploy *.* /E /XA:H /PURGE /XO /XD &amp;quot;.svn&amp;quot; /NDL /NC /NS /NP&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;buildArgs&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;buildTimeoutSeconds&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;buildTimeoutSeconds&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;successExitCodes&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;1,0&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;successExitCodes&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:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;exec&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 you need to correct the robocopy.exe path. For Windows Vista/Windows 2008, keep it as it is. For Windows 2003, you need to specify the full path. You also need to remove the (x86) from the path if you have 32bit OS.&lt;/p&gt;
&lt;p&gt;Next is the &lt;span style="text-decoration:underline;"&gt;&amp;lt;baseDirectory&amp;gt;.&lt;/span&gt; This is relative to the working directory. It&amp;#39;s the path of the website folder. Dropthings website folder is located under the Dropthings folder under trunk. So, I have specified Dropthings\ as the subfolder where the website files are located. You need to specify your project&amp;#39;s website folder&amp;#39;s relative path here form the &lt;span style="text-decoration:underline;"&gt;&amp;lt;workingDirectory&amp;gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Next change the path in the &lt;span style="text-decoration:underline;"&gt;&amp;lt;buildArgs&amp;gt;&lt;/span&gt; node. First one is the source &amp;quot;.\&amp;quot; which you keep as it is. It means copy files from the &lt;span style="text-decoration:underline;"&gt;baseDirectory&lt;/span&gt;. Next is the absolute path to the deployment folder where the web site is mapped in IIS. You can use both relative or absolute path here. While using relative path, just keep in mind the robocopy is running from the &amp;lt;workingDirectory&amp;gt;\&amp;lt;baseDirectory&amp;gt; folder.&lt;/p&gt;
&lt;p&gt;After the path keep the *.* and the remaining flags intact. The flags mean:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Copy all subdirectories /E&lt;/li&gt;
&lt;li&gt;Copy hidded files /XA:H&lt;/li&gt;
&lt;li&gt;Do not copy old files /XO&lt;/li&gt;
&lt;li&gt;Exclude .svn directory while copying files /XD &amp;quot;.svn&amp;quot;&lt;/li&gt;
&lt;li&gt;Do not show list of files and directories being copie /NDL, /NC, /NP&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After the deployment, you need to turn IIS back on or start the website that you stopped:&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:#008000;"&gt;&amp;lt;!-- Turn IIS back on --&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;exec&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;executable&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;iisreset&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;executable&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;buildArgs&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;/start&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;buildArgs&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:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;exec&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;&amp;nbsp;&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:#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:#008000;"&gt;&amp;lt;exec&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:#008000;"&gt;    &amp;lt;executable&amp;gt;iisweb&amp;lt;/executable&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:#008000;"&gt;    &amp;lt;buildArgs&amp;gt;/start &amp;quot;Dropthings&amp;quot;&amp;lt;/buildArgs&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:#008000;"&gt;&amp;lt;/exec&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:#008000;"&gt;--&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now we got the build and deployment done. Next is to email a nice report to developers and QA. If build succeeds, email both developers and QA so that they can check out the latest build. But if build fails, email only developers.&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;publishers&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;rss&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;xmllogger&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;statistics&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;&amp;nbsp;&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:#008000;"&gt;&amp;lt;!-- Email build report to development and QA team --&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;email&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;from&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;admin@yourcompany.com&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;mailhost&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;localhost&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;mailport&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;25&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;includeDetails&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;TRUE&amp;quot;&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:#ff0000;"&gt;mailhostUsername&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;mailhostPassword&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;useSSL&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;FALSE&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;&amp;nbsp;&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;users&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;user&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Developer1&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;group&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;devs&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;address&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;dev1@yourcompany.com&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;user&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Developer2&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;group&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;devs&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;address&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;dev2@yourcompany.com&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;user&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Developer3&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;group&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;devs&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;address&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;dev3@yourcompany.com&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;/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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;user&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;QA1&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;group&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;qa&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;address&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;qa1@yourcompany.com&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;user&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;QA2&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;group&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;qa&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;address&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;qa2@yourcompany.com&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;user&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;QA3&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;group&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;qa&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;address&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;qa3@yourcompany.com&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;/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:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;users&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;&amp;nbsp;&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;groups&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;group&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;devs&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;notification&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Always&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;group&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;qa&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;notification&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Success&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:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;groups&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;&amp;nbsp;&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;converters&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:#008000;"&gt;&amp;lt;!--&amp;lt;regexConverter find=&amp;quot;$&amp;quot; replace=&amp;quot;@dropthings.com&amp;quot; /&amp;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:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;converters&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;&amp;nbsp;&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;modifierNotificationTypes&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;NotificationType&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;Always&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;NotificationType&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:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;modifierNotificationTypes&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;&amp;nbsp;&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:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;email&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:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;modificationHistory&lt;/span&gt;  &lt;span style="color:#ff0000;"&gt;onlyLogWhenChangesFound&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;true&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:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;publishers&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 you need to change the &lt;span style="text-decoration:underline;"&gt;&amp;lt;email&amp;gt;&lt;/span&gt; tab where you specify the from address, mail server name, and optionally a user account for the email address that you need to use to send out emails.&lt;/p&gt;
&lt;p&gt;Then edit the &lt;span style="text-decoration:underline;"&gt;&amp;lt;users&amp;gt;&lt;/span&gt; node and put your developers and QA.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s it! You got the configuration file done. Next step is to launch the CruiseControl.NET from Programs -&amp;gt; CruiseControl.NET -&amp;gt; CruiseControl.NET. It will launch a process that will execute the tasks according to the configuration. On Windows Vista, you will have to run it with Administrative privilege.&lt;/p&gt;
&lt;p&gt;There&amp;#39;s also a Windows Service that gets installed. It&amp;#39;s named CruiseControl.NET. You can start the service as well on a server and go to sleep. It will do continuous integration and automated deployment for you.&lt;/p&gt;
&lt;p&gt;There&amp;#39;s also a web based Dashboard that you can use to force a build or stop a build or see detail build reports.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.SetupASP.NETwebs.NETSubversionandMSBuild_5F00_D35/image_5F00_2.png"&gt;&lt;img border="0" width="604" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.SetupASP.NETwebs.NETSubversionandMSBuild_5F00_D35/image_5F00_thumb.png" alt="image" height="272" style="border-right:0px;border-top:0px;border-left:0px;border-bottom:0px;" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;You can create multiple projects. You can have one project to build trunk code only, but do no deployment. Then you can create another project to build, deploy some branch that&amp;#39;s ready for production. You can create another project to build and deploy on QA server and so on. &lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/ccnet.zip"&gt;Here&amp;#39;s the full configuration file&lt;/a&gt; that you can use as your baseline.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px;" id="scid:B3E14793-948F-49af-A347-D19C374A7C4F:f699e682-0ab4-4a9d-97ad-c7aa1944438d" class="wlWriterSmartContent"&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="http://digg.com/tools/diggthis.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%2f06%2fasp-net-website-continuous-integration-deployment-using-cruisecontrol-net-subversion-msbuild-and-robocopy.aspx"&gt;&lt;img alt="kick it on DotNetKicks.com" border="0" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f10%2f06%2fasp-net-website-continuous-integration-deployment-using-cruisecontrol-net-subversion-msbuild-and-robocopy.aspx" /&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=1649873" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/misc/default.aspx">misc</category><category domain="http://msmvps.com/blogs/omar/archive/tags/production/default.aspx">production</category></item><item><title>Best practices for creating websites in IIS 6.0</title><link>http://msmvps.com/blogs/omar/archive/2008/10/04/best-practices-for-creating-websites-in-iis-6-0.aspx</link><pubDate>Sat, 04 Oct 2008 10:05:22 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1649697</guid><dc:creator>omar</dc:creator><slash:comments>20</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1649697</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/10/04/best-practices-for-creating-websites-in-iis-6-0.aspx#comments</comments><description>&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;/p&gt; &lt;p&gt;&lt;strong&gt;Create a separate application pool for each web application&lt;/strong&gt;&lt;/p&gt; &lt;p&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 &lt;u&gt;DefaultAppPool&lt;/u&gt; does not give me the flexibility to control these per site.&lt;/p&gt; &lt;p&gt;The more app pool you create, the more ASP.NET threads you make available to your application. Each &lt;u&gt;w3wp.exe&lt;/u&gt; has it&amp;#39;s own thread pool. So, if some application is congesting particular &lt;u&gt;w3wp.exe&lt;/u&gt; process, other applications can run happily on their separate &lt;u&gt;w3wp.exe&lt;/u&gt; instance, running under separate app pool. Each app pool hosts its own &lt;u&gt;w3wp.exe&lt;/u&gt; instance.&lt;/p&gt; &lt;p&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;/p&gt; &lt;p&gt;Another best practice: Disable the &lt;u&gt;DefaultAppPool&lt;/u&gt; so that you don&amp;#39;t mistakenly keep adding sites to &lt;u&gt;DefaultAppPool&lt;/u&gt;.&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.BestpracticesforcreatingwebsitesinIIS6.0_5F00_CC6A/image_5F00_4.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="340" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.BestpracticesforcreatingwebsitesinIIS6.0_5F00_CC6A/image_5F00_thumb_5F00_1.png" width="664" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&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;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.BestpracticesforcreatingwebsitesinIIS6.0_5F00_CC6A/image_5F00_6.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="501" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.BestpracticesforcreatingwebsitesinIIS6.0_5F00_CC6A/image_5F00_thumb_5F00_2.png" width="620" border="0" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Customize Website properties for performance, scalability and maintainability&lt;/strong&gt;&lt;/p&gt; &lt;p&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 &lt;a href="http://www.domain.com"&gt;www.domain.com&lt;/a&gt;. 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;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.BestpracticesforcreatingwebsitesinIIS6.0_5F00_CC6A/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="493" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.BestpracticesforcreatingwebsitesinIIS6.0_5F00_CC6A/image_5F00_thumb_5F00_4.png" width="648" border="0" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Next turn on some log entries:&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.BestpracticesforcreatingwebsitesinIIS6.0_5F00_CC6A/image_5F00_12.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="458" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.BestpracticesforcreatingwebsitesinIIS6.0_5F00_CC6A/image_5F00_thumb_5F00_5.png" width="605" border="0" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&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, &lt;a title="s" href="http://awstats.sourceforge.net/"&gt;open source AWStats&lt;/a&gt;. &lt;/p&gt; &lt;p&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 you are using ASP.NET Forms Authentication, the gigantic cookie coming with every request will produce gigabytes of logs per week if you have a medium traffic website.&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.BestpracticesforcreatingwebsitesinIIS6.0_5F00_CC6A/image_5F00_14.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="269" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.BestpracticesforcreatingwebsitesinIIS6.0_5F00_CC6A/image_5F00_thumb_5F00_6.png" width="473" border="0" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;This is kinda no brainer. I add Default.aspx as the default content page so that, when visitors hit the site without any .aspx page name, e.g. alzabir.com, they get the default.aspx served.&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.BestpracticesforcreatingwebsitesinIIS6.0_5F00_CC6A/image_5F00_16.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="461" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.BestpracticesforcreatingwebsitesinIIS6.0_5F00_CC6A/image_5F00_thumb_5F00_7.png" width="475" border="0" /&gt;&lt;/a&gt;&amp;nbsp; &lt;/p&gt; &lt;p&gt;Things I do here:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Turn on Content Expiration. This makes static files remain in browser cache for 30 days and browser serves the files from its own cache instead of hitting the server. As a result, when your users revisit, they don&amp;#39;t download all the static files like images, javascripts, css files again and again. This one setting significantly improves your site&amp;#39;s performance.  &lt;li&gt;Remove the &lt;u&gt;X-Powered-By: ASP.NET&lt;/u&gt; header. You really don&amp;#39;t need it unless you want to attach Visual Studio Remote Debugger to your IIS. Otherwise, it&amp;#39;s just sending 21 bytes on every response.  &lt;li&gt;Add &amp;quot;From&amp;quot; header and set the server name. I do this on each webserver and specify different names on each box. It&amp;#39;s handy to see from which servers requests are being served. When you are trying to troubleshoot load balancing issues, it comes handy to see if a particular server is sending requests. &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.BestpracticesforcreatingwebsitesinIIS6.0_5F00_CC6A/image_5F00_18.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="465" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.BestpracticesforcreatingwebsitesinIIS6.0_5F00_CC6A/image_5F00_thumb_5F00_8.png" width="538" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;I set the 404 handler to some ASPX so that I can show some custom error message. There&amp;#39;s a 404.aspx which shows some nice friendly message and suggests some other pages that user can visit. However, another reason to use this custom mapping is to serve extensionless URL from IIS. &lt;a href="http://msmvps.com/blogs/omar/archive/2007/04/29/serve-extensionless-url-from-asp-net-without-using-isapi-module-or-iis-6-wildcard-mapping.aspx"&gt;Read this blog post for details&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.BestpracticesforcreatingwebsitesinIIS6.0_5F00_CC6A/image_5F00_20.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="459" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.BestpracticesforcreatingwebsitesinIIS6.0_5F00_CC6A/image_5F00_thumb_5F00_9.png" width="471" border="0" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Make sure to set ASP.NET 2.0 for your ASP.NET 2.0, 3.0 and 3.5 websites.&lt;/p&gt; &lt;p&gt;Finally, you must, I repeat you &amp;quot;MUST&amp;quot; &lt;a href="http://msmvps.com/blogs/omar/archive/2006/08/10/iis-6-compression-quickest-and-effective-way-to-do-it-for-asp-net-compression.aspx"&gt;turn on IIS 6.0 gzip compression&lt;/a&gt;. This turns on the Volkswagen V8 engine that is built into IIS to make your site screaming fast.&lt;/p&gt; &lt;div class="wlWriterSmartContent" id="scid:B3E14793-948F-49af-A347-D19C374A7C4F:c9260f79-7b63-4c02-96a4-1a4a412a5a65" style="padding-right:0px;display:inline;padding-left:0px;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;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f10%2f04%2fbest-practices-for-creating-websites-in-iis-6-0.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%2f04%2fbest-practices-for-creating-websites-in-iis-6-0.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=1649697" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx">performance</category><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/production/default.aspx">production</category><category domain="http://msmvps.com/blogs/omar/archive/tags/IIS/default.aspx">IIS</category></item><item><title>Create ASP.NET MVC Controllers under Namespace and specific URL</title><link>http://msmvps.com/blogs/omar/archive/2008/10/04/create-asp-net-mvc-controllers-under-namespace-and-specific-url.aspx</link><pubDate>Sat, 04 Oct 2008 08:06:21 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1649692</guid><dc:creator>omar</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1649692</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/10/04/create-asp-net-mvc-controllers-under-namespace-and-specific-url.aspx#comments</comments><description>&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 &lt;u&gt;/Admin/User&lt;/u&gt; where &lt;u&gt;Admin&lt;/u&gt; is the subfolder and &lt;u&gt;User&lt;/u&gt; 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 &lt;u&gt;/API/&lt;/u&gt; folder. You also want to make sure no one can access those controllers from the root url. For example, no one must call &lt;u&gt;/User/GetUserList&lt;/u&gt; instead they must call &lt;u&gt;/API/User/GetUserList&lt;/u&gt;&lt;/p&gt; &lt;p&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 &lt;u&gt;DefaultControllerFactory&lt;/u&gt; 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 &lt;u&gt;/Admin&lt;/u&gt; folder to respond to all controllers that are under then &lt;u&gt;YourWebApp.Admin&lt;/u&gt; namespace. Similarly, you can map &lt;u&gt;/API&lt;/u&gt; folder to respond to all controllers that are under the &lt;u&gt;YourWebApp.API&lt;/u&gt; namespace. None of these controllers can be accessed outside the specified URL. Here&amp;#39;s the factory that does it:&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Cre.NETMVCControllersunderNamespaceandsp_5F00_C141/image_5F00_2.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="410" alt="ProtectedNamespaceController Factory that replaces DefaultControllerFactory" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Cre.NETMVCControllersunderNamespaceandsp_5F00_C141/image_5F00_thumb.png" width="724" border="0" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&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 &lt;u&gt;MvcWebAPI.API.UserController&lt;/u&gt;, it ensures the URL being requested must be &lt;u&gt;/MvcWebAPI/API/User&lt;/u&gt;. It will return null if the URL was something else like &lt;u&gt;/MvcWebAPI/User&lt;/u&gt; or &lt;u&gt;/MvcWebAPI/SomeotherFolder/User&lt;/u&gt;.&lt;/p&gt; &lt;p&gt;Here&amp;#39;s how you use it form &lt;u&gt;Global.asax&lt;/u&gt;:&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Cre.NETMVCControllersunderNamespaceandsp_5F00_C141/image_5F00_6.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="241" alt="Using ProtectedNamespaceControllerFactory from Global.asax" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Cre.NETMVCControllersunderNamespaceandsp_5F00_C141/image_5F00_thumb_5F00_2.png" width="556" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&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;/p&gt; &lt;p&gt;Now the second catch is, the default Route for the &lt;u&gt;{controller}/{action}/{id}&lt;/u&gt; won&amp;#39;t work for you. You need to create a specific router that starts with the subfolder name. For example, &lt;u&gt;API/{controller}/{action}&lt;/u&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Cre.NETMVCControllersunderNamespaceandsp_5F00_C141/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="111" alt="Creating a new route for the Controllers under the /API folder" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Cre.NETMVCControllersunderNamespaceandsp_5F00_C141/image_5F00_thumb_5F00_4.png" width="513" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Here&amp;#39; two things to notice:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;The use of &lt;u&gt;PathStartWith&lt;/u&gt; routing constraint, which I will explain soon  &lt;li&gt;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;/li&gt;&lt;/ul&gt; &lt;p&gt;So, the &lt;u&gt;PathStartsWith&lt;/u&gt; routing constraint ensures this route gets hit only when the requested URL is under the &lt;u&gt;/API/&lt;/u&gt; folder. For any other URL, it returns false and thus the routing handler skips this route.&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Cre.NETMVCControllersunderNamespaceandsp_5F00_C141/image_5F00_12.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="239" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Cre.NETMVCControllersunderNamespaceandsp_5F00_C141/image_5F00_thumb_5F00_5.png" width="761" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;It just does a comparison on the &lt;u&gt;AbsolutePath&lt;/u&gt; of the current request URL to ensure the URL starts with the specified match. &lt;/p&gt; &lt;p&gt;Similarly, we need to tell the Default route to ignore all paths with &lt;u&gt;/API&lt;/u&gt;. Here&amp;#39;s how to do it:&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Cre.NETMVCControllersunderNamespaceandsp_5F00_C141/image_5F00_14.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="110" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Cre.NETMVCControllersunderNamespaceandsp_5F00_C141/image_5F00_thumb_5F00_6.png" width="540" border="0" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;That&amp;#39;s it. Enjoy the full code from:&lt;/p&gt; &lt;p&gt;&lt;a title="http://code.msdn.microsoft.com/MvcWebAPI" href="http://code.msdn.microsoft.com/MvcWebAPI"&gt;http://code.msdn.microsoft.com/MvcWebAPI&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Read my previous post on creating Web API using ASP.NET MVC that can consume and expose Json and Xml:&lt;/p&gt; &lt;p&gt;&lt;a title="http://msmvps.com/blogs/omar/archive/2008/10/03/create-rest-api-using-asp-net-mvc-that-speaks-both-json-and-plain-xml.aspx" href="http://msmvps.com/blogs/omar/archive/2008/10/03/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;/p&gt; &lt;p&gt;Note: incase you already read it, I have published new code that you should download.&lt;/p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2fdefault.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%2fdefault.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=1649692" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/MVC/default.aspx">MVC</category></item><item><title>Create REST API using ASP.NET MVC that speaks both Json and plain Xml</title><link>http://msmvps.com/blogs/omar/archive/2008/10/03/create-rest-api-using-asp-net-mvc-that-speaks-both-json-and-plain-xml.aspx</link><pubDate>Fri, 03 Oct 2008 16:05:51 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1649607</guid><dc:creator>omar</dc:creator><slash:comments>17</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1649607</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/10/03/create-rest-api-using-asp-net-mvc-that-speaks-both-json-and-plain-xml.aspx#comments</comments><description>&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;/p&gt; &lt;p&gt;There are some challenges to solve in order to expose REST API:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;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.  &lt;li&gt;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;/li&gt;&lt;/ul&gt; &lt;p&gt;I have created an &lt;u&gt;ObjectResult&lt;/u&gt; class which takes an object and generates Xml or Json output automatically looking at the &lt;u&gt;Content-Type&lt;/u&gt; header of &lt;u&gt;HttpRequest&lt;/u&gt;. AJAX calls send &lt;u&gt;Content-Type=application/json&lt;/u&gt;. So, it generates Json as response in that case, but when Content-Type is something else, it does simple Xml Serialzation. &lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.CreateJSONandXMLWebAPIusingASP.NETMVC_5F00_F635/image_5F00_2.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="471" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.CreateJSONandXMLWebAPIusingASP.NETMVC_5F00_F635/image_5F00_thumb.png" width="670" border="0" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Here&amp;#39;s the &lt;u&gt;ObjectResult&lt;/u&gt; 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. &lt;u&gt;XmlSerialization&lt;/u&gt; is a bit complex though:&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.CreateJSONandXMLWebAPIusingASP.NETMVC_5F00_F635/image_5F00_4.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="409" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.CreateJSONandXMLWebAPIusingASP.NETMVC_5F00_F635/image_5F00_thumb_5F00_1.png" width="592" border="0" /&gt;&lt;/a&gt; Things to note here:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;You have to force UTF8 encoding. Otherwise it produces UTF16 output.  &lt;li&gt;XML Declaration is skipped because that&amp;#39;s not quite necessary. Wastes bandwidth. If you need it, turn it on.  &lt;li&gt;I have turned on indenting for better readability. You can turn it off to save bandwidth.&lt;/li&gt;&lt;/ul&gt; &lt;p&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;/p&gt; &lt;p&gt;Now back to Object Serialization, we got the serialization done. Now you can return objects from Controller easily:&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.CreateJSONandXMLWebAPIusingASP.NETMVC_5F00_F635/image_5F00_6.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="481" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.CreateJSONandXMLWebAPIusingASP.NETMVC_5F00_F635/image_5F00_thumb_5F00_2.png" width="537" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;You can use the test web project to call these methods and see the result:&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.CreateJSONandXMLWebAPIusingASP.NETMVC_5F00_F635/image_5F00_8.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="472" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.CreateJSONandXMLWebAPIusingASP.NETMVC_5F00_F635/image_5F00_thumb_5F00_3.png" width="531" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&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 - &lt;u&gt;ErrorCode&lt;/u&gt; (0 by default means success), &lt;u&gt;Message&lt;/u&gt; (a string data type) and &lt;u&gt;Data&lt;/u&gt; which is the real object.&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.CreateJSONandXMLWebAPIusingASP.NETMVC_5F00_F635/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="239" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.CreateJSONandXMLWebAPIusingASP.NETMVC_5F00_F635/image_5F00_thumb_5F00_4.png" width="463" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;When you want to return only a result with error message, you can do this:&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.CreateJSONandXMLWebAPIusingASP.NETMVC_5F00_F635/image_5F00_12.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="86" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.CreateJSONandXMLWebAPIusingASP.NETMVC_5F00_F635/image_5F00_thumb_5F00_5.png" width="585" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;This produces a result like this:&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.CreateJSONandXMLWebAPIusingASP.NETMVC_5F00_F635/image_5F00_14.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="97" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.CreateJSONandXMLWebAPIusingASP.NETMVC_5F00_F635/image_5F00_thumb_5F00_6.png" width="445" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&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 failure. It makes our life so easier. &lt;/p&gt; &lt;p&gt;So, far we have only returned objects and lists. Now we need to accept Json and Xml payload, delivered via HTTP POST. Sometimes your client might want to upload a collection of objects in one shot for batch processing. So, they can upload objects using either Json or Xml format. There&amp;#39;s no native support in ASP.NET MVC to automatically parse posted Json or Xml and automatically map to Action parameters. So, I wrote a filter that does it.&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.CreateJSONandXMLWebAPIusingASP.NETMVC_5F00_F635/image_5F00_18.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="491" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.CreateJSONandXMLWebAPIusingASP.NETMVC_5F00_F635/image_5F00_thumb_5F00_8.png" width="578" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;This filter intercepts calls going to Action methods and checks whether client has posted Xml or Json. Based on what has been posted, it uses &lt;u&gt;DataContractJsonSerializer&lt;/u&gt; or simple &lt;u&gt;XmlSerializer&lt;/u&gt; to convert the payload to objects or collections.&lt;/p&gt; &lt;p&gt;You use this attribute on Action methods like this:&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.CreateJSONandXMLWebAPIusingASP.NETMVC_5F00_F635/image_5F00_20.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="98" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.CreateJSONandXMLWebAPIusingASP.NETMVC_5F00_F635/image_5F00_thumb_5F00_9.png" width="385" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;The attribute expects a parameter name where it stores the deserialized object/collection. It also expects a root type that it needs to pass to the deserializer. If you are expecting a single object, specify &lt;u&gt;typeof(SingeObject)&lt;/u&gt;. If you are expecting a list of objects, specify an array of that object like &lt;u&gt;typeof(SingleObject[])&lt;/u&gt;&lt;/p&gt; &lt;p&gt;You can test the project live at this URL:&lt;/p&gt; &lt;p&gt;&lt;a href="http://labs.dropthings.com/MvcWebAPI"&gt;http://labs.dropthings.com/MvcWebAPI&lt;/a&gt;&lt;/p&gt; &lt;p&gt;The code is also available at:&lt;/p&gt; &lt;p&gt;&lt;a href="http://code.msdn.microsoft.com/MvcWebAPI"&gt;http://code.msdn.microsoft.com/MvcWebAPI&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Enjoy!&lt;/p&gt; &lt;p&gt;------------&lt;/p&gt; &lt;p&gt;Here&amp;#39;s an Eid gift for my believer brothers. Check out this amazing site &lt;a href="http://www.quranexplorer.com/"&gt;www.quranexplorer.com/&lt;/a&gt;. You will get online recitation, translation - verse by verse. The recitation of Mishari Rashid is something you have to listen to to believe. Try these two recitations to see what I mean:&lt;/p&gt; &lt;p&gt;&lt;a title="Quran Bookmark  Oct 3  Sura 97 - Verse 1" href="http://www.quranexplorer.com/Quran/?Sura=97&amp;amp;FromVerse=1&amp;amp;ToVerse=5&amp;amp;Reciter=Mishari-Rashid&amp;amp;Translation=Eng-Pickthal-Audio&amp;amp;Zoom=5&amp;amp;TajweedRules=0"&gt;Sura 97 - Verse 1&lt;/a&gt;&lt;br /&gt;&lt;a title="Quran Bookmark  Oct 3  Sura 114 - Verse 1" href="http://www.quranexplorer.com/Quran/?Sura=114&amp;amp;FromVerse=1&amp;amp;ToVerse=6&amp;amp;Reciter=Mishari-Rashid&amp;amp;Translation=Eng-Pickthal-Audio&amp;amp;Zoom=5&amp;amp;TajweedRules=0"&gt;Sura 114 - Verse 1&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Press the &amp;quot;Play&amp;quot; icon at bottom left (hard to find).&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f10%2f03%2fcreate-rest-api-using-asp-net-mvc-that-speaks-both-json-and-plain-xml.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%2f03%2fcreate-rest-api-using-asp-net-mvc-that-speaks-both-json-and-plain-xml.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=1649607" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/ajax/default.aspx">ajax</category><category domain="http://msmvps.com/blogs/omar/archive/tags/MVC/default.aspx">MVC</category></item><item><title>HTTP handler to combine multiple files, cache and deliver compressed output for faster page load</title><link>http://msmvps.com/blogs/omar/archive/2008/08/28/http-handler-to-combine-multiple-files-cache-and-deliver-compressed-output-for-faster-page-load.aspx</link><pubDate>Thu, 28 Aug 2008 18:43:45 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1646119</guid><dc:creator>omar</dc:creator><slash:comments>26</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1646119</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/08/28/http-handler-to-combine-multiple-files-cache-and-deliver-compressed-output-for-faster-page-load.aspx#comments</comments><description>&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;/p&gt; &lt;p&gt;Here&amp;#39;s a graph that shows how each request latency adds up and introduces significant delay in page loading:&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.AmultipurposeHTTPhandlertocombinemultipl_5F00_C9CA/image_5F00_16.png"&gt;&lt;img height="253" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.AmultipurposeHTTPhandlertocombinemultipl_5F00_C9CA/image_5F00_thumb_5F00_7.png" width="385" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;You can reduce the wait time by using a CDN. Read &lt;a href="http://msmvps.com/blogs/omar/archive/2007/10/01/make-your-website-faster-using-content-delivery-network.aspx"&gt;my previous blog post&lt;/a&gt; about using CDN. However, a better solution is to deliver multiple files over one request using an &lt;u&gt;HttpHandler&lt;/u&gt; 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 &lt;u&gt;HttpHandler&lt;/u&gt;. 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;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.AmultipurposeHTTPhandlertocombinemultipl_5F00_C9CA/image_5F00_18.png"&gt;&lt;img height="157" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.AmultipurposeHTTPhandlertocombinemultipl_5F00_C9CA/image_5F00_thumb_5F00_8.png" width="326" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Here you can see how much improvement you get if you can combine multiple javascripts and css into one.&lt;/p&gt; &lt;p&gt;In a typical web page, you will see many javascripts referenced:&lt;/p&gt;&lt;pre&gt;&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;/pre&gt;
&lt;p&gt;Instead of these individual &lt;u&gt;&amp;lt;script&amp;gt;&lt;/u&gt; tags, you can use only one &lt;u&gt;&amp;lt;script&amp;gt;&lt;/u&gt; tag to serve the whole set of scripts using an Http Handler:&lt;/p&gt;&lt;pre&gt;&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;/pre&gt;
&lt;p&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 again on future visits.&lt;/p&gt;
&lt;p&gt;You can find details about the &lt;u&gt;HttpHandler&lt;/u&gt; from this CodeProject article:&lt;/p&gt;
&lt;p&gt;&lt;a title="http://www.codeproject.com/KB/aspnet/HttpCombine.aspx" href="http://www.codeproject.com/KB/aspnet/HttpCombine.aspx"&gt;http://www.codeproject.com/KB/aspnet/HttpCombine.aspx&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can also get the latest code from this code site:&lt;/p&gt;
&lt;p&gt;&lt;a title="http://code.msdn.microsoft.com/HttpCombiner" href="http://code.msdn.microsoft.com/HttpCombiner"&gt;http://code.msdn.microsoft.com/HttpCombiner&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That&amp;#39;s it! Make your website faster to load, get more users and earn more revenue.&lt;/p&gt;&lt;span class="sbmLink"&gt;
&lt;table cellspacing="1" cellpadding="1"&gt;

&lt;tr&gt;
&lt;td class="sbmText"&gt;Share this post : &lt;/td&gt;
&lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to del.icio.us" href="http://del.icio.us/post?url=http://msmvps.com/blogs/omar/archive/2008/08/28/http-handler-to-combine-multiple-files-cache-and-deliver-compressed-output-for-faster-page-load.aspx&amp;amp;;title=HttpCombiner%20-%20combine,%20compress%20and%20cache%20multiple%20CSS,%20Javascript%20or%20URL" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/deliciou4.png" border="0" alt="" /&gt;&lt;/a&gt;
&lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to digg" href="http://digg.com/submit?phase=2&amp;amp;url=http://msmvps.com/blogs/omar/archive/2008/08/28/http-handler-to-combine-multiple-files-cache-and-deliver-compressed-output-for-faster-page-load.aspx&amp;amp;title=HttpCombiner%20-%20combine,%20compress%20and%20cache%20multiple%20CSS,%20Javascript%20or%20URL" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/digg14.png" border="0" alt="" /&gt;&lt;/a&gt;
&lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to dotnetkicks" href="http://www.dotnetkicks.com/kick/?url=http://msmvps.com/blogs/omar/archive/2008/08/28/http-handler-to-combine-multiple-files-cache-and-deliver-compressed-output-for-faster-page-load.aspx&amp;amp;title=HttpCombiner%20-%20combine,%20compress%20and%20cache%20multiple%20CSS,%20Javascript%20or%20URL" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/CropperCapture154.jpg" border="0" alt="" /&gt;&lt;/a&gt;
&lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to furl" href="http://www.furl.net/store?s=f&amp;amp;to=0&amp;amp;u=http://msmvps.com/blogs/omar/archive/2008/08/28/http-handler-to-combine-multiple-files-cache-and-deliver-compressed-output-for-faster-page-load.aspx&amp;amp;ti=HttpCombiner%20-%20combine,%20compress%20and%20cache%20multiple%20CSS,%20Javascript%20or%20URL" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/furl4.png" border="0" alt="" /&gt;&lt;/a&gt;
&lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to live" href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://msmvps.com/blogs/omar/archive/2008/08/28/http-handler-to-combine-multiple-files-cache-and-deliver-compressed-output-for-faster-page-load.aspx&amp;amp;title=HttpCombiner%20-%20combine,%20compress%20and%20cache%20multiple%20CSS,%20Javascript%20or%20URL" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/live4.png" border="0" alt="" /&gt;&lt;/a&gt;
&lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to reddit!" href="http://reddit.com/submit?url=http://msmvps.com/blogs/omar/archive/2008/08/28/http-handler-to-combine-multiple-files-cache-and-deliver-compressed-output-for-faster-page-load.aspx&amp;amp;title=HttpCombiner%20-%20combine,%20compress%20and%20cache%20multiple%20CSS,%20Javascript%20or%20URL" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/reddit4.png" border="0" alt="" /&gt;&lt;/a&gt;
&lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to spurl" href="http://www.spurl.net/spurl.php?v=3&amp;amp;url=http://msmvps.com/blogs/omar/archive/2008/08/28/http-handler-to-combine-multiple-files-cache-and-deliver-compressed-output-for-faster-page-load.aspx&amp;amp;title=HttpCombiner%20-%20combine,%20compress%20and%20cache%20multiple%20CSS,%20Javascript%20or%20URL" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/spurl8.png" border="0" alt="" /&gt;&lt;/a&gt;
&lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to technorati!" href="http://technorati.com/faves/?add=http://msmvps.com/blogs/omar/archive/2008/08/28/http-handler-to-combine-multiple-files-cache-and-deliver-compressed-output-for-faster-page-load.aspx&amp;amp;title=HttpCombiner%20-%20combine,%20compress%20and%20cache%20multiple%20CSS,%20Javascript%20or%20URL" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/technora4.png" border="0" alt="" /&gt;&lt;/a&gt;
&lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to yahoo!" href="http://myweb.yahoo.com/myresults/bookmarklet?u=http://msmvps.com/blogs/omar/archive/2008/08/28/http-handler-to-combine-multiple-files-cache-and-deliver-compressed-output-for-faster-page-load.aspx&amp;amp;t=HttpCombiner%20-%20combine,%20compress%20and%20cache%20multiple%20CSS,%20Javascript%20or%20URL" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/yahoo9.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/span&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f08%2f28%2fhttp-handler-to-combine-multiple-files-cache-and-deliver-compressed-output-for-faster-page-load.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%2f08%2f28%2fhttp-handler-to-combine-multiple-files-cache-and-deliver-compressed-output-for-faster-page-load.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=1646119" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx">performance</category><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category></item><item><title>Loading static content in ASP.NET pages from different domain for faster parallel download</title><link>http://msmvps.com/blogs/omar/archive/2008/08/01/loading-static-content-in-asp-net-pages-from-different-domain-for-faster-parallel-download.aspx</link><pubDate>Fri, 01 Aug 2008 18:15:08 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1643008</guid><dc:creator>omar</dc:creator><slash:comments>25</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1643008</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/08/01/loading-static-content-in-asp-net-pages-from-different-domain-for-faster-parallel-download.aspx#comments</comments><description>&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 &lt;a href="http://www.dropthings.com"&gt;www.dropthings.com&lt;/a&gt;. There are three problems in this approach:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;They occupy connections on the same domain &lt;a href="http://www.dropthings.com"&gt;www.dropthings.com&lt;/a&gt; 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.  &lt;li&gt;If you are using ASP.NET Forms Authentication, then you have that gigantic Forms Authentication cookie being sent with every single request on &lt;a href="http://www.dropthings.com"&gt;www.dropthings.com&lt;/a&gt;. 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.  &lt;li&gt;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;/li&gt;&lt;/ul&gt; &lt;p&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;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Storestaticcontentindifferentrootdomain_5F00_AEB5/image_5F00_2.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="248" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Storestaticcontentindifferentrootdomain_5F00_AEB5/image_5F00_thumb.png" width="550" border="0" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;This figure shows only two files are downloaded in parallel. All the hits are going to the same domain e.g. &lt;a href="http://www.dropthings.com"&gt;www.dropthings.com&lt;/a&gt;. 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;/p&gt; &lt;p&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;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Storestaticcontentindifferentrootdomain_5F00_AEB5/image_5F00_8.png"&gt;&lt;img height="246" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Storestaticcontentindifferentrootdomain_5F00_AEB5/image_5F00_thumb_5F00_3.png" width="544" border="0" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&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. &lt;a href="http://www.dropthings.com"&gt;www.dropthings.com&lt;/a&gt;&lt;/p&gt; &lt;p&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;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Storestaticcontentindifferentrootdomain_5F00_AEB5/image_5F00_14.png"&gt;&lt;img height="144" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Storestaticcontentindifferentrootdomain_5F00_AEB5/image_5F00_thumb_5F00_6.png" width="600" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&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;/p&gt; &lt;p&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 cookies are registered only on the www subdomain, browser does not send the cookies to any other subdomain or domain. Thus requests going to other domains are smaller and thus faster.&lt;/p&gt; &lt;p&gt;Would not it be great if you could just plugin something in your ASP.NET project and all the graphics, CSS, javascript URLs automatically get converted to a different domain URL without you having to do anything manually like going through all your ASP.NET pages, webcontrols and manually changing the urls?&lt;/p&gt; &lt;p&gt;Here&amp;#39;s a nice &lt;u&gt;HttpFilter&lt;/u&gt; that will do the exact thing. You just configure in your &lt;u&gt;web.config&lt;/u&gt; what prefix you want to add in front of your javascript, css and images and the filter takes care of changing all the links for you when a page is being rendered.&lt;/p&gt; &lt;p&gt;First you add these keys in your &lt;u&gt;web.config&lt;/u&gt;&amp;#39;s &lt;u&gt;&amp;lt;appSettings&amp;gt;&lt;/u&gt; block that defines the prefix to inject before the relative URL of your static content. You can define three different prefix for images, javascripts and css:&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Storestaticcontentindifferentrootdomain_5F00_AEB5/image_5F00_16.png"&gt;&lt;img height="57" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Storestaticcontentindifferentrootdomain_5F00_AEB5/image_5F00_thumb_5F00_7.png" width="478" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;So, you can download images from one domain, javascripts from another domain and css from another domain in order to increase parallel download. But beware, there&amp;#39;s the overhead of DNS lookup which is significant. Ideally you should have max three unique domains used in your entire page, one for the main domain and two other domain.&lt;/p&gt; &lt;p&gt;Then you register the Filter on &lt;u&gt;Application_BeginRequest&lt;/u&gt; so that it intercepts all aspx pages:&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Storestaticcontentindifferentrootdomain_5F00_AEB5/image_5F00_18.png"&gt;&lt;img height="266" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Storestaticcontentindifferentrootdomain_5F00_AEB5/image_5F00_thumb_5F00_8.png" width="600" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;That&amp;#39;s it! You will see all the &lt;u&gt;&amp;lt;img&amp;gt;&lt;/u&gt; tag&amp;#39;s &lt;u&gt;src&lt;/u&gt; attribute, &lt;u&gt;&amp;lt;script&amp;gt;&lt;/u&gt; tag&amp;#39;s &lt;u&gt;src&lt;/u&gt; attribute, &lt;u&gt;&amp;lt;link&amp;gt;&lt;/u&gt; tag&amp;#39;s &lt;u&gt;href&lt;/u&gt; attribute are automatically prefixed with the prefix defined in &lt;u&gt;web.config&lt;/u&gt;&lt;/p&gt; &lt;p&gt;Here&amp;#39;s how the Filter works. First it intercepts the &lt;u&gt;Write&lt;/u&gt; method and then searches through the buffer if there&amp;#39;s any of the tags. If found, it checks for the &lt;u&gt;src&lt;/u&gt; or &lt;u&gt;href&lt;/u&gt; attribute and then sees if the URL is absolute or relative. If relative, inserts the prefix first and then the relative value follows.&lt;/p&gt; &lt;p&gt;The principle is relatively simple, but the code is far more complex than it sounds. As you work with &lt;u&gt;char[]&lt;/u&gt; in an &lt;u&gt;HttpFilter&lt;/u&gt;, you need to work with &lt;u&gt;char[]&lt;/u&gt; array only, no &lt;u&gt;string&lt;/u&gt;. Moreover, there&amp;#39;s very high performance requirement for such a filter because it processes each and every page&amp;#39;s output. So, the filter will be processing megabytes of data every second on a busy site. Thus it needs to be extremely fast. No string allocation, no string comparison, no &lt;u&gt;Dictionary&lt;/u&gt; or &lt;u&gt;ArrayList&lt;/u&gt;, no &lt;u&gt;StringBuilder&lt;/u&gt; or &lt;u&gt;MemoryStream&lt;/u&gt;. You need to forget all these .NET goodies and go back to good old Computer Science school days and work with arrays, bytes, char and so on.&lt;/p&gt; &lt;p&gt;First, we run through the content array provided and see if there&amp;#39;s any of the intended tag&amp;#39;s start. &lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Storestaticcontentindifferentrootdomain_5F00_AEB5/image_5F00_22.png"&gt;&lt;img height="736" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Storestaticcontentindifferentrootdomain_5F00_AEB5/image_5F00_thumb_5F00_10.png" width="600" border="0" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Idea is to find all the image, script and link tags and see what their src/href value is and inject the prefix if needed. The &lt;u&gt;WritePrefixIf&lt;/u&gt;(...) function does the work of parsing the attribute. Some cool things to notice here is that, there&amp;#39;s absolutely no string comparison here. Everything is done on the &lt;u&gt;char[]&lt;/u&gt; passed to the &lt;u&gt;Write&lt;/u&gt; method. &lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Storestaticcontentindifferentrootdomain_5F00_AEB5/image_5F00_24.png"&gt;&lt;img height="584" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Storestaticcontentindifferentrootdomain_5F00_AEB5/image_5F00_thumb_5F00_11.png" width="600" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;This function checks if &lt;u&gt;src/href&lt;/u&gt; attribute is found and it writes the prefix right after the double quote if the value of the prefix does not start with &lt;u&gt;http://&lt;/u&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;Basically that&amp;#39;s it. The only other interesting thing is the &lt;u&gt;FindAttributeValuePos&lt;/u&gt;. It checks if the specified attribute exists and if it does, finds the position of the value in the content array so that content can be flushed up to the value position.&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Storestaticcontentindifferentrootdomain_5F00_AEB5/image_5F00_26.png"&gt;&lt;img height="382" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Storestaticcontentindifferentrootdomain_5F00_AEB5/image_5F00_thumb_5F00_12.png" width="600" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Two other small functions that are worth mentioning are the compare functions so that you can see, there&amp;#39;s absolutely no string comparison involved in this entire filter:&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Storestaticcontentindifferentrootdomain_5F00_AEB5/image_5F00_28.png"&gt;&lt;img height="351" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Storestaticcontentindifferentrootdomain_5F00_AEB5/image_5F00_thumb_5F00_13.png" width="495" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Now the season finally, the remaining code in Write function that solves several challenges like unfinished tags in a buffer. It&amp;#39;s possible Write method will pass you a buffer where a tag has just started, but did not end. Of you can get part of a tag like &lt;u&gt;&amp;lt;scr&lt;/u&gt; and that&amp;#39;s it. So, these scenario needs to be handled. Idea is to detect such unfinished tags and store them in a temporary buffer. When next &lt;u&gt;Write&lt;/u&gt; call happens, it will combine the buffer and process it.&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Storestaticcontentindifferentrootdomain_5F00_AEB5/image_5F00_30.png"&gt;&lt;img height="645" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Storestaticcontentindifferentrootdomain_5F00_AEB5/image_5F00_thumb_5F00_14.png" width="600" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;That&amp;#39;s it for the filter&amp;#39;s code. &lt;/p&gt; &lt;p&gt;&lt;a title="Download filter Code" href="http://code.msdn.microsoft.com/FastContentLoad"&gt;Download the code from here&lt;/a&gt;. It&amp;#39;s just one class.&lt;/p&gt; &lt;p&gt;You can use this filter in conjunction with the &lt;u&gt;ScriptDeferFilter&lt;/u&gt; that I have showed in &lt;a href="http://www.codeproject.com/kb/aspnet/fastload.aspx"&gt;CodeProject article which defers script loading after body and combines multiple script tags into one&lt;/a&gt; for faster download and better compression and thus significantly faster web page load performance.&lt;/p&gt; &lt;p&gt;In case you are wondering whether this is &lt;strong&gt;production ready&lt;/strong&gt;, visit &lt;a href="http://www.dropthings.com"&gt;www.dropthings.com&lt;/a&gt; and you will see static content downloads from &lt;u&gt;s.dropthings.com&lt;/u&gt; using this Filter.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;span class="sbmLink"&gt; &lt;table cellspacing="1" cellpadding="1"&gt;  &lt;tr&gt; &lt;td class="sbmText"&gt;Share this post : &lt;/td&gt; &lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to del.icio.us" href="http://del.icio.us/post?url=http://msmvps.com/blogs/omar/archive/2008/08/01/loading-static-content-in-asp-net-pages-from-different-domain-for-faster-parallel-download.aspx&amp;amp;;title=Loading%20static%20content%20in%20ASP.NET%20pages%20from%20different%20domain%20for%20faster%20parallel%20download" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/deliciou4.png" border="0" alt="" /&gt;&lt;/a&gt;  &lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to digg" href="http://digg.com/submit?phase=2&amp;amp;url=http://msmvps.com/blogs/omar/archive/2008/08/01/loading-static-content-in-asp-net-pages-from-different-domain-for-faster-parallel-download.aspx&amp;amp;title=Loading%20static%20content%20in%20ASP.NET%20pages%20from%20different%20domain%20for%20faster%20parallel%20download" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/digg14.png" border="0" alt="" /&gt;&lt;/a&gt;  &lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to dotnetkicks" href="http://www.dotnetkicks.com/kick/?url=http://msmvps.com/blogs/omar/archive/2008/08/01/loading-static-content-in-asp-net-pages-from-different-domain-for-faster-parallel-download.aspx&amp;amp;title=Loading%20static%20content%20in%20ASP.NET%20pages%20from%20different%20domain%20for%20faster%20parallel%20download" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/CropperCapture154.jpg" border="0" alt="" /&gt;&lt;/a&gt;  &lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to furl" href="http://www.furl.net/store?s=f&amp;amp;to=0&amp;amp;u=http://msmvps.com/blogs/omar/archive/2008/08/01/loading-static-content-in-asp-net-pages-from-different-domain-for-faster-parallel-download.aspx&amp;amp;ti=Loading%20static%20content%20in%20ASP.NET%20pages%20from%20different%20domain%20for%20faster%20parallel%20download" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/furl4.png" border="0" alt="" /&gt;&lt;/a&gt;  &lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to live" href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://msmvps.com/blogs/omar/archive/2008/08/01/loading-static-content-in-asp-net-pages-from-different-domain-for-faster-parallel-download.aspx&amp;amp;title=Loading%20static%20content%20in%20ASP.NET%20pages%20from%20different%20domain%20for%20faster%20parallel%20download" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/live4.png" border="0" alt="" /&gt;&lt;/a&gt;  &lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to reddit!" href="http://reddit.com/submit?url=http://msmvps.com/blogs/omar/archive/2008/08/01/loading-static-content-in-asp-net-pages-from-different-domain-for-faster-parallel-download.aspx&amp;amp;title=Loading%20static%20content%20in%20ASP.NET%20pages%20from%20different%20domain%20for%20faster%20parallel%20download" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/reddit4.png" border="0" alt="" /&gt;&lt;/a&gt;  &lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to spurl" href="http://www.spurl.net/spurl.php?v=3&amp;amp;url=http://msmvps.com/blogs/omar/archive/2008/08/01/loading-static-content-in-asp-net-pages-from-different-domain-for-faster-parallel-download.aspx&amp;amp;title=Loading%20static%20content%20in%20ASP.NET%20pages%20from%20different%20domain%20for%20faster%20parallel%20download" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/spurl8.png" border="0" alt="" /&gt;&lt;/a&gt;  &lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to technorati!" href="http://technorati.com/faves/?add=http://msmvps.com/blogs/omar/archive/2008/08/01/loading-static-content-in-asp-net-pages-from-different-domain-for-faster-parallel-download.aspx&amp;amp;title=Loading%20static%20content%20in%20ASP.NET%20pages%20from%20different%20domain%20for%20faster%20parallel%20download" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/technora4.png" border="0" alt="" /&gt;&lt;/a&gt;  &lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to yahoo!" href="http://myweb.yahoo.com/myresults/bookmarklet?u=http://msmvps.com/blogs/omar/archive/2008/08/01/loading-static-content-in-asp-net-pages-from-different-domain-for-faster-parallel-download.aspx&amp;amp;t=Loading%20static%20content%20in%20ASP.NET%20pages%20from%20different%20domain%20for%20faster%20parallel%20download" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/yahoo9.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/span&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f08%2f01%2floading-static-content-in-asp-net-pages-from-different-domain-for-faster-parallel-download.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%2f08%2f01%2floading-static-content-in-asp-net-pages-from-different-domain-for-faster-parallel-download.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=1643008" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx">performance</category><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category></item><item><title>Open Source ASP.NET 3.5 AJAX Portal - new and improved</title><link>http://msmvps.com/blogs/omar/archive/2008/07/14/open-source-asp-net-3-5-ajax-portal-new-and-improved.aspx</link><pubDate>Mon, 14 Jul 2008 12:10:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1640766</guid><dc:creator>omar</dc:creator><slash:comments>42</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1640766</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/07/14/open-source-asp-net-3-5-ajax-portal-new-and-improved.aspx#comments</comments><description>&lt;p&gt;Last week I released a new version of &lt;a href="http://dropthings.omaralzabir.com"&gt;Dropthings&lt;/a&gt;, 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 &lt;a href="http://www.amazon.com/dp/0596510500?tag=wwwoazabircom-20&amp;amp;camp=14573&amp;amp;creative=327641&amp;amp;linkCode=as1&amp;amp;creativeASIN=0596510500&amp;amp;adid=1X55CJZEN83ZEQRFPZ7J&amp;amp;"&gt;a book&lt;/a&gt; on these topics as well.&lt;/p&gt;
&lt;p&gt;The new version implements the following performance and scalability improvement techniques:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://msmvps.com/blogs/omar/archive/2008/01/30/10-asp-net-performance-and-scalability-secrets.aspx"&gt;10 ASP.NET Performance and Scalability Secrets&lt;/a&gt;  &lt;/li&gt;
&lt;li&gt;&lt;a href="http://msmvps.com/blogs/omar/archive/2008/04/06/fast-page-loading-by-postponing-asp-net-ajax-scripts-after-content.aspx"&gt;Fast ASP.NET page rendering by deferred script loading&lt;/a&gt;  &lt;/li&gt;
&lt;li&gt;&lt;a href="http://msmvps.com/blogs/omar/archive/2008/05/10/fast-asp-net-web-page-loading-by-downloading-multiple-javascripts-in-batch.aspx"&gt;Load large amount of Javascripts in batch and thus load AJAX sites a lot faster&lt;/a&gt;  &lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.codeproject.com/KB/ajax/ajaxproxy.aspx"&gt;Fast Streaming AJAX proxy that solves double downloading problems and continuously streams content from external domain&lt;/a&gt;  &lt;/li&gt;
&lt;li&gt;&lt;a href="http://msmvps.com/blogs/omar/archive/2007/11/29/making-best-use-of-cache-for-high-performance-website.aspx"&gt;Making best use of cache for high performance website&lt;/a&gt;  &lt;/li&gt;
&lt;li&gt;&lt;a href="http://msmvps.com/controlpanel/blogs/posteditor.aspx/On-demand%20UI%20loading%20on%20AJAX%20websites"&gt;On-demand UI loading on AJAX websites&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;#39;s how the new version looks:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_2.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Dropthings new version" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb.png" border="0" width="600" height="341" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&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;/p&gt;
&lt;p&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;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span class="sbmLink"&gt; 
&lt;table cellpadding="1" cellspacing="1"&gt;

&lt;tr&gt;
&lt;td class="sbmText"&gt;Share this post : &lt;/td&gt;
&lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to del.icio.us" href="http://del.icio.us/post?url=http://msmvps.com/blogs/omar/archive/2008/07/14/open-source-asp-net-3-5-ajax-portal-new-and-improved.aspx&amp;amp;;title=Opren%20Source%20ASP.NET%203.5%20AJAX%20Portal%20-%20new%20and%20improved" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/deliciou4.png" border="0" alt="" /&gt;&lt;/a&gt;  &lt;/td&gt;
&lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to digg" href="http://digg.com/submit?phase=2&amp;amp;url=http://msmvps.com/blogs/omar/archive/2008/07/14/open-source-asp-net-3-5-ajax-portal-new-and-improved.aspx&amp;amp;title=Opren%20Source%20ASP.NET%203.5%20AJAX%20Portal%20-%20new%20and%20improved" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/digg14.png" border="0" alt="" /&gt;&lt;/a&gt;  &lt;/td&gt;
&lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to dotnetkicks" href="http://www.dotnetkicks.com/kick/?url=http://msmvps.com/blogs/omar/archive/2008/07/14/open-source-asp-net-3-5-ajax-portal-new-and-improved.aspx&amp;amp;title=Opren%20Source%20ASP.NET%203.5%20AJAX%20Portal%20-%20new%20and%20improved" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/CropperCapture154.jpg" border="0" alt="" /&gt;&lt;/a&gt;  &lt;/td&gt;
&lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to furl" href="http://www.furl.net/store?s=f&amp;amp;to=0&amp;amp;u=http://msmvps.com/blogs/omar/archive/2008/07/14/open-source-asp-net-3-5-ajax-portal-new-and-improved.aspx&amp;amp;ti=Opren%20Source%20ASP.NET%203.5%20AJAX%20Portal%20-%20new%20and%20improved" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/furl4.png" border="0" alt="" /&gt;&lt;/a&gt;  &lt;/td&gt;
&lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to live" href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://msmvps.com/blogs/omar/archive/2008/07/14/open-source-asp-net-3-5-ajax-portal-new-and-improved.aspx&amp;amp;title=Opren%20Source%20ASP.NET%203.5%20AJAX%20Portal%20-%20new%20and%20improved" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/live4.png" border="0" alt="" /&gt;&lt;/a&gt;  &lt;/td&gt;
&lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to reddit!" href="http://reddit.com/submit?url=http://msmvps.com/blogs/omar/archive/2008/07/14/open-source-asp-net-3-5-ajax-portal-new-and-improved.aspx&amp;amp;title=Opren%20Source%20ASP.NET%203.5%20AJAX%20Portal%20-%20new%20and%20improved" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/reddit4.png" border="0" alt="" /&gt;&lt;/a&gt;  &lt;/td&gt;
&lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to spurl" href="http://www.spurl.net/spurl.php?v=3&amp;amp;url=http://msmvps.com/blogs/omar/archive/2008/07/14/open-source-asp-net-3-5-ajax-portal-new-and-improved.aspx&amp;amp;title=Opren%20Source%20ASP.NET%203.5%20AJAX%20Portal%20-%20new%20and%20improved" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/spurl8.png" border="0" alt="" /&gt;&lt;/a&gt;  &lt;/td&gt;
&lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to technorati!" href="http://technorati.com/faves/?add=http://msmvps.com/blogs/omar/archive/2008/07/14/open-source-asp-net-3-5-ajax-portal-new-and-improved.aspx&amp;amp;title=Opren%20Source%20ASP.NET%203.5%20AJAX%20Portal%20-%20new%20and%20improved" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/technora4.png" border="0" alt="" /&gt;&lt;/a&gt;  &lt;/td&gt;
&lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to yahoo!" href="http://myweb.yahoo.com/myresults/bookmarklet?u=http://msmvps.com/blogs/omar/archive/2008/07/14/open-source-asp-net-3-5-ajax-portal-new-and-improved.aspx&amp;amp;t=Opren%20Source%20ASP.NET%203.5%20AJAX%20Portal%20-%20new%20and%20improved" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/yahoo9.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
&lt;/span&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f07%2f14%2fopen-source-asp-net-3-5-ajax-portal-new-and-improved.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%2f07%2f14%2fopen-source-asp-net-3-5-ajax-portal-new-and-improved.aspx" 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=1640766" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/ajax/default.aspx">ajax</category></item><item><title>Deploy ASP.NET MVC on IIS 6, solve 404, compression and performance problems</title><link>http://msmvps.com/blogs/omar/archive/2008/06/30/deploy-asp-net-mvc-on-iis-6-solve-404-compression-and-performance-problems.aspx</link><pubDate>Mon, 30 Jun 2008 08:12:22 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1638845</guid><dc:creator>omar</dc:creator><slash:comments>21</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1638845</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/06/30/deploy-asp-net-mvc-on-iis-6-solve-404-compression-and-performance-problems.aspx#comments</comments><description>&lt;p&gt;There are several problems with ASP.NET MVC application when deployed on IIS 6.0:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Extensionless URLs give 404 unless some URL Rewrite module is used or wildcard mapping is enabled  &lt;li&gt;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.  &lt;li&gt;Mapping wildcard extension to ASP.NET introduces the following problems:  &lt;ul&gt; &lt;li&gt;Slow performance as all static files get handled by ASP.NET and ASP.NET reads the file from file system on every call  &lt;li&gt;Expires headers doesn&amp;#39;t work for static content as IIS does not serve them anymore. Learn about benefits of expires header from &lt;a title="Making best use of cache" href="http://msmvps.com/blogs/omar/archive/2007/11/29/making-best-use-of-cache-for-high-performance-website.aspx"&gt;here&lt;/a&gt;. ASP.NET serves a fixed expires header that makes content expire in a day.  &lt;li&gt;Cache-Control header does not produce max-age properly and thus caching does not work as expected. Learn about caching best practices from &lt;a title="Making best use of Cache" href="http://msmvps.com/blogs/omar/archive/2007/11/29/making-best-use-of-cache-for-high-performance-website.aspx"&gt;here&lt;/a&gt;. &lt;/li&gt;&lt;/ul&gt; &lt;li&gt;After deploying on a domain as the root site, the homepage produces HTTP 404.&lt;/li&gt;&lt;/ul&gt; &lt;h3&gt;Problem 1: Visiting your website&amp;#39;s homepage gives 404 when hosted on a domain&lt;/h3&gt; &lt;p&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;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_32.png"&gt;&lt;img style="border-right:0px;border-top:0px;border-left:0px;border-bottom:0px;" height="273" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_6.png" width="430" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;You will find people banging their heads on the wall here:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a title="http://forums.asp.net/t/1237051.aspx" href="http://forums.asp.net/t/1237051.aspx"&gt;http://forums.asp.net/t/1237051.aspx&lt;/a&gt;  &lt;li&gt;&lt;a title="http://forums.asp.net/t/1253599.aspx" href="http://forums.asp.net/t/1253599.aspx"&gt;http://forums.asp.net/t/1253599.aspx&lt;/a&gt;  &lt;li&gt;&lt;a title="http://forums.asp.net/p/1239943/2294813.aspx" href="http://forums.asp.net/p/1239943/2294813.aspx"&gt;http://forums.asp.net/p/1239943/2294813.aspx&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Solution is to capture hits going to &amp;quot;/&amp;quot; and then rewrite it to Default.aspx:&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_4.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="61" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_1.png" width="600" border="0" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&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.&lt;/p&gt; &lt;h3&gt;Problem 2: IIS 6 compression is no longer working after wildcard mapping&lt;/h3&gt; &lt;p&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 &lt;a title="IIS 6 Compression - quickest and effective way to do it" href="http://msmvps.com/blogs/omar/archive/2006/08/10/iis-6-compression-quickest-and-effective-way-to-do-it-for-asp-net-compression.aspx"&gt;my earlier post&lt;/a&gt;. &lt;/p&gt; &lt;p&gt;Solution is to use an HttpModule to do the compression for dynamic requests.&lt;/p&gt; &lt;h3&gt;Problem 3: ASP.NET ISAPI does not cache Static Files &lt;/h3&gt; &lt;p&gt;When ASP.NET&amp;#39;s &lt;u&gt;DefaultHttpHandler&lt;/u&gt; 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 &lt;u&gt;DefaultHttpHandler&lt;/u&gt; 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 &lt;u&gt;ETag&lt;/u&gt; for each file based on file&amp;#39;s modified date. For best caching efficiency, we need to get rid of that &lt;u&gt;ETag&lt;/u&gt;, produce an expiry date on far future (like 30 days), and produce &lt;u&gt;Cache-Control&lt;/u&gt; header which offers better control over caching.&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_12.png"&gt;&lt;img height="433" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_5.png" width="600" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&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 files directly from cache instead of hitting the disk. Here are the steps:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Install an &lt;u&gt;HttpModule&lt;/u&gt; that installs a Compression Stream on &lt;u&gt;Response.Filter&lt;/u&gt; so that anything written on Response gets compressed. This serves dynamic requests.  &lt;li&gt;Replace ASP.NET&amp;#39;s &lt;u&gt;DefaultHttpHandler&lt;/u&gt; that listens on *.* for static files.  &lt;li&gt;Write our own Http Handler that will deliver compressed response for static resources like Javascript, CSS, and HTML. &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_6.png"&gt;&lt;img height="59" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_2.png" width="600" border="0" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Here&amp;#39;s the mapping in ASP.NET&amp;#39;s web.config for the &lt;u&gt;DefaultHttpHandler&lt;/u&gt;. You will have to replace this with your own handler in order to serve static files compressed and cached. &lt;/p&gt; &lt;h3&gt;Solution 1: An Http Module to compress dynamic requests&lt;/h3&gt; &lt;p&gt;First, you need to serve compressed responses that are served by the &lt;u&gt;MvcHandler&lt;/u&gt; or ASP.NET&amp;#39;s default Page Handler. The following &lt;u&gt;HttpCompressionModule&lt;/u&gt; hooks on the &lt;u&gt;Response.Filter&lt;/u&gt; and installs a &lt;u&gt;GZipStream&lt;/u&gt; or &lt;u&gt;DeflateStream&lt;/u&gt; on it so that whatever is written on the Response stream, it gets compressed.&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_8.png"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="393" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_3.png" width="596" border="0" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;These are formalities for a regular &lt;u&gt;HttpModule&lt;/u&gt;. The real hook is installed as below:&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/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="436" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_4.png" width="593" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Here you see we ignore requests that are handled by ASP.NET&amp;#39;s &lt;u&gt;DefaultHttpHandler&lt;/u&gt; and our own &lt;u&gt;StaticFileHandler&lt;/u&gt; that you will see in next section. After that, it checks whether the request allows content to be compressed. &lt;u&gt;Accept-Encoding&lt;/u&gt; header contains &amp;quot;gzip&amp;quot; or &amp;quot;deflate&amp;quot; or both when browser supports compressed content. So, when browser supports compressed content, a Response Filter is installed to compress the output.&lt;/p&gt; &lt;h3&gt;Solution 2: An Http Module to compress and cache static file requests&lt;/h3&gt; &lt;p&gt;Here&amp;#39;s how the handler works:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Hooks on *.* so that all unhandled requests get served by the handler  &lt;li&gt;Handles some specific files like js, css, html, graphics files. Anything else, it lets ASP.NET transmit it  &lt;li&gt;The extensions it handles itself, it caches the file content so that subsequent requests are served from cache  &lt;li&gt;It allows compression of some specific extensions like js, css, html. It does not compress graphics files or any other extension.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Let&amp;#39;s start with the handler code:&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_16.png"&gt;&lt;img height="230" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_7.png" width="600" border="0" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Here you will find the extensions the handler handles and the extensions it compresses. You should only put files that are text files in the COMPRESS_FILE_TYPES.&lt;/p&gt; &lt;p&gt;Now start handling each request from &lt;u&gt;BeginProcessRequest&lt;/u&gt;. &lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_18.png"&gt;&lt;img height="432" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_8.png" width="598" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Here you decide the compression mode based on &lt;u&gt;Accept-Encoding&lt;/u&gt; header. If browser does not support compression, do not perform any compression. Then check if the file being requested falls in one of the extensions that we support. If not, let ASP.NET handle it. You will see soon how.&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_20.png"&gt;&lt;img height="537" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_9.png" width="599" border="0" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Calculate the cache key based on the compression mode and the physical path of the file. This ensures that no matter what the URL requested, we have one cache entry for one physical file. Physical file path won&amp;#39;t be different for the same file. Compression mode is used in the cache key because we need to store different copy of the file&amp;#39;s content in ASP.NET cache based on Compression Mode. So, there will be one uncompressed version, a gzip compressed version and a deflate compressed version.&lt;/p&gt; &lt;p&gt;Next check if the file exits. If not, throw HTTP 404. Then create a memory stream that will hold the bytes for the file or the compressed content. Then read the file and write in the memory stream either directly or via a GZip or Deflate stream. Then cache the bytes in the memory stream and deliver to response. You will see the &lt;u&gt;ReadFileData&lt;/u&gt; and &lt;u&gt;CacheAndDeliver&lt;/u&gt; functions soon.&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_22.png"&gt;&lt;img height="385" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_10.png" width="600" border="0" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;This function delivers content directly from ASP.NET cache. The code is simple, read from cache and write to the response.&lt;/p&gt; &lt;p&gt;When the content is not available in cache, read the file bytes and store in a memory stream either as it is or compressed based on what compression mode you decided before:&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_24.png"&gt;&lt;img height="426" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_11.png" width="598" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Here bytes are read in chunk in order to avoid large amount of memory allocation. You could read the whole file in one shot and store in a byte array same as the size of the file length. But I wanted to save memory allocation. Do a performance test to figure out if reading in 8K chunk is not the best approach for you.&lt;/p&gt; &lt;p&gt;Now you have the bytes to write to the response. Next step is to cache it and then deliver it.&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_26.png"&gt;&lt;img height="284" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_12.png" width="600" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Now the two functions that you have seen several times and have been wondering what they do. Here they are:&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_28.png"&gt;&lt;img height="477" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_13.png" width="599" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&lt;u&gt;WriteResponse&lt;/u&gt; has no tricks, but &lt;u&gt;ProduceResponseHeader&lt;/u&gt; has much wisdom in it. First it turns off response buffering so that ASP.NET does not store the written bytes in any internal buffer. This saves some memory allocation. Then it produces proper cache headers to cache the file in browser and proxy for 30 days, ensures proxy revalidate the file after the expiry date and also produces the &lt;u&gt;Last-Modified&lt;/u&gt; date from the file&amp;#39;s last write time in UTC.&lt;/p&gt; &lt;h3&gt;How to use it&lt;/h3&gt; &lt;p&gt;Get the &lt;u&gt;HttpCompressionModule&lt;/u&gt; and &lt;u&gt;StaticFileHandler&lt;/u&gt; from: &lt;/p&gt; &lt;p&gt;&lt;a title="http://code.msdn.microsoft.com/fastmvc" href="http://code.msdn.microsoft.com/fastmvc"&gt;http://code.msdn.microsoft.com/fastmvc&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Then install them in &lt;u&gt;web.config&lt;/u&gt;. First you install the &lt;u&gt;StaticFileHandler&lt;/u&gt; by removing the existing mapping for path=&amp;quot;*&amp;quot; and then you install the &lt;u&gt;HttpCompressionModule&lt;/u&gt;.&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_30.png"&gt;&lt;img height="208" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_14.png" width="602" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;That&amp;#39;s it! Enjoy a faster and more responsive ASP.NET MVC website deployed on IIS 6.0.&lt;/p&gt;&lt;span class="sbmLink"&gt;&lt;span class="sbmLink"&gt; &lt;table cellspacing="1" cellpadding="1"&gt;  &lt;tr&gt; &lt;td class="sbmText"&gt;Share this post : &lt;/td&gt; &lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to del.icio.us" href="http://del.icio.us/post?url=http://msmvps.com/blogs/omar/archive/2008/06/30/deploy-asp-net-mvc-on-iis-6-solve-404-compression-and-performance-problems.aspx&amp;amp;;title=Deploy%20ASP.NET%20MVC%20on%20IIS%206,%20solve%20404,%20compression%20and%20performance%20problems" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/deliciou4.png" border="0" alt="" /&gt;del.icio.us&lt;/a&gt;  &lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to digg" href="http://digg.com/submit?phase=2&amp;amp;url=http://msmvps.com/blogs/omar/archive/2008/06/30/deploy-asp-net-mvc-on-iis-6-solve-404-compression-and-performance-problems.aspx&amp;amp;title=Deploy%20ASP.NET%20MVC%20on%20IIS%206,%20solve%20404,%20compression%20and%20performance%20problems" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/digg14.png" border="0" alt="" /&gt;digg&lt;/a&gt;  &lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to dotnetkicks" href="http://www.dotnetkicks.com/kick/?url=http://msmvps.com/blogs/omar/archive/2008/06/30/deploy-asp-net-mvc-on-iis-6-solve-404-compression-and-performance-problems.aspx&amp;amp;title=Deploy%20ASP.NET%20MVC%20on%20IIS%206,%20solve%20404,%20compression%20and%20performance%20problems" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/CropperCapture154.jpg" border="0" alt="" /&gt;dotnetkicks&lt;/a&gt;  &lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to furl" href="http://www.furl.net/store?s=f&amp;amp;to=0&amp;amp;u=http://msmvps.com/blogs/omar/archive/2008/06/30/deploy-asp-net-mvc-on-iis-6-solve-404-compression-and-performance-problems.aspx&amp;amp;ti=Deploy%20ASP.NET%20MVC%20on%20IIS%206,%20solve%20404,%20compression%20and%20performance%20problems" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/furl4.png" border="0" alt="" /&gt;furl&lt;/a&gt;  &lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to live" href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://msmvps.com/blogs/omar/archive/2008/06/30/deploy-asp-net-mvc-on-iis-6-solve-404-compression-and-performance-problems.aspx&amp;amp;title=Deploy%20ASP.NET%20MVC%20on%20IIS%206,%20solve%20404,%20compression%20and%20performance%20problems" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/live4.png" border="0" alt="" /&gt;live&lt;/a&gt;  &lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to reddit!" href="http://reddit.com/submit?url=http://msmvps.com/blogs/omar/archive/2008/06/30/deploy-asp-net-mvc-on-iis-6-solve-404-compression-and-performance-problems.aspx&amp;amp;title=Deploy%20ASP.NET%20MVC%20on%20IIS%206,%20solve%20404,%20compression%20and%20performance%20problems" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/reddit4.png" border="0" alt="" /&gt;reddit&lt;/a&gt;  &lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to spurl" href="http://www.spurl.net/spurl.php?v=3&amp;amp;url=http://msmvps.com/blogs/omar/archive/2008/06/30/deploy-asp-net-mvc-on-iis-6-solve-404-compression-and-performance-problems.aspx&amp;amp;title=Deploy%20ASP.NET%20MVC%20on%20IIS%206,%20solve%20404,%20compression%20and%20performance%20problems" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/spurl8.png" border="0" alt="" /&gt;spurl&lt;/a&gt;  &lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to technorati!" href="http://technorati.com/faves/?add=http://msmvps.com/blogs/omar/archive/2008/06/30/deploy-asp-net-mvc-on-iis-6-solve-404-compression-and-performance-problems.aspx&amp;amp;title=Deploy%20ASP.NET%20MVC%20on%20IIS%206,%20solve%20404,%20compression%20and%20performance%20problems" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/technora4.png" border="0" alt="" /&gt;technorati&lt;/a&gt;  &lt;td class="sbmDim"&gt;&lt;a class="sbmDim" title="Post it to yahoo!" href="http://myweb.yahoo.com/myresults/bookmarklet?u=http://msmvps.com/blogs/omar/archive/2008/06/30/deploy-asp-net-mvc-on-iis-6-solve-404-compression-and-performance-problems.aspx&amp;amp;t=Deploy%20ASP.NET%20MVC%20on%20IIS%206,%20solve%20404,%20compression%20and%20performance%20problems" target="_blank"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/yahoo9.png" border="0" alt="" /&gt;yahoo&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt; &lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f06%2f30%2fdeploy-asp-net-mvc-on-iis-6-solve-404-compression-and-performance-problems.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%2f06%2f30%2fdeploy-asp-net-mvc-on-iis-6-solve-404-compression-and-performance-problems.aspx" 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=1638845" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx">performance</category><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/production/default.aspx">production</category><category domain="http://msmvps.com/blogs/omar/archive/tags/.net/default.aspx">.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net+MVC/default.aspx">asp.net MVC</category></item><item><title>ensure - Ensure relevant Javascript and HTML are loaded before using them</title><link>http://msmvps.com/blogs/omar/archive/2008/06/09/ensure-ensure-relevant-javascript-and-html-are-loaded-before-using-them.aspx</link><pubDate>Mon, 09 Jun 2008 06:08:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1633238</guid><dc:creator>omar</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1633238</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/06/09/ensure-ensure-relevant-javascript-and-html-are-loaded-before-using-them.aspx#comments</comments><description>&lt;p&gt;&lt;code&gt;ensure&lt;/code&gt; allows you to load Javascript, HTML and CSS on-demand, whenever they are needed. It saves you from writing a gigantic Javascript framework up front so that you can ensure all functions are available whenever they are needed. It also saves you from delivering all possible html on your default page (e.g. default.aspx) hoping that they might some day be needed on some user action. Delivering Javascript, html fragments, CSS during initial loading that is not immediately used on first view makes initial loading slow. Moreover, browser operations get slower as there are lots of stuff on the browser DOM to deal with. So, &lt;code&gt;ensure&lt;/code&gt; saves you from delivering unnecessary javascript, html and CSS up front, instead load them on-demand. Javascripts, html and CSS loaded by &lt;code&gt;ensure&lt;/code&gt; remain in the browser and next time when &lt;code&gt;ensure&lt;/code&gt; is called with the same Javascript, CSS or HTML, it does not reload them and thus saves from repeated downloads.  &lt;/p&gt;
&lt;p&gt;Ensure supports &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt;, &lt;a href="http://www.asp.net/ajax"&gt;Microsoft ASP.NET AJAX&lt;/a&gt; and &lt;a href="http://www.prototypejs.org/"&gt;Prototype &lt;/a&gt;framework. This means you can use it on any html, ASP.NET, PHP, JSP page that uses any of the above framework.  &lt;/p&gt;
&lt;p&gt;For example, you can use &lt;code&gt;ensure&lt;/code&gt; to download Javascript on demand:  &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="jscript"&gt;ensure( { js: &amp;quot;Some.js&amp;quot; }, function()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SomeJS(); // The function SomeJS is available in Some.js only&lt;br /&gt;});&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The above code ensures Some.js is available before executing the code. If the SomeJS.js has already been loaded, it executes the function write away. Otherwise it downloads Some.js, waits until it is properly loaded and only then it executes the function. Thus it saves you from deliverying Some.js upfront when you only need it upon some user action.  &lt;/p&gt;
&lt;p&gt;Similarly you can wait for some HTML fragment to be available, say a popup dialog box. There&amp;#39;s no need for you to deliver HTML for all possible popup boxes that you will ever show to user on your default web page. You can fetch the HTML whenever you need them.  &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="jscript"&gt;ensure( {html: &amp;quot;Popup.html&amp;quot;}, function()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // The element &amp;quot;Popup&amp;quot; is available only in Popup.html&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; document.getElementById(&amp;quot;Popup&amp;quot;).style.display = &amp;quot;&amp;quot;;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;});&lt;/pre&gt;
&lt;p&gt;The above code downloads the html from &amp;quot;Popup.html&amp;quot; and adds it into the body of the document and then fires the function. So, you code can safely use the UI element from that html.  &lt;/p&gt;
&lt;p&gt;You can mix match Javascript, html and CSS altogether in one &lt;code&gt;ensure&lt;/code&gt; call. For example,  &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="jscript"&gt;ensure( { js: &amp;quot;popup.js&amp;quot;, html: &amp;quot;popup.html&amp;quot;, css: &amp;quot;popup.css&amp;quot; }, function()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; PopupManager.show();&lt;br /&gt;});&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;You can also specify multiple Javascripts, html or CSS files to ensure all of them are made available before executing the code:  &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="jscript"&gt;ensure( { js: [&amp;quot;blockUI.js&amp;quot;,&amp;quot;popup.js&amp;quot;], html: [&amp;quot;popup.html&amp;quot;, &amp;quot;blockUI.html&amp;quot;], css: [&amp;quot;blockUI.css&amp;quot;, &amp;quot;popup.css&amp;quot;] }, function()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; BlockUI.show();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; PopupManager.show();&lt;br /&gt;});&lt;/pre&gt;
&lt;p&gt;You might think you are going to end up writing a lot of &lt;code&gt;ensure&lt;/code&gt; code all over your Javascript code and result in a larger Javascript file than before. In order to save you javascript size, you can define shorthands for commonly used files:  &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="jscript"&gt;var JQUERY = { js: &amp;quot;jquery.js&amp;quot; };&lt;br /&gt;var POPUP = { js: [&amp;quot;blockUI.js&amp;quot;,&amp;quot;popup.js&amp;quot;], html: [&amp;quot;popup.html&amp;quot;, &amp;quot;blockUI.html&amp;quot;], css: [&amp;quot;blockUI.css&amp;quot;, &amp;quot;popup.css&amp;quot;] };&lt;br /&gt;...&lt;br /&gt;...&lt;br /&gt;ensure( JQUERY, POPUP, function() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $(&amp;quot;DeleteConfirmPopupDIV&amp;quot;).show();&lt;br /&gt;});&lt;br /&gt;...&lt;br /&gt;...&lt;br /&gt;ensure( POPUP, function()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $(&amp;quot;SaveConfirmationDIV&amp;quot;).show();&lt;br /&gt;);&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;While loading html, you can specify a container element where ensure can inject the loaded HTML. For example, you can say load HtmlSnippet.html and then inject the content inside a DIV named &amp;quot;exampleDiv&amp;quot;  &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="jscript"&gt;ensure( { html: [&amp;quot;popup.html&amp;quot;, &amp;quot;blockUI.html&amp;quot;], parent: &amp;quot;exampleDiv&amp;quot;}, function(){});&lt;/pre&gt;
&lt;p&gt;You can also specify Javascript and CSS that will be loaded along with the html.&amp;nbsp; &lt;/p&gt;
&lt;h3&gt;How ensure works&lt;/h3&gt;
&lt;p&gt;The following CodeProject article explains in detail how ensure it built. Be prepared for a high dose of Javascript techniques:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.codeproject.com/KB/ajax/ensure.aspx"&gt;http://www.codeproject.com/KB/ajax/ensure.aspx&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you find ensure useful, please vote for me. &lt;/p&gt;
&lt;h3&gt;Download Code&lt;/h3&gt;
&lt;p&gt;Download latest source code from CodePlex: &lt;a href="http://www.codeplex.com/ensure"&gt;www.codeplex.com/ensure&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class="sbmLink"&gt; 
&lt;table cellpadding="1" cellspacing="1"&gt;

&lt;tr&gt;
&lt;td class="sbmText"&gt;Share this post : &lt;/td&gt;
&lt;td class="sbmDim"&gt;&lt;a target="_blank" href="http://del.icio.us/post?url=http://www.codeproject.com/KB/ajax/ensure.aspx&amp;amp;;title=Ensure" title="Post it to del.icio.us" class="sbmDim"&gt;&lt;img border="0" src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/deliciou4.png" alt="" /&gt;&lt;/a&gt;  &lt;/td&gt;
&lt;td class="sbmDim"&gt;&lt;a target="_blank" href="http://digg.com/submit?phase=2&amp;amp;url=http://www.codeproject.com/KB/ajax/ensure.aspx&amp;amp;title=Ensure" title="Post it to digg" class="sbmDim"&gt;&lt;img border="0" src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/digg14.png" alt="" /&gt;&lt;/a&gt;  &lt;/td&gt;
&lt;td class="sbmDim"&gt;&lt;a target="_blank" href="http://www.dotnetkicks.com/kick/?url=http://www.codeproject.com/KB/ajax/ensure.aspx&amp;amp;title=Ensure" title="Post it to dotnetkicks" class="sbmDim"&gt;&lt;img border="0" src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/CropperCapture154.jpg" alt="" /&gt;&lt;/a&gt;  &lt;/td&gt;
&lt;td class="sbmDim"&gt;&lt;a target="_blank" href="http://www.furl.net/store?s=f&amp;amp;to=0&amp;amp;u=http://www.codeproject.com/KB/ajax/ensure.aspx&amp;amp;ti=Ensure" title="Post it to furl" class="sbmDim"&gt;&lt;img border="0" src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/furl4.png" alt="" /&gt;&lt;/a&gt;  &lt;/td&gt;
&lt;td class="sbmDim"&gt;&lt;a target="_blank" href="https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://www.codeproject.com/KB/ajax/ensure.aspx&amp;amp;title=Ensure" title="Post it to live" class="sbmDim"&gt;&lt;img border="0" src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/live4.png" alt="" /&gt;&lt;/a&gt;  &lt;/td&gt;
&lt;td class="sbmDim"&gt;&lt;a target="_blank" href="http://reddit.com/submit?url=http://www.codeproject.com/KB/ajax/ensure.aspx&amp;amp;title=Ensure" title="Post it to reddit!" class="sbmDim"&gt;&lt;img border="0" src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/reddit4.png" alt="" /&gt;&lt;/a&gt;  &lt;/td&gt;
&lt;td class="sbmDim"&gt;&lt;a target="_blank" href="http://www.spurl.net/spurl.php?v=3&amp;amp;url=http://www.codeproject.com/KB/ajax/ensure.aspx&amp;amp;title=Ensure" title="Post it to spurl" class="sbmDim"&gt;&lt;img border="0" src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/spurl8.png" alt="" /&gt;&lt;/a&gt;  &lt;/td&gt;
&lt;td class="sbmDim"&gt;&lt;a target="_blank" href="http://technorati.com/faves/?add=http://www.codeproject.com/KB/ajax/ensure.aspx&amp;amp;title=Ensure" title="Post it to technorati!" class="sbmDim"&gt;&lt;img border="0" src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/technora4.png" alt="" /&gt;&lt;/a&gt;  &lt;/td&gt;
&lt;td class="sbmDim"&gt;&lt;a target="_blank" href="http://myweb.yahoo.com/myresults/bookmarklet?u=http://www.codeproject.com/KB/ajax/ensure.aspx&amp;amp;t=Ensure" title="Post it to yahoo!" class="sbmDim"&gt;&lt;img border="0" src="http://blogs.msdn.com/blogfiles/rahulso/WindowsLiveWriter/IconsfordifferentSocialBookmarkingSites_B387/yahoo9.png" alt="" /&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
&lt;/span&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fwww.codeproject.com%2fKB%2fajax%2fensure.aspx"&gt;&lt;img border="0" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.codeproject.com%2fKB%2fajax%2fensure.aspx" 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=1633238" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx">performance</category><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/javascript/default.aspx">javascript</category><category domain="http://msmvps.com/blogs/omar/archive/tags/ajax/default.aspx">ajax</category></item><item><title>UFrame: goodness of UpdatePanel and IFRAME combined</title><link>http://msmvps.com/blogs/omar/archive/2008/05/24/uframe-goodness-of-updatepanel-and-iframe-combined.aspx</link><pubDate>Sat, 24 May 2008 19:31:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1626915</guid><dc:creator>omar</dc:creator><slash:comments>47</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1626915</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/05/24/uframe-goodness-of-updatepanel-and-iframe-combined.aspx#comments</comments><description>&lt;p&gt;&lt;span style="text-decoration:underline;"&gt;UFrame&lt;/span&gt; combines the goodness of &lt;span style="text-decoration:underline;"&gt;UpdatePanel&lt;/span&gt; and &lt;span style="text-decoration:underline;"&gt;IFRAME&lt;/span&gt; in a cross browser and cross platform solution. It allows a &lt;span style="text-decoration:underline;"&gt;DIV&lt;/span&gt; to behave like an &lt;span style="text-decoration:underline;"&gt;IFRAME&lt;/span&gt; loading content from any page either static or dynamic. It can load pages having both inline and external Javascript and CSS, just like an IFRAME. But unlike IFRAME, it loads the content within the main document and you can put any number of &lt;span style="text-decoration:underline;"&gt;UFrame&lt;/span&gt; on your page without slowing down the browser. It supports ASP.NET postback nicely and you can have &lt;span style="text-decoration:underline;"&gt;DataGrid&lt;/span&gt; or any other complex ASP.NET control within a &lt;span style="text-decoration:underline;"&gt;UFrame&lt;/span&gt;. &lt;span style="text-decoration:underline;"&gt;UFrame&lt;/span&gt; works perfectly with &lt;strong&gt;ASP.NET MVC&lt;/strong&gt; making it an replacement for &lt;span style="text-decoration:underline;"&gt;UpdatePanel&lt;/span&gt;. Best of all, &lt;span style="text-decoration:underline;"&gt;UFrame&lt;/span&gt; is implemented 100% in Javascript making it a cross platform solution. As a result, you can use &lt;span style="text-decoration:underline;"&gt;UFrame&lt;/span&gt; on &lt;strong&gt;ASP.NET, PHP, JSP&lt;/strong&gt; or any other platform. &lt;/p&gt;
&lt;div&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;UFrame&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;UFrame1&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;src&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;SomePage.aspx?ID=UFrame1&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;p&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;This should get replaced with content from Somepage.aspx&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;p&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Response from &lt;span style="text-decoration:underline;"&gt;SomePage.aspx&lt;/span&gt; is rendered directly inside the &lt;span style="text-decoration:underline;"&gt;UFrame&lt;/span&gt;. Here you see two &lt;span style="text-decoration:underline;"&gt;UFrame&lt;/span&gt;&amp;#39;s are used to load the same &lt;span style="text-decoration:underline;"&gt;SomePage.aspx&lt;/span&gt; as if they are loaded inside &lt;span style="text-decoration:underline;"&gt;IFRAME. &lt;/span&gt;Another &lt;span style="text-decoration:underline;"&gt;UFrame&lt;/span&gt; is used to load &lt;span style="text-decoration:underline;"&gt;AnotherPage.aspx&lt;/span&gt; that shows photos from Flickr.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/omarzabir/WindowsLiveWriter/UFramegoodnessofUpdatePanelandIFRAMEcomb_C197/image_12.png"&gt;&lt;img border="0" width="550" src="http://weblogs.asp.net/blogs/omarzabir/WindowsLiveWriter/UFramegoodnessofUpdatePanelandIFRAMEcomb_C197/image_thumb_5.png" alt="image" height="387" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;h3&gt;See it in action!&lt;/h3&gt;
&lt;p&gt;You can test &lt;span style="text-decoration:underline;"&gt;UFrame&lt;/span&gt; from:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title="UFrame ASP.NET Version" href="http://labs.omaralzabir.com/UFrame2005"&gt;http://labs.omaralzabir.com/UFrame2005&lt;/a&gt; - Visual Studio 2005 version, .NET 2.0 implementation showing regular ASP.NET 2.0 controls work as usual &lt;/li&gt;
&lt;li&gt;&lt;a title="UFrame ASP.NET MVC Version" href="http://labs.omaralzabir.com/UFrameMvc"&gt;http://labs.omaralzabir.com/UFrameMvc&lt;/a&gt; - Visual Studio 2008 version shows ASP.NET MVC works fine making &lt;span style="text-decoration:underline;"&gt;UFrame&lt;/span&gt; an ultimate replacement for &lt;span style="text-decoration:underline;"&gt;UpdatePanel&lt;/span&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;What is UFrame?&lt;/h3&gt;
&lt;p&gt;&lt;span style="text-decoration:underline;"&gt;UFrame &lt;/span&gt;can load and host a page (ASP.NET, PHP or regular html) inside a DIV. Unlike IFRAME which loads the content inside a browser frame that has no relation with the main document, &lt;span style="text-decoration:underline;"&gt;UFrame&lt;/span&gt; loads the content within the same document. Thus all the Javascripts, CSS on the main document flows through the loaded content. It&amp;#39;s just like &lt;span style="text-decoration:underline;"&gt;UpdatePanel&lt;/span&gt; with IFRAME&amp;#39;s &lt;span style="text-decoration:underline;"&gt;src &lt;/span&gt;attribute.&lt;/p&gt;
&lt;p&gt;The above &lt;span style="text-decoration:underline;"&gt;UFrames&lt;/span&gt; are declared like this:&lt;/p&gt;
&lt;div&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;UFrame1&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;src&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;SomePage.aspx&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;p&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;This should get replaced with content from Somepage.aspx&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;p&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The features of &lt;span style="text-decoration:underline;"&gt;UFrame&lt;/span&gt; are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can build regular ASP.NET/PHP/JSP/HTML page and make them behave as if they are fully AJAX enabled! Simple regular postback will work as if it&amp;#39;s an &lt;span style="text-decoration:underline;"&gt;UpdatePanel&lt;/span&gt;, or simple hyperlinks will behave as if content is being loaded using AJAX. &lt;/li&gt;
&lt;li&gt;Load any URL inside a DIV. It can be a PHP, ASP.NET, JSP or regular HTML page. &lt;/li&gt;
&lt;li&gt;Just like IFRAME, you can set &lt;span style="text-decoration:underline;"&gt;src&lt;/span&gt; property of DIVs and they are converted to &lt;span style="text-decoration:underline;"&gt;UFrame&lt;span style="text-decoration:underline;"&gt;s&lt;/span&gt;&lt;/span&gt; when &lt;span style="text-decoration:underline;"&gt;UFrame&lt;/span&gt; library loads. &lt;/li&gt;
&lt;li&gt;Unlike IFRAME, it loads the content within the main document. So, main document&amp;#39;s CSS and Javascripts are available to the loaded content. &lt;/li&gt;
&lt;li&gt;It allows you to build parts of a page as multiple fully independent pages. &lt;/li&gt;
&lt;li&gt;Each page is built as standalone page. You can build, test and debug each small page independently and put them together on the main page using &lt;span style="text-decoration:underline;"&gt;UFrames&lt;/span&gt;. &lt;/li&gt;
&lt;li&gt;It loads and executes both inline and external scripts from loaded page. You can also render different scripts during &lt;span style="text-decoration:underline;"&gt;UFrame&lt;/span&gt; postback. &lt;/li&gt;
&lt;li&gt;All external scripts are loaded before the body content is set. And all inline scripts are executed when both external scripts and body has been loaded. This way the inline scripts execute when the body content is already available. &lt;/li&gt;
&lt;li&gt;It loads both inline and external CSS. &lt;/li&gt;
&lt;li&gt;It handles duplicates nicely. It does not load the same external Javascript or CSS twice. &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Download the code&lt;/h3&gt;
&lt;p&gt;You can download latest version of &lt;span style="text-decoration:underline;"&gt;UFrame&lt;/span&gt; along with the VS 2005 and VS 2008 (MVC) example projects from CodePlex:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.codeplex.com/uframe"&gt;www.codeplex.com/uframe&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Please go to the &amp;quot;Source Code&amp;quot; tab for the latest version. You are invited to join the project and improve it or fix bugs.&lt;/p&gt;
&lt;h3&gt;Read the article about UFrame&lt;/h3&gt;
&lt;p&gt;I have published an article about UFrame at CodeProject:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.codeproject.com/KB/aspnet/uframe.aspx"&gt;http://www.codeproject.com/KB/aspnet/uframe.aspx&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The article explains in details how the UFrame is built. Be prepared for a big dose of Javascript code. &lt;/p&gt;
&lt;p&gt;If you find UFrame or the article useful, please vote for me at CodeProject.&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fwww.codeproject.com%2fKB%2faspnet%2fuframe.aspx"&gt;&lt;img alt="kick it on DotNetKicks.com" border="0" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.codeproject.com%2fKB%2faspnet%2fuframe.aspx" /&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=1626915" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/javascript/default.aspx">javascript</category><category domain="http://msmvps.com/blogs/omar/archive/tags/ajax/default.aspx">ajax</category></item><item><title>Fast ASP.NET web page loading by downloading multiple javascripts in batch</title><link>http://msmvps.com/blogs/omar/archive/2008/05/10/fast-asp-net-web-page-loading-by-downloading-multiple-javascripts-in-batch.aspx</link><pubDate>Sat, 10 May 2008 00:31:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1618688</guid><dc:creator>omar</dc:creator><slash:comments>23</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1618688</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/05/10/fast-asp-net-web-page-loading-by-downloading-multiple-javascripts-in-batch.aspx#comments</comments><description>&lt;p&gt;A web page can load a lot faster and feel faster if the javascripts on the page can be loaded after the visible content has been loaded and multiple javascripts can be batched into one download. Browsers download one external script at a time and sometimes pause rendering while a script is being downloaded and executed. This makes web pages load and render slow when there are multiple javascripts on the page. For every javascript reference, browser stops downloading and processing of any other content on the page and some browsers (like IE6) pause rendering while it processes the javascript. This gives a slow loading experience and the web page kind of gets &amp;#39;stuck&amp;#39; frequently. As a result, a web page can only load fast when there are small number of external scripts on the page and the scripts are loaded after the visible content of the page has loaded.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example, when you visit http://dropthings.omaralzabir.com, you see a lot of Javascripts downloading. Majority of these are from the ASP.NET AJAX framework and the ASP.NET AJAX Control Toolkit project. &lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/blogs/omar/WindowsLiveWriter/Fas.NETwebpageloadingbydeferringandcombi_11F2/Andysnap_003_4.png"&gt;&lt;img alt="Andysnap_003" src="http://msmvps.com/blogs/omar/WindowsLiveWriter/Fas.NETwebpageloadingbydeferringandcombi_11F2/Andysnap_003_thumb_1.png" border="0" width="619" height="269" /&gt;&lt;/a&gt;&lt;br /&gt;Figure: Many scripts downloaded on a typical ASP.NET AJAX page having ASP.NET AJAX Control Toolkit&lt;/p&gt;
&lt;p&gt;As you see, browser gets stuck for 15 times as it downloads and processes external scripts. This makes page loading &amp;quot;feel&amp;quot; slower. The actual loading time is also pretty bad because these 15 http requests waste 15*100ms = 1500ms on the network latency inside USA. Outside USA, the latency is even higher. Asia gets about 270ms and Australia gets about 380ms latency from any server in USA. So, users outside USA wastes 4 to 6 seconds on network latency where no data is being downloaded. This is an unacceptable performance for any website. &lt;/p&gt;
&lt;p&gt;You pay for such high number of script downloads only because you use two extenders from AJAX Control Toolkit and the &lt;span style="text-decoration:underline;"&gt;UpdatePanel&lt;/span&gt; of ASP.NET AJAX.&lt;/p&gt;
&lt;p&gt;If we can batch the multiple individual script calls into one call like &lt;span style="text-decoration:underline;"&gt;Scripts.ashx&lt;/span&gt; as shown in the picture below and download several scripts together in one shot using an HTTP Handler, it saves us a lot of http connection which could be spent doing other valuable work like downloading CSS for the page to show content properly or downloading images on the page that is visible to user. &lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/blogs/omar/WindowsLiveWriter/Fas.NETwebpageloadingbydeferringandcombi_11F2/Andysnap_002_4.png"&gt;&lt;img alt="Andysnap_002" src="http://msmvps.com/blogs/omar/WindowsLiveWriter/Fas.NETwebpageloadingbydeferringandcombi_11F2/Andysnap_002_thumb_1.png" border="0" width="499" height="69" /&gt;&lt;/a&gt;&lt;br /&gt;Figure: Download several javascripts over one connection and save call and latency &lt;/p&gt;
&lt;p&gt;The &lt;span style="text-decoration:underline;"&gt;Scripts.ashx&lt;/span&gt; handler can not only download multiple scripts in one shot, but also has a very short URL form. For example:&lt;/p&gt;
&lt;p&gt;&lt;span style="text-decoration:underline;"&gt;/scripts.ashx?initial=a,b,c,d,e&amp;amp;/&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Compared to conventional ASP.NET &lt;span style="text-decoration:underline;"&gt;ScriptResource&lt;/span&gt; URLs like:&lt;/p&gt;
&lt;p&gt;&lt;span style="text-decoration:underline;"&gt;/ScriptResource.axd?d=WzuUYZ-Ggi7-B0tkhjPDTmMmgb5FPLmciWEXQLdjNjt&lt;br /&gt;bmek2jgmm3QETspZjKLvHue5em5kVYJGEuf4kofrcKNL9z6AiMhCe3SrJrcBel_c1&lt;br /&gt;&amp;amp;amp;t=633454272919375000&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The benefits of downloading multiple Javascript over one http call are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Saves expensive network roundtrip latency where neither browser nor the origin server is doing anything, not even a single byte is being transmitted during the latency  &lt;/li&gt;
&lt;li&gt;Create less &amp;quot;pause&amp;quot; moments for the browser. So, browser can fluently render the content of the page and thus give user a fast loading feel  &lt;/li&gt;
&lt;li&gt;Give browser move time and free http connections to download visible artifacts of the page and thus give user a &amp;quot;something&amp;#39;s happening&amp;quot; feel  &lt;/li&gt;
&lt;li&gt;When IIS compression is enabled, the total size of individually compressed files is greater than multiple files compressed after they are combined. This is because each compressed byte stream has compression header in order to decompress the content.  &lt;/li&gt;
&lt;li&gt;This reduces the size of the page html as there are only a few handful of script tag. So, you can easily saves hundreds of bytes from the page html. Especially when ASP.NET AJAX produces gigantic &lt;span style="text-decoration:underline;"&gt;WebResource.axd&lt;/span&gt; and &lt;span style="text-decoration:underline;"&gt;ScriptResource.axd&lt;/span&gt; URLs that have very large query parameter&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The solution is to dynamically parse the response of a page before it is sent to the browser and find out what script references are being sent to the browser. I have built an http module which can parse the generated html of a page and find out what are the script blocks being sent. It then parses those script blocks and find the scripts that can be combined. Then it takes out those individual script tags from the response and adds one script tag that generates the combined response of multiple script tags.&lt;/p&gt;
&lt;p&gt;For example, the homepage of &lt;a href="http://www.dropthings.com"&gt;Dropthings.com&lt;/a&gt; produces the following script tags:&lt;/p&gt;
&lt;div&gt;
&lt;pre class="csharpcode"&gt;&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;
...
&lt;span class="rem"&gt;//]]&amp;gt;&lt;/span&gt;
&amp;lt;/script&amp;gt;
&amp;lt;script src=&lt;span class="str"&gt;&amp;quot;/Dropthings/WebResource.axd?d=_w65Lg0FVE-htJvl4_zmXw2&amp;amp;amp;t=633403939286875000&amp;quot;&lt;/span&gt; &lt;br /&gt;type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;
...
&amp;lt;script src=&lt;span class="str"&gt;&amp;quot;Widgets/FastFlickrWidget.js&amp;quot;&lt;/span&gt; type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&lt;span class="str"&gt;&amp;quot;Widgets/FastRssWidget.js&amp;quot;&lt;/span&gt; type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&lt;span class="str"&gt;&amp;quot;/Dropthings/ScriptResource.axd?d=WzuUYZ-Ggi7-B0tkhjPDTmMmgb5FPLmciWEXQLdj&lt;br /&gt;Njtbmek2jgmm3QETspZjKLvHue5em5kVYJGEuf4kofrcKNL9z6AiMhCe3SrJrcBel_c1&lt;br /&gt;&amp;amp;amp;t=633454272919375000&amp;quot;&lt;/span&gt; type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;
&lt;span class="rem"&gt;//&amp;lt;![CDATA[&lt;/span&gt;
...
&amp;lt;/script&amp;gt;
&amp;lt;script src=&lt;span class="str"&gt;&amp;quot;/Dropthings/ScriptResource.axd?d=WzuUYZ-Ggi7-B0tkhjPDTmMmgb5FPLmciWEXQLdjNjtbmek2j&lt;br /&gt;gmm3QETspZjKLvHIbaYWwsewvr_eclXZRGNKzWlaVj44lDEdg9CT2tyH-Yo9jFoQij_XIWxZNETQkZ90&lt;br /&gt;&amp;amp;amp;t=633454272919375000&amp;quot;&lt;/span&gt; type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;
...
&amp;lt;/script&amp;gt;
&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;
...
&amp;lt;/script&amp;gt;
&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt; charset=&lt;span class="str"&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt;&amp;gt;
...
&amp;lt;/script&amp;gt;
&amp;lt;script src=&lt;span class="str"&gt;&amp;quot;Myframework.js&amp;quot;&lt;/span&gt; type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;
...
&amp;lt;/script&amp;gt;
&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class="kwrd"&gt;if&lt;/span&gt;( &lt;span class="kwrd"&gt;typeof&lt;/span&gt; Proxy == &lt;span class="str"&gt;&amp;quot;undefined&amp;quot;&lt;/span&gt; ) Proxy = ProxyAsync;&amp;lt;/script&amp;gt;
&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;
...
&amp;lt;/script&amp;gt;
&amp;lt;script src=&lt;span class="str"&gt;&amp;quot;/Dropthings/ScriptResource.axd?d=WzuUYZ-Ggi7-B0tkhjPDTmMmgb5FPLmciWEXQLdjN&lt;br /&gt;jtbmek2jgmm3QETspZjKLvH-H5JQeA1OWzBaqnbKRQWwc2hxzZ5M8vtSrMhytbB-Oc1&lt;br /&gt;&amp;amp;amp;t=633454272919375000&amp;quot;&lt;/span&gt; type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&lt;span class="str"&gt;&amp;quot;/Dropthings/ScriptResource.axd?d=BXpG1T2rClCdn7QzWc-HrzQ2ECeqBhG6oiVakhRAk&lt;br /&gt;RY6YSaFJsnzqttheoUJJXE4jMUal_1CAxRvbSZ_4_ikAw2&lt;br /&gt;&amp;amp;amp;t=633454540450468750&amp;quot;&lt;/span&gt; type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&lt;span class="str"&gt;&amp;quot;/Dropthings/ScriptResource.axd?d=BXpG1T2rClCdn7QzWc-HrzQ2ECeqBhG6oiVakhRA&lt;br /&gt;kRYRhsy_ZxsfsH4NaPtFtpdDEJ8oZaV5wKE16ikC-hinpw2&lt;br /&gt;&amp;amp;amp;t=633454540450468750&amp;quot;&lt;/span&gt; type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&lt;span class="str"&gt;&amp;quot;/Dropthings/ScriptResource.axd?d=BXpG1T2rClCdn7QzWc-HrzQ2ECeqBhG6oiVakhRAk&lt;br /&gt;RZbimFWogKpiYN4SVreNyf57osSvFc_f24oloxX4RTFfnfj5QsvJGQanl-pbbMbPf01&lt;br /&gt;&amp;amp;amp;t=633454540450468750&amp;quot;&lt;/span&gt; type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;
...
&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;As you see, there are lots of large script tags, in total 15 of them. The solution I will show here will combine the script links and replace with two script links that download 13 of the individual scripts. I have left two scripts out that are related to ASP.NET AJAX Timer extender. &lt;/p&gt;
&lt;div&gt;
&lt;pre class="csharpcode"&gt;&lt;p&gt;&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;
...
&amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt; src=&lt;span class="str"&gt;&amp;quot;Scripts.ashx?initial=a,b,c,d,e,f&amp;amp;/dropthings/&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/b&gt;

&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;
...
&amp;lt;/script&amp;gt;

&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;
...
&amp;lt;/script&amp;gt;
&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;
...
&amp;lt;/script&amp;gt;

&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;
...
&amp;lt;/script&amp;gt;

&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class="kwrd"&gt;if&lt;/span&gt;( &lt;span class="kwrd"&gt;typeof&lt;/span&gt; Proxy == &lt;span class="str"&gt;&amp;quot;undefined&amp;quot;&lt;/span&gt; ) Proxy = ProxyAsync;&amp;lt;/script&amp;gt;
&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;
...
&amp;lt;/script&amp;gt;
&amp;lt;script src=&lt;span class="str"&gt;&amp;quot;/Dropthings/ScriptResource.axd?d=WzuUYZ-...&amp;quot;&lt;/span&gt; type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&lt;span class="str"&gt;&amp;quot;/Dropthings/ScriptResource.axd?d=BXpG1T2...&amp;quot;&lt;/span&gt; type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;b&gt;&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt; src=&lt;span class="str"&gt;&amp;quot;Scripts.ashx?post=C,D,E,F,G,H,I,J&amp;amp;/dropthings/&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/b&gt;

&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;
...
&amp;lt;/script&amp;gt;&lt;/p&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;As you see, 13 of the script links have been combined into two script links. The URL is also smaller than majority of the script references.&lt;/p&gt;
&lt;p&gt;There are two steps involved here:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Find out all the &lt;span style="text-decoration:underline;"&gt;script&lt;/span&gt; tags being emitted inside generated response HTML and collect them in a buffer. Move them after the visible artifacts in the HTML, especially the &lt;span style="text-decoration:underline;"&gt;&amp;lt;form&amp;gt;&lt;/span&gt; tag that contains the generated output of all ASP.NET controls on the page 
&lt;/li&gt;
&lt;li&gt;Parse the buffer and see which script references can be combined into one set. The sets are defined in a configuration file. Replace the individual script references with the combined set reference.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The whole solution is explained in this CodeProject article:&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Fast ASP.NET web page loading by downloading multiple javascripts after visible content and in batch&lt;br /&gt;&lt;/b&gt;&lt;a title="http://www.codeproject.com/KB/aspnet/fastload.aspx" href="http://www.codeproject.com/KB/aspnet/fastload.aspx"&gt;http://www.codeproject.com/KB/aspnet/fastload.aspx&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You should be able to use this approach in any ASP.NET (even better if AJAX) application and give your site a big performance boost. &lt;/p&gt;
&lt;p&gt;If you like the idea, please vote for me.&lt;/p&gt;
&lt;p&gt;

&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fwww.codeproject.com%2fKB%2faspnet%2ffastload.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.codeproject.com%2fKB%2faspnet%2ffastload.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=1618688" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx">performance</category><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/javascript/default.aspx">javascript</category><category domain="http://msmvps.com/blogs/omar/archive/tags/ajax/default.aspx">ajax</category></item><item><title>Fast, Streaming AJAX proxy - continuously download from cross domain</title><link>http://msmvps.com/blogs/omar/archive/2008/04/14/fast-streaming-ajax-proxy-continuously-download-from-cross-domain.aspx</link><pubDate>Mon, 14 Apr 2008 07:29:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1586081</guid><dc:creator>omar</dc:creator><slash:comments>15</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1586081</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/04/14/fast-streaming-ajax-proxy-continuously-download-from-cross-domain.aspx#comments</comments><description>&lt;p&gt;&lt;span id="intelliTXT"&gt;Due to browser&amp;#39;s prohibition on cross domain
XMLHTTP call, all AJAX
websites must have server side proxy to fetch content from external
domain like Flickr or Digg. From client side javascript code, an
XMLHTTP call goes to the server side proxy hosted on the same domain
and then the proxy downloads the content from the external server and
sends back to the browser. In general, all AJAX websites on the
Internet that are showing content from external domains are following
this proxy approach except some rare ones who are using JSONP. Such a
proxy gets a very large number of hits when a lot of component on the
website are downloading content from external domains. So, it becomes a
scalability issue when the proxy starts getting millions of hits.
Moreover, web page&amp;#39;s overall load performance largely depends on the
performance of the proxy as it delivers content to the page. In this
article, we will take a look how we can take a conventional AJAX Proxy
and make it faster, asynchronous, continuously stream content and thus
make it more scalable.&lt;/span&gt; &lt;/p&gt; &lt;p&gt;You can see such a proxy in action when you go to &lt;a href="http://www.pageflakes.com/"&gt;Pageflakes.com&lt;/a&gt;. You will see flakes (widgets) loading many different content like weather feed, flickr photo, youtube videos, RSS from many different external domains. All these are done via a &lt;i&gt;Content Proxy&lt;/i&gt;. Content Proxy served about &lt;b&gt;42.3 million URLs&lt;/b&gt; last month which is quite an engineering challenge for us to make it both fast and scalable. Sometimes Content Proxy serves megabytes of data, which poses even greater engineering challenge. As such proxy gets large number of hits, if we can save on an average 100ms from each call, we can save &lt;b&gt;4.23 million seconds&lt;/b&gt; of download/upload/processing time every month. That&amp;#39;s about 1175 man hours wasted throughout the world by millions of people staring at browser waiting for content to download.&lt;/p&gt; &lt;p&gt;Such a content proxy takes an external server&amp;#39;s URL as a query parameter. It downloads the content from the URL and then writes the content as response back to browser. &lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/blogs/omar/WindowsLiveWriter/FastStreamingAJAXproxy_A628/image1.png"&gt;&lt;img src="http://msmvps.com/blogs/omar/WindowsLiveWriter/FastStreamingAJAXproxy_A628/image1_thumb.png" alt="image" border="0" height="107" width="532" /&gt;&lt;/a&gt;&lt;br /&gt;Figure: Content Proxy working as a middleman between browser and external domain &lt;/p&gt; &lt;p&gt;The above timeline shows how request goes to the server and then server makes a request to external server, downloads the response and then transmits back to the browser. The response arrow from proxy to browser is larger than the response arrow from external server to proxy because generally proxy server&amp;#39;s hosting environment has better download speed than the user&amp;#39;s Internet connectivity.&lt;/p&gt; &lt;p&gt;Such a content proxy is also available in my open source Ajax Web Portal &lt;a href="http://www.dropthings.com/"&gt;Dropthings.com&lt;/a&gt;. You can see from &lt;a href="http://www.codeplex.com/dropthings"&gt;its code&lt;/a&gt; how such a proxy is implemented.&lt;/p&gt; &lt;p&gt;The following is a very simple synchronous, non-streaming, blocking Proxy:&lt;/p&gt; &lt;div class="csharpcode-wrapper" style="width:94.38%;height:192px;"&gt;&lt;pre class="csharpcode" style="width:63.65%;height:176px;"&gt;[WebMethod]&lt;br /&gt;[ScriptMethod(UseHttpGet=&lt;span class="kwrd"&gt;true&lt;/span&gt;)]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; GetString(&lt;span class="kwrd"&gt;string&lt;/span&gt; url)&lt;br /&gt;{&lt;br /&gt;        &lt;span class="kwrd"&gt;using&lt;/span&gt; (WebClient client = &lt;span class="kwrd"&gt;new&lt;/span&gt; WebClient())&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; response = client.DownloadString(url);&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; response;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Although it shows the general principle, but it&amp;#39;s no where close to a real proxy because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It&amp;#39;s a synchronous proxy and thus not scalable. Every call to this web method causes the ASP.NET thread to wait until the call to the external URL completes. 
&lt;/li&gt;&lt;li&gt;It&amp;#39;s &lt;b&gt;non streaming&lt;/b&gt;. It first downloads the entire content on the server, storing it in a string and then uploading that entire content to the browser. If you pass &lt;a href="http://msdn.microsoft.com/rss.xml"&gt;MSDN feed URL&lt;/a&gt;, it will download that gigantic 220 KB RSS XML on the server and store it on a 220 KB long string (actually double the size as .NET strings are all Unicode string) and then write 220 KB to&amp;nbsp; ASP.NET Response buffer, consuming another 220 KB UTF8 byte array in memory. Then that 220 KB will be passed to IIS in chunks so that it can transmit it to the browser. 
&lt;/li&gt;&lt;li&gt;It does not produce proper response header to cache the response on the server. Nor does it deliver important headers like &lt;i&gt;Content-Type&lt;/i&gt; from the source. 
&lt;/li&gt;&lt;li&gt;If external URL is providing gzipped content, it decompresses the content into a string representation and thus wastes server memory. 
&lt;/li&gt;&lt;li&gt;It does not cache the content on the server. So, repeated call to the same external URL within the same second or minute will download content from the external URL and thus waste bandwidth on your server. &lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;So, we need an asynchronous &lt;b&gt;streaming proxy&lt;/b&gt; that transmits the content to the browser while it downloads from the external domain server. So, it will download bytes from external URL in small chunks and immediately transmit that to the browser. As a result, browser will see a continuous transmission of bytes right after calling the web service. There will be no delay while the content is fully downloaded on the server.&lt;/p&gt;
&lt;p&gt;Before I show you the complex streaming proxy code, let&amp;#39;s take an evolutionary approach. Let&amp;#39;s build a better Content Proxy that the one shown above, which is synchronous, non-streaming but does not have the other problems mentioned above. We will build a HTTP Handler named &lt;u&gt;RegularProxy.ashx&lt;/u&gt; which will take &lt;u&gt;url&lt;/u&gt; as a query parameter. It will also take &lt;u&gt;cache&lt;/u&gt; as a query parameter which it will use to produce proper response headers in order to cache the content on the browser. Thus it will save browser from downloading the same content again and again.&lt;/p&gt;
&lt;div&gt;&lt;pre class="csharpcode"&gt;&amp;lt;%@ WebHandler Language=&lt;span class="str"&gt;&amp;quot;C#&amp;quot;&lt;/span&gt; Class=&lt;span class="str"&gt;&amp;quot;RegularProxy&amp;quot;&lt;/span&gt; %&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Web;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Web.Caching;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Net;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; ProxyHelpers;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; RegularProxy : IHttpHandler {&lt;br /&gt;        &lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ProcessRequest (HttpContext context) {&lt;br /&gt;        &lt;span class="kwrd"&gt;string&lt;/span&gt; url = context.Request[&lt;span class="str"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;];&lt;br /&gt;        &lt;span class="kwrd"&gt;int&lt;/span&gt; cacheDuration = Convert.ToInt32(context.Request[&lt;span class="str"&gt;&amp;quot;cache&amp;quot;&lt;/span&gt;]?? &lt;span class="str"&gt;&amp;quot;0&amp;quot;&lt;/span&gt;);&lt;br /&gt;        &lt;span class="kwrd"&gt;string&lt;/span&gt; contentType = context.Request[&lt;span class="str"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;];&lt;br /&gt;&lt;br /&gt;        &lt;span class="rem"&gt;// We don&amp;#39;t want to buffer because we want to save memory&lt;/span&gt;&lt;br /&gt;        context.Response.Buffer = &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;            &lt;br /&gt;        &lt;span class="rem"&gt;// Serve from cache if available&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (context.Cache[url] != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;        {&lt;br /&gt;            context.Response.BinaryWrite(context.Cache[url] &lt;span class="kwrd"&gt;as&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[]);&lt;br /&gt;            context.Response.Flush();&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="kwrd"&gt;using&lt;/span&gt; (WebClient client = &lt;span class="kwrd"&gt;new&lt;/span&gt; WebClient())&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (!&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(contentType))&lt;br /&gt;                client.Headers[&lt;span class="str"&gt;&amp;quot;Content-Type&amp;quot;&lt;/span&gt;] = contentType;&lt;br /&gt;            &lt;br /&gt;            client.Headers[&lt;span class="str"&gt;&amp;quot;Accept-Encoding&amp;quot;&lt;/span&gt;] = &lt;span class="str"&gt;&amp;quot;gzip&amp;quot;&lt;/span&gt;;&lt;br /&gt;            client.Headers[&lt;span class="str"&gt;&amp;quot;Accept&amp;quot;&lt;/span&gt;] = &lt;span class="str"&gt;&amp;quot;*/*&amp;quot;&lt;/span&gt;;&lt;br /&gt;            client.Headers[&lt;span class="str"&gt;&amp;quot;Accept-Language&amp;quot;&lt;/span&gt;] = &lt;span class="str"&gt;&amp;quot;en-US&amp;quot;&lt;/span&gt;;&lt;br /&gt;            client.Headers[&lt;span class="str"&gt;&amp;quot;User-Agent&amp;quot;&lt;/span&gt;] = &lt;br /&gt;&lt;span class="str"&gt;&amp;quot;Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6&amp;quot;&lt;/span&gt;;&lt;br /&gt;            &lt;br /&gt;            &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] data = client.DownloadData(url);&lt;br /&gt;&lt;br /&gt;            context.Cache.Insert(url, data, &lt;span class="kwrd"&gt;null&lt;/span&gt;,&lt;br /&gt;                        Cache.NoAbsoluteExpiration,&lt;br /&gt;                        TimeSpan.FromMinutes(cacheDuration),&lt;br /&gt;                        CacheItemPriority.Normal, &lt;span class="kwrd"&gt;null&lt;/span&gt;); &lt;br /&gt;            &lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (!context.Response.IsClientConnected) &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;            &lt;br /&gt;            &lt;span class="rem"&gt;// Deliver content type, encoding and length as it is received from the external URL&lt;/span&gt;&lt;br /&gt;            context.Response.ContentType = client.ResponseHeaders[&lt;span class="str"&gt;&amp;quot;Content-Type&amp;quot;&lt;/span&gt;];&lt;br /&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; contentEncoding = client.ResponseHeaders[&lt;span class="str"&gt;&amp;quot;Content-Encoding&amp;quot;&lt;/span&gt;];&lt;br /&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; contentLength = client.ResponseHeaders[&lt;span class="str"&gt;&amp;quot;Content-Length&amp;quot;&lt;/span&gt;];&lt;br /&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (!&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(contentEncoding))&lt;br /&gt;                context.Response.AppendHeader(&lt;span class="str"&gt;&amp;quot;Content-Encoding&amp;quot;&lt;/span&gt;, contentEncoding);&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (!&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(contentLength))&lt;br /&gt;                context.Response.AppendHeader(&lt;span class="str"&gt;&amp;quot;Content-Length&amp;quot;&lt;/span&gt;, contentLength);&lt;br /&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (cacheDuration &amp;gt; 0)&lt;br /&gt;                HttpHelper.CacheResponse(context, cacheDuration);&lt;br /&gt;            &lt;br /&gt;            &lt;span class="rem"&gt;// Transmit the exact bytes downloaded&lt;/span&gt;&lt;br /&gt;            context.Response.BinaryWrite(data);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt; &lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsReusable {&lt;br /&gt;        get {&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are two enhancements in this proxy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It allows server side caching of content. Same URL requested by a different browser within a time period will not be downloaded on server again, instead it will be served from cache. 
&lt;/li&gt;&lt;li&gt;It generates proper response cache header so that the content can be cached on browser. 
&lt;/li&gt;&lt;li&gt;It does not decompress the downloaded content in memory. It keeps the original byte stream intact. This saves memory allocation. 
&lt;/li&gt;&lt;li&gt;It transmits the data in non-buffered fashion, which means ASP.NET Response object does not buffer the response and thus saves memory&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;However, this is a blocking proxy. We need to make a streaming asynchronous proxy for better performance. Here&amp;#39;s why:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/blogs/omar/WindowsLiveWriter/FastStreamingAJAXproxy_A628/image_8.png"&gt;&lt;img src="http://msmvps.com/blogs/omar/WindowsLiveWriter/FastStreamingAJAXproxy_A628/image_thumb_3.png" alt="image" border="0" height="128" width="497" /&gt;&lt;/a&gt;&amp;nbsp;&lt;br /&gt;Figure: Continuous streaming proxy&lt;/p&gt;
&lt;p&gt;As you see, when data is transmitted from server to browser while server downloads the content, the delay for server side download is eliminated. So, if server takes 300ms to download something from external source, and then 700ms to send it back to browser, you can save up to 300ms Network Latency between server and browser. The situation gets even better when the external server that serves the content is slow and takes quite some time to deliver the content. The slower external site is, the more saving you get in this continuous streaming approach. This is significantly faster than blocking approach when the external server is in Asia or Australia and your server is in USA. &lt;/p&gt;
&lt;p&gt;The approach for continuous proxy is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read bytes from external server in chunks of 8KB from a separate thread (Reader thread) so that it&amp;#39;s not blocked 
&lt;/li&gt;&lt;li&gt;Store the chunks in an in-memory Queue 
&lt;/li&gt;&lt;li&gt;Write the chunks to ASP.NET Response from that same queue 
&lt;/li&gt;&lt;li&gt;If the queue is finished, wait until more bytes are downloaded by the reader thread&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/blogs/omar/WindowsLiveWriter/FastStreamingAJAXproxy_A628/image15.png"&gt;&lt;img src="http://msmvps.com/blogs/omar/WindowsLiveWriter/FastStreamingAJAXproxy_A628/image15_thumb.png" alt="image" border="0" height="180" width="551" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;The Pipe Stream needs to be thread safe and it needs to support blocking Read. By blocking read it means, if a thread tries to read a chunk from it and the stream is empty, it will suspend that thread until another thread writes something on the stream. Once a write happens, it will resume the reader thread and allow it to read. I have taken the code of &lt;u&gt;PipeStream&lt;/u&gt; from &lt;a href="http://www.codeproject.com/KB/threads/PipeStream.aspx"&gt;CodeProject article by James Kolpack&lt;/a&gt; and extended it to make sure it&amp;#39;s high performance, supports chunks of bytes to be stored instead of single bytes, support timeout on waits and so on. &lt;/p&gt;
&lt;p&gt;A did some comparison between Regular proxy (blocking, synchronous, download all then deliver) and Streaming Proxy (continuous transmission from external server to browser). Both proxy downloads the MSDN feed and delivers it to the browser. The time taken here shows the total duration of browser making the request to the proxy and then getting the entire response.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/blogs/omar/WindowsLiveWriter/FastStreamingAJAXproxy_A628/image_14.png"&gt;&lt;img src="http://msmvps.com/blogs/omar/WindowsLiveWriter/FastStreamingAJAXproxy_A628/image_thumb_4.png" alt="image" border="0" height="230" width="381" /&gt;&lt;/a&gt; &lt;br /&gt;Figure: Time taken by Streaming Proxy vs Regular Proxy while downloading MSDN feed&lt;/p&gt;
&lt;p&gt;Not a very scientific graph and response time varies on the link speed between the browser and the proxy server and then from proxy server to the external server. But it shows that most of the time, Streaming Proxy outperformed Regular proxy.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/blogs/omar/WindowsLiveWriter/FastStreamingAJAXproxy_A628/image_18.png"&gt;&lt;img src="http://msmvps.com/blogs/omar/WindowsLiveWriter/FastStreamingAJAXproxy_A628/image_thumb_7.png" alt="image" border="0" height="373" width="457" /&gt;&lt;/a&gt; &lt;br /&gt;Figure: Test client to compare between Regular Proxy and Streaming Proxy&lt;/p&gt;
&lt;p&gt;You can also test both proxy&amp;#39;s response time by going to &lt;a href="http://labs.dropthings.com/AjaxStreamingProxy"&gt;http://labs.dropthings.com/AjaxStreamingProxy&lt;/a&gt;. Put your URL and hit Regular/Stream button and see the &amp;quot;Statistics&amp;quot; text box for the total duration. You can turn on &amp;quot;Cache response&amp;quot; and hit a URL from one browser. Then go to another browser and hit the URL to see the response coming from server cache directly. Also if you hit the URL again on the same browser, you will see response comes instantly without ever making call to the server. That&amp;#39;s browser cache at work.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Learn more about Http Response caching from my blog post:&lt;br /&gt;&lt;a href="http://feeds.feedburner.com/%7Er/OmarAlZabirBlog/%7E3/267239050/making-best-use-of-cache-for-high-performance-website.aspx"&gt;Making best use of cache for high performance website&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;h3&gt;&lt;/h3&gt;
&lt;p&gt;A Visual Studio Web Test run inside a Load Test shows a better picture:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/blogs/omar/WindowsLiveWriter/FastStreamingAJAXproxy_A628/image_24.png"&gt;&lt;img src="http://msmvps.com/blogs/omar/WindowsLiveWriter/FastStreamingAJAXproxy_A628/image_thumb_10.png" alt="image" border="0" height="200" width="512" /&gt;&lt;/a&gt;&amp;nbsp;&lt;br /&gt;Figure: Regular Proxy load test result shows &lt;b&gt;Average Requests/Sec 0.79&lt;/b&gt; and &lt;b&gt;Avg Response Time 2.5 sec&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/blogs/omar/WindowsLiveWriter/FastStreamingAJAXproxy_A628/image_26.png"&gt;&lt;img src="http://msmvps.com/blogs/omar/WindowsLiveWriter/FastStreamingAJAXproxy_A628/image_thumb_11.png" alt="image" border="0" height="214" width="506" /&gt;&lt;/a&gt;&lt;br /&gt;Figure: Streaming Proxy load test result shows &lt;b&gt;Avg Req/Sec is 1.08&lt;/b&gt; and &lt;b&gt;Avg Response Time 1.8 sec&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;From the above load test results, Streaming Proxy is &lt;b&gt;26% better Request/Sec and Average Response Time is 29% better&lt;/b&gt;. The numbers may sound small, but at Pageflakes, 29% better response time means &lt;b&gt;1.29 million seconds&lt;/b&gt; saved per month for all the users on the website. So, we are effectively saving 353 man hours per month which was wasted staring at browser screen while it downloads content.&lt;/p&gt;
&lt;h3&gt;Building the Streaming Proxy&lt;/h3&gt;&lt;p&gt;The details how the Streaming Proxy is built is quite long and not suitable for a blog post. So, I have written a CodeProject article:&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.codeproject.com/KB/ajax/ajaxproxy.aspx"&gt;Fast, Scalable, Streaming AJAX Proxy - continuously deliver data from cross domain&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Please read the article and please vote for me if your find it useful. &amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1586081" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx">performance</category><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net+ajax/default.aspx">asp.net ajax</category><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/pageflakes/default.aspx">pageflakes</category><category domain="http://msmvps.com/blogs/omar/archive/tags/ajax/default.aspx">ajax</category><category domain="http://msmvps.com/blogs/omar/archive/tags/.net/default.aspx">.net</category></item><item><title>Reduce website download time by heavily compressing PNG and JPEG</title><link>http://msmvps.com/blogs/omar/archive/2008/04/07/reduce-website-download-time-by-heavily-compressing-png-and-jpeg.aspx</link><pubDate>Mon, 07 Apr 2008 13:17:47 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1576733</guid><dc:creator>omar</dc:creator><slash:comments>9</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1576733</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/04/07/reduce-website-download-time-by-heavily-compressing-png-and-jpeg.aspx#comments</comments><description>&lt;p&gt;PNG and JPEG are two most popular formats for web graphics. JPEG is used for photographs, screenshots and backgrounds where PNG is used for all other graphics need including cliparts, buttons, headers, footers, borders and so on. As a result, these two types of graphics file usually take up 80% of the total graphics used in a website. Of course, there&amp;#39;s the GIF, which is very popular. But as it supports only 256 colors, it is losing its popularity day by day. PNG seems to be a all rounder winner for all kinds of graphics need. As all browsers support PNG well enough and PNG supports alpha transparency, it&amp;#39;s surely the best format so far on the web for all purpose graphics need for websites. So, if you can optimize all PNG and JPEG on your website and compress them rigorously, you can easily shed off several seconds of load time from your website without doing any coding. Especially if your website is graphics rich like &lt;a href="http://www.pageflakes.com"&gt;Pageflakes&lt;/a&gt;, 30% reduction in total size of graphics throughout the website is a big performance win.&lt;/p&gt; &lt;h3&gt;&lt;/h3&gt; &lt;h3&gt;Optimize all PNG on your website&lt;/h3&gt; &lt;p&gt;PNG has a lot of scope for optimization. Generally regular graphics tools like Photoshop, Paintshop pro, Paint.NET all generate PNG using a moderate compression. So, PNG can be compressed further by using advanced compression tools. &lt;a href="http://en.wikipedia.org/wiki/OptiPNG"&gt;OptiPNG&lt;/a&gt; is such a tool that can compress PNG and sometimes produce 50% smaller output. At Pageflakes, we have around 380 PNG which when compressed using OptiPNG, gives us 40% reduction in total size. This is a big win for us.&lt;/p&gt; &lt;p&gt;Here&amp;#39;s what wikipedia says about OptiPNG:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;OptiPNG is an open source command line computer program that reduces the size of PNG files. The compression is lossless, meaning that the resulting image will have exactly the same appearance as the source image.  &lt;p&gt;The main purpose of OptiPNG is to reduce the size of the PNG IDAT data stream by trying various filtering and compression methods. It also performs automatic bit depth, color type and color palette reduction where possible, and can correct some data integrity errors in input files.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Here&amp;#39;s a poweshell script that you can run from the root folder of your website. It will scan through all the PNG files in the webtree and run OptiPNG on each file. This takes quite some time if you have hundreds of files. So, you should make it a part of your build script.&lt;/p&gt;&lt;pre class="csharpcode"&gt;gci -include *.png -recurse | &lt;span class="kwrd"&gt;foreach&lt;/span&gt;
 { $fileName = $_.FullName; cmd /c &amp;quot;C:\soft\png\optipng.exe -o7 `&amp;quot;&lt;span class="str"&gt;$fileName`&amp;quot;&amp;quot;&lt;/span&gt; }&lt;/pre&gt;
&lt;p&gt;Here I have stored the optipng.exe on the c:\soft\png folder.&lt;/p&gt;
&lt;p&gt;OptiPNG gives very good compression. But there&amp;#39;s even more scope for compression. &lt;a href="http://en.wikipedia.org/wiki/AdvanceCOMP"&gt;AdvanceCOMP&lt;/a&gt; is the ultimate in compression technology for PNG as it uses the mighty &lt;a href="http://www.7-zip.org/"&gt;7zip&lt;/a&gt; compression algorithm. It can squeeze down PNG even further after being compressed by OptiPNG using its maximum compression mode. PNG files are compressed using DEFLATE algorithm. DEFLATE has 0 to 9 compression level, where 9 is the highest. AdvanceCOMP uses 7zip DEFLATE encoder, that extends the compression factor even more. During 7zip compression, a much more detailed search of compression possibilities is performed, at the expense of significant further processor time spent on searching. Effectively, the 10-point scale used in gzip is extended to include extra settings above 9, the previous maximum search level. There will be no difference in decompression speed, regardless of the level of compressed size achieved or time taken to encode the data.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a poweshell script that you can run from the root folder of your website. It will scan through all the PNG files in the webtree and run AdvanceCOMP on each file. You need to run AdvanceCOMP after running OptiPNG.&lt;/p&gt;&lt;pre class="csharpcode"&gt;gci -include *.png -recurse | &lt;span class="kwrd"&gt;foreach&lt;/span&gt;
 { $fileName = $_.FullName; cmd /c &lt;span class="str"&gt;&amp;quot;C:\soft\png\advpng.exe 
 --shrink-insane -z `&amp;quot;&lt;/span&gt;$fileName`&lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt; }&lt;/pre&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;I have collected &lt;a href="http://omar.mvps.org/tool/png.zip"&gt;both optipng and advpng in this zip&lt;/a&gt; file.&lt;/p&gt;
&lt;h3&gt;Optimize all JPEG on your website&lt;/h3&gt;
&lt;p&gt;Unfortunately, there&amp;#39;s not much powerful tool like OptiPNG for jpeg that you can run on all your jpeg files and compress them rigorously. JPEG file is compressed when it is saved. Generally all graphics applications provide you an option to select what&amp;#39;s the quality ratio of the jpeg being saved. So, you have to consciously make the best compression vs quality choice while saving the jpeg file. However, &lt;a href="http://en.wikipedia.org/wiki/Libjpeg"&gt;libjpeg&lt;/a&gt; project has a jpeg optimizer tool that does some optimization on jpeg files. It has a jpegtran utility which does the optimization according to wikipedia:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;jpegtran - a utility for lossless transcoding between different JPEG formats. The jpegtran command-line program is useful to optimize the compression of a JPEG file, convert between progressive and non-progressive JPEG formats, eliminate non-standard application-specific data inserted by some image programs, or to perform certain transformations on a file — such as grayscaling, or rotating and flipping (within certain limits) — all done &amp;quot;losslessly&amp;quot; (i.e. without decompressing and recompressing the data, and so causing a reduction of image quality due to generation loss).&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;However, when we ran jpegtran on all the jpeg files in Pageflakes, we are able to reduce about 20% total size of all jpeg. So, that was not too bad. &lt;/p&gt;
&lt;p&gt;Here&amp;#39;s how you run jpegtran to get all the jpeg files within your website directory optimized:&lt;/p&gt;&lt;pre class="csharpcode"&gt;gci -include *.jpg -recurse | &lt;span class="kwrd"&gt;foreach&lt;/span&gt;
 { $fileName = $_.FullName; $newFileName = $fileName + &lt;span class="str"&gt;&amp;quot;.tmp&amp;quot;&lt;/span&gt;; 
cmd /c &lt;span class="str"&gt;&amp;quot;C:\soft\jpeg\jpegtran.exe -optimize -outfile `&amp;quot;&lt;/span&gt;$newFileName`&lt;span class="str"&gt;&amp;quot; `&amp;quot;&lt;/span&gt;$fileName`&lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;; 
copy $newFileName $fileName; del $newFileName; }&lt;/pre&gt;
&lt;p&gt;The &lt;a href="http://omar.mvps.org/tool/jpeg.zip"&gt;libjpeg binaries are uploaded here&lt;/a&gt; for your convenience.&lt;/p&gt;
&lt;p&gt;Warning: You have to run all these powershell commands in a single line. I have broken the commands in multiple line for better readability.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s save global bandwidth, go green.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1576733" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx">performance</category><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/production/default.aspx">production</category><category domain="http://msmvps.com/blogs/omar/archive/tags/powershell/default.aspx">powershell</category><category domain="http://msmvps.com/blogs/omar/archive/tags/compress/default.aspx">compress</category><category domain="http://msmvps.com/blogs/omar/archive/tags/optimize/default.aspx">optimize</category><category domain="http://msmvps.com/blogs/omar/archive/tags/jpeg/default.aspx">jpeg</category><category domain="http://msmvps.com/blogs/omar/archive/tags/png/default.aspx">png</category></item><item><title>Fast page loading by moving ASP.NET AJAX scripts after visible content</title><link>http://msmvps.com/blogs/omar/archive/2008/04/06/fast-page-loading-by-postponing-asp-net-ajax-scripts-after-content.aspx</link><pubDate>Sun, 06 Apr 2008 14:49:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1574992</guid><dc:creator>omar</dc:creator><slash:comments>21</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1574992</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/04/06/fast-page-loading-by-postponing-asp-net-ajax-scripts-after-content.aspx#comments</comments><description>&lt;p&gt;ASP.NET &lt;u&gt;ScriptManager&lt;/u&gt; control has a property &lt;u&gt;LoadScriptsBeforeUI&lt;/u&gt;, when set to &lt;b&gt;false&lt;/b&gt;, &lt;i&gt;should&lt;/i&gt; load all AJAX framework scripts after the content of the page. But it &lt;strong&gt;does not&lt;/strong&gt; effectively push down all scripts after the content. Some framework scripts, extender scripts and other scripts registered by Ajax Control Toolkit still load before the page content loads. The following screen taken from &lt;a href="http://www.dropthings.com"&gt;www.dropthings.com&lt;/a&gt; shows several script tags are still added at the beginning of &amp;lt;form&amp;gt; which forces them to download first before the page content is loaded and displayed on the page. Script tags pause rendering on several browsers especially in IE until the scripts download and execute. As a result, it gives user a slow loading impression as user stares at a white screen for some time until the scripts before the content download and execute completely. If browser could render the html before it downloads any script, user would see the page content immediately after visiting the site and not see a white screen. This will give user an impression that the website is blazingly fast (just like Google homepage) because user will ideally see the page content, if it&amp;#39;s not too large, immediately after hitting the URL.&lt;/p&gt; &lt;p&gt;&lt;img height="351" alt="image" src="http://omar.mvps.org/images/Fastpageloadi.NETAJAXscriptsaftercontent_C72F/image.png" width="604" /&gt;&lt;br /&gt;Figure: Script blocks being delivered before the content &lt;/p&gt; &lt;p&gt;From the above screen shot you see there are some scripts from ASP.NET AJAX framework and some scripts from Ajax Control Toolkit that are added before the content of the page. Until these scripts download, browser don&amp;#39;t see anything on the UI and thus you get a pause in rendering giving user a slow load feeling. Each script to external URL adds about 200ms avg network roundtrip delay outside USA while it tries to fetch the script. So, user basically stares at a white screen for at least 1.5 sec no matter how fast internet connection he/she has.&lt;/p&gt; &lt;p&gt;These scripts are rendered at the beginning of &lt;u&gt;form&lt;/u&gt; tag because they are registered using &lt;u&gt;Page.ClientScript.RegisterClientScriptBlock&lt;/u&gt;. Inside &lt;u&gt;Page&lt;/u&gt; class of &lt;u&gt;System.Web&lt;/u&gt;, there&amp;#39;s a method &lt;u&gt;BeginFormRender&lt;/u&gt; which renders the client script blocks immediately after the form tag.&lt;/p&gt; &lt;div&gt; &lt;div class="csharpcode"&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;internal&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; BeginFormRender(HtmlTextWriter writer, &lt;span class="kwrd"&gt;string&lt;/span&gt; formUniqueID)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   3:&lt;/span&gt;     ...&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:&lt;/span&gt;         &lt;span class="kwrd"&gt;this&lt;/span&gt;.ClientScript.RenderHiddenFields(writer);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   5:&lt;/span&gt;         &lt;span class="kwrd"&gt;this&lt;/span&gt;.RenderViewStateFields(writer);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:&lt;/span&gt;         ...&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   7:&lt;/span&gt;         &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;.ClientSupportsJavaScript)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:&lt;/span&gt;         {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   9:&lt;/span&gt;             ...&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:&lt;/span&gt;             &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;._fRequirePostBackScript)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  11:&lt;/span&gt;             {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:&lt;/span&gt;                 &lt;span class="kwrd"&gt;this&lt;/span&gt;.RenderPostBackScript(writer, formUniqueID);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  13:&lt;/span&gt;             }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:&lt;/span&gt;             &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;._fRequireWebFormsScript)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  15:&lt;/span&gt;             {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:&lt;/span&gt;                 &lt;span class="kwrd"&gt;this&lt;/span&gt;.RenderWebFormsScript(writer);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  17:&lt;/span&gt;             }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:&lt;/span&gt;         }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  19:&lt;/span&gt;         &lt;span class="kwrd"&gt;this&lt;/span&gt;.ClientScript.RenderClientScriptBlocks(writer);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Figure: Decompiled code from &lt;u&gt;System.Web.Page&lt;/u&gt; class&lt;/p&gt;
&lt;p&gt;Here you see several script blocks including scripts registered by calling &lt;u&gt;ClientScript.RegisterClientScriptBlock&lt;/u&gt; are rendered right after &lt;u&gt;form&lt;/u&gt; tag starts.&lt;/p&gt;
&lt;p&gt;There&amp;#39;s no easy work around to override the &lt;u&gt;BeginFormRender&lt;/u&gt; method and defer rendering of these scripts. These rendering functions are buried inside &lt;u&gt;System.Web&lt;/u&gt; and none of these are overridable. So, the only solution seems to be using a Response Filter to capture the html being written and suppress rendering the script blocks until it&amp;#39;s the end of the &lt;u&gt;body&lt;/u&gt; tag. When the &lt;u&gt;&amp;lt;/body&amp;gt;&lt;/u&gt; tag is about to be rendered, we can safely assume page content has been successfully delivered and now all suppressed script blocks can be rendered at once.&lt;/p&gt;
&lt;p&gt;In ASP.NET 2.0, you to create Response Filter which is an implementation of a Stream. You can replace default &lt;u&gt;Response.Filter&lt;/u&gt; with your own stream and then ASP.NET will use your filter to write the final rendered HTML. When &lt;u&gt;Response.Write&lt;/u&gt; is called or &lt;u&gt;Page&amp;#39;&lt;/u&gt;s Render method fires, the response is written to the output stream via the filter. So, you can intercept every byte that&amp;#39;s going to be sent to the client (browser) and modify it the way you like. Response Filters can be used in variety ways to optimize Page output like stripping off all white spaces or doing some formatting on the generated content, or manipulating the characters being sent to the browser and so on.&lt;/p&gt;
&lt;p&gt;I have created a Response filter which captures all characters being sent to the browser. It it finds that script blocks are being rendered, instead of rendering it to the &lt;u&gt;Response.OutputStream&lt;/u&gt;, it will extract the script blocks out of the buffer being written and render the rest of the content. It stores all script blocks, both internal and external, in a string buffer. When it detects &lt;u&gt;&amp;lt;/body&amp;gt;&lt;/u&gt; tag is about to be written to the response, it flushes all the captured script blocks from the string buffer.&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ScriptDeferFilter : Stream&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   3:&lt;/span&gt;     Stream responseStream;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:&lt;/span&gt;     &lt;span class="kwrd"&gt;long&lt;/span&gt; position;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:&lt;/span&gt;     &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   7:&lt;/span&gt;     &lt;span class="rem"&gt;/// When this is true, script blocks are suppressed and captured for &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:&lt;/span&gt;     &lt;span class="rem"&gt;/// later rendering&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   9:&lt;/span&gt;     &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:&lt;/span&gt;     &lt;span class="kwrd"&gt;bool&lt;/span&gt; captureScripts;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  11:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:&lt;/span&gt;     &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  13:&lt;/span&gt;     &lt;span class="rem"&gt;/// Holds all script blocks that are injected by the controls&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:&lt;/span&gt;     &lt;span class="rem"&gt;/// The script blocks will be moved after the form tag renders&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  15:&lt;/span&gt;     &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:&lt;/span&gt;     StringBuilder scriptBlocks;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  17:&lt;/span&gt;     &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:&lt;/span&gt;     Encoding encoding;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  19:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:&lt;/span&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; ScriptDeferFilter(Stream inputStream, HttpResponse response)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  21:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:&lt;/span&gt;         &lt;span class="kwrd"&gt;this&lt;/span&gt;.encoding = response.Output.Encoding;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  23:&lt;/span&gt;         &lt;span class="kwrd"&gt;this&lt;/span&gt;.responseStream = response.Filter;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  25:&lt;/span&gt;         &lt;span class="kwrd"&gt;this&lt;/span&gt;.scriptBlocks = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder(5000);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  26:&lt;/span&gt;         &lt;span class="rem"&gt;// When this is on, script blocks are captured and not written to output&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  27:&lt;/span&gt;         &lt;span class="kwrd"&gt;this&lt;/span&gt;.captureScripts = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  28:&lt;/span&gt;     }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here&amp;#39;s the beginning of the Filter class. When it initializes, it takes the original Response Filter. Then it overrides the &lt;u&gt;Write&lt;/u&gt; method of the Stream so that it can capture the buffers being written and do it&amp;#39;s own processing. &lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Write(&lt;span class="kwrd"&gt;byte&lt;/span&gt;[] buffer, &lt;span class="kwrd"&gt;int&lt;/span&gt; offset, &lt;span class="kwrd"&gt;int&lt;/span&gt; count)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   3:&lt;/span&gt;     &lt;span class="rem"&gt;// If we are not capturing script blocks anymore, just redirect to response stream&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:&lt;/span&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt; (!&lt;span class="kwrd"&gt;this&lt;/span&gt;.captureScripts)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   5:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:&lt;/span&gt;         &lt;span class="kwrd"&gt;this&lt;/span&gt;.responseStream.Write(buffer, offset, count);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   7:&lt;/span&gt;         &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   9:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:&lt;/span&gt;     &lt;span class="rem"&gt;/* &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  11:&lt;/span&gt; &lt;span class="rem"&gt;     * Script and HTML can be in one of the following combinations in the specified buffer:          &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:&lt;/span&gt; &lt;span class="rem"&gt;     * .....&amp;lt;script ....&amp;gt;.....&amp;lt;/script&amp;gt;.....&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  13:&lt;/span&gt; &lt;span class="rem"&gt;     * &amp;lt;script ....&amp;gt;.....&amp;lt;/script&amp;gt;.....&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:&lt;/span&gt; &lt;span class="rem"&gt;     * &amp;lt;script ....&amp;gt;.....&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  15:&lt;/span&gt; &lt;span class="rem"&gt;     * &amp;lt;script ....&amp;gt;.....&amp;lt;/script&amp;gt; .....&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:&lt;/span&gt; &lt;span class="rem"&gt;     * ....&amp;lt;script ....&amp;gt;..... &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  17:&lt;/span&gt; &lt;span class="rem"&gt;     * &amp;lt;script ....&amp;gt;..... &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:&lt;/span&gt; &lt;span class="rem"&gt;     * .....&amp;lt;/script&amp;gt;.....&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  19:&lt;/span&gt; &lt;span class="rem"&gt;     * .....&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:&lt;/span&gt; &lt;span class="rem"&gt;     * &amp;lt;script&amp;gt;.....&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  21:&lt;/span&gt; &lt;span class="rem"&gt;     * .... &amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:&lt;/span&gt; &lt;span class="rem"&gt;     * ......&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  23:&lt;/span&gt; &lt;span class="rem"&gt;     * Here, &amp;quot;....&amp;quot; means html content between and outside script tags&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:&lt;/span&gt; &lt;span class="rem"&gt;    */&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  25:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  26:&lt;/span&gt;     &lt;span class="kwrd"&gt;char&lt;/span&gt;[] content = &lt;span class="kwrd"&gt;this&lt;/span&gt;.encoding.GetChars(buffer, offset, count);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  27:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  28:&lt;/span&gt;     &lt;span class="kwrd"&gt;int&lt;/span&gt; scriptTagStart = 0;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  29:&lt;/span&gt;     &lt;span class="kwrd"&gt;int&lt;/span&gt; lastScriptTagEnd = 0;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  30:&lt;/span&gt;     &lt;span class="kwrd"&gt;bool&lt;/span&gt; scriptTagStarted = &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  31:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  32:&lt;/span&gt;     &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; pos = 0; pos &amp;lt; content.Length; pos++)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  33:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  34:&lt;/span&gt;         &lt;span class="rem"&gt;// See if tag start&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  35:&lt;/span&gt;         &lt;span class="kwrd"&gt;char&lt;/span&gt; c = content[pos];&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  36:&lt;/span&gt;         &lt;span class="kwrd"&gt;if&lt;/span&gt; (c == &lt;span class="str"&gt;&amp;#39;&amp;lt;&amp;#39;&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  37:&lt;/span&gt;         {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  38:&lt;/span&gt;             &lt;span class="kwrd"&gt;int&lt;/span&gt; tagStart = pos;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  39:&lt;/span&gt;             &lt;span class="rem"&gt;// Check if it&amp;#39;s a tag ending&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  40:&lt;/span&gt;             &lt;span class="kwrd"&gt;if&lt;/span&gt; (content[pos+1] == &lt;span class="str"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  41:&lt;/span&gt;             {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  42:&lt;/span&gt;                 pos+=2; &lt;span class="rem"&gt;// go past the &amp;lt;/ &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  43:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  44:&lt;/span&gt;                 &lt;span class="rem"&gt;// See if script tag is ending&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  45:&lt;/span&gt;                 &lt;span class="kwrd"&gt;if&lt;/span&gt; (isScriptTag(content, pos))&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  46:&lt;/span&gt;                 {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  47:&lt;/span&gt;                     &lt;span class="rem"&gt;/// Script tag just ended. Get the whole script&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  48:&lt;/span&gt;                     &lt;span class="rem"&gt;/// and store in buffer&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  49:&lt;/span&gt;                     pos = pos + &lt;span class="str"&gt;&amp;quot;script&amp;gt;&amp;quot;&lt;/span&gt;.Length;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  50:&lt;/span&gt;                     scriptBlocks.Append(content, scriptTagStart, pos - scriptTagStart);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  51:&lt;/span&gt;                     scriptBlocks.Append(Environment.NewLine);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  52:&lt;/span&gt;                     lastScriptTagEnd = pos;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  53:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  54:&lt;/span&gt;                     scriptTagStarted = &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  55:&lt;/span&gt;                     &lt;span class="kwrd"&gt;continue&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  56:&lt;/span&gt;                 }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  57:&lt;/span&gt;                 &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (isBodyTag(content, pos))&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  58:&lt;/span&gt;                 {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  59:&lt;/span&gt;                     &lt;span class="rem"&gt;/// body tag has just end. Time for rendering all the script&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  60:&lt;/span&gt;                     &lt;span class="rem"&gt;/// blocks we have suppressed so far and stop capturing script blocks&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  61:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  62:&lt;/span&gt;                     &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;.scriptBlocks.Length &amp;gt; 0)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  63:&lt;/span&gt;                     {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  64:&lt;/span&gt;                         &lt;span class="rem"&gt;// Render all pending html output till now&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  65:&lt;/span&gt;                         &lt;span class="kwrd"&gt;this&lt;/span&gt;.WriteOutput(content, lastScriptTagEnd, tagStart - lastScriptTagEnd);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  66:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  67:&lt;/span&gt;                         &lt;span class="rem"&gt;// Render the script blocks&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  68:&lt;/span&gt;                         &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] scriptBytes = &lt;span class="kwrd"&gt;this&lt;/span&gt;.encoding.GetBytes(&lt;span class="kwrd"&gt;this&lt;/span&gt;.scriptBlocks.ToString());&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  69:&lt;/span&gt;                         &lt;span class="kwrd"&gt;this&lt;/span&gt;.responseStream.Write(scriptBytes, 0, scriptBytes.Length);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  70:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  71:&lt;/span&gt;                         &lt;span class="rem"&gt;// Stop capturing for script blocks&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  72:&lt;/span&gt;                         &lt;span class="kwrd"&gt;this&lt;/span&gt;.captureScripts = &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  73:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  74:&lt;/span&gt;                         &lt;span class="rem"&gt;// Write from the body tag start to the end of the inut buffer and return&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  75:&lt;/span&gt;                         &lt;span class="rem"&gt;// from the function. We are done.&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  76:&lt;/span&gt;                         &lt;span class="kwrd"&gt;this&lt;/span&gt;.WriteOutput(content, tagStart, content.Length - tagStart);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  77:&lt;/span&gt;                         &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  78:&lt;/span&gt;                     }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  79:&lt;/span&gt;                 }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  80:&lt;/span&gt;                 &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  81:&lt;/span&gt;                 {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  82:&lt;/span&gt;                     &lt;span class="rem"&gt;// some other tag&amp;#39;s closing. safely skip one character as smallest&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  83:&lt;/span&gt;                     &lt;span class="rem"&gt;// html tag is one character e.g. &amp;lt;b&amp;gt;. just an optimization to save one loop&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  84:&lt;/span&gt;                     pos++;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  85:&lt;/span&gt;                 }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  86:&lt;/span&gt;             }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  87:&lt;/span&gt;             &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  88:&lt;/span&gt;             {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  89:&lt;/span&gt;                 &lt;span class="kwrd"&gt;if&lt;/span&gt; (isScriptTag(content, pos+1))&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  90:&lt;/span&gt;                 {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  91:&lt;/span&gt;                     &lt;span class="rem"&gt;/// Script tag started. Record the position as we will &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  92:&lt;/span&gt;                     &lt;span class="rem"&gt;/// capture the whole script tag including its content&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  93:&lt;/span&gt;                     &lt;span class="rem"&gt;/// and store in an internal buffer.&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  94:&lt;/span&gt;                     scriptTagStart = pos;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  95:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  96:&lt;/span&gt;                     &lt;span class="rem"&gt;// Write html content since last script tag closing upto this script tag &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  97:&lt;/span&gt;                     &lt;span class="kwrd"&gt;this&lt;/span&gt;.WriteOutput(content, lastScriptTagEnd, scriptTagStart - lastScriptTagEnd);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  98:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  99:&lt;/span&gt;                     &lt;span class="rem"&gt;// Skip the tag start to save some loops&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 100:&lt;/span&gt;                     pos += &lt;span class="str"&gt;&amp;quot;&amp;lt;script&amp;quot;&lt;/span&gt;.Length;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 101:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 102:&lt;/span&gt;                     scriptTagStarted = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 103:&lt;/span&gt;                 }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 104:&lt;/span&gt;                 &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 105:&lt;/span&gt;                 {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 106:&lt;/span&gt;                     &lt;span class="rem"&gt;// some other tag started&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 107:&lt;/span&gt;                     &lt;span class="rem"&gt;// safely skip 2 character because the smallest tag is one character e.g. &amp;lt;b&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 108:&lt;/span&gt;                     &lt;span class="rem"&gt;// just an optimization to eliminate one loop &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 109:&lt;/span&gt;                     pos++;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 110:&lt;/span&gt;                 }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 111:&lt;/span&gt;             }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 112:&lt;/span&gt;         }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 113:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 114:&lt;/span&gt;     &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 115:&lt;/span&gt;     &lt;span class="rem"&gt;// If a script tag is partially sent to buffer, then the remaining content&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 116:&lt;/span&gt;     &lt;span class="rem"&gt;// is part of the last script block&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 117:&lt;/span&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt; (scriptTagStarted)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 118:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 119:&lt;/span&gt;         &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 120:&lt;/span&gt;         &lt;span class="kwrd"&gt;this&lt;/span&gt;.scriptBlocks.Append(content, scriptTagStart, content.Length - scriptTagStart);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 121:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 122:&lt;/span&gt;     &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 123:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 124:&lt;/span&gt;         &lt;span class="rem"&gt;/// Render the characters since the last script tag ending&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 125:&lt;/span&gt;         &lt;span class="kwrd"&gt;this&lt;/span&gt;.WriteOutput(content, lastScriptTagEnd, content.Length - lastScriptTagEnd);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 126:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 127:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;There are several situations to consider here. The &lt;u&gt;Write&lt;/u&gt; method is called several times during the Page render process because the generated HTML can be quite big. So, it will contain partial HTML. So, it&amp;#39;s possible the first Write call contains a start of a script block, but no ending script tag. The following Write call may or may not have the ending script block. So, we need to preserve state to make sure we don&amp;#39;t overlook any script block. Each &lt;u&gt;Write&lt;/u&gt; call can have several script block in the buffer as well. It can also have no script block and only page content.&lt;/p&gt;
&lt;p&gt;The idea here is to go through each character and see if there&amp;#39;s any starting script tag. If there is, remember the start position of the script tag. If script end tag is found within the buffer, then extract out the whole script block from the buffer and render the remaining html. If there&amp;#39;s no ending tag found but a script tag did start within the buffer, then suppress output and capture the remaining content within the script buffer so that next call to &lt;u&gt;Write&lt;/u&gt; method can grab the remaining script and extract it out from the output.&lt;/p&gt;
&lt;p&gt;There are two other private functions that are basically helper functions and does not do anything interesting:&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; WriteOutput(&lt;span class="kwrd"&gt;char&lt;/span&gt;[] content, &lt;span class="kwrd"&gt;int&lt;/span&gt; pos, &lt;span class="kwrd"&gt;int&lt;/span&gt; length)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   3:&lt;/span&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt; (length == 0) &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   5:&lt;/span&gt;     &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] buffer = &lt;span class="kwrd"&gt;this&lt;/span&gt;.encoding.GetBytes(content, pos, length);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:&lt;/span&gt;     &lt;span class="kwrd"&gt;this&lt;/span&gt;.responseStream.Write(buffer, 0, buffer.Length);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   7:&lt;/span&gt; }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   9:&lt;/span&gt; &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; isScriptTag(&lt;span class="kwrd"&gt;char&lt;/span&gt;[] content, &lt;span class="kwrd"&gt;int&lt;/span&gt; pos)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:&lt;/span&gt; {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  11:&lt;/span&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt; (pos + 5 &amp;lt; content.Length)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:&lt;/span&gt;         &lt;span class="kwrd"&gt;return&lt;/span&gt; ((content[pos] == &lt;span class="str"&gt;&amp;#39;s&amp;#39;&lt;/span&gt; || content[pos] == &lt;span class="str"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  13:&lt;/span&gt;             &amp;amp;&amp;amp; (content[pos + 1] == &lt;span class="str"&gt;&amp;#39;c&amp;#39;&lt;/span&gt; || content[pos + 1] == &lt;span class="str"&gt;&amp;#39;C&amp;#39;&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:&lt;/span&gt;             &amp;amp;&amp;amp; (content[pos + 2] == &lt;span class="str"&gt;&amp;#39;r&amp;#39;&lt;/span&gt; || content[pos + 2] == &lt;span class="str"&gt;&amp;#39;R&amp;#39;&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  15:&lt;/span&gt;             &amp;amp;&amp;amp; (content[pos + 3] == &lt;span class="str"&gt;&amp;#39;i&amp;#39;&lt;/span&gt; || content[pos + 3] == &lt;span class="str"&gt;&amp;#39;I&amp;#39;&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:&lt;/span&gt;             &amp;amp;&amp;amp; (content[pos + 4] == &lt;span class="str"&gt;&amp;#39;p&amp;#39;&lt;/span&gt; || content[pos + 4] == &lt;span class="str"&gt;&amp;#39;P&amp;#39;&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  17:&lt;/span&gt;             &amp;amp;&amp;amp; (content[pos + 5] == &lt;span class="str"&gt;&amp;#39;t&amp;#39;&lt;/span&gt; || content[pos + 5] == &lt;span class="str"&gt;&amp;#39;T&amp;#39;&lt;/span&gt;));&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:&lt;/span&gt;     &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  19:&lt;/span&gt;         &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  21:&lt;/span&gt; }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  23:&lt;/span&gt; &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; isBodyTag(&lt;span class="kwrd"&gt;char&lt;/span&gt;[] content, &lt;span class="kwrd"&gt;int&lt;/span&gt; pos)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:&lt;/span&gt; {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  25:&lt;/span&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt; (pos + 3 &amp;lt; content.Length)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  26:&lt;/span&gt;         &lt;span class="kwrd"&gt;return&lt;/span&gt; ((content[pos] == &lt;span class="str"&gt;&amp;#39;b&amp;#39;&lt;/span&gt; || content[pos] == &lt;span class="str"&gt;&amp;#39;B&amp;#39;&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  27:&lt;/span&gt;             &amp;amp;&amp;amp; (content[pos + 1] == &lt;span class="str"&gt;&amp;#39;o&amp;#39;&lt;/span&gt; || content[pos + 1] == &lt;span class="str"&gt;&amp;#39;O&amp;#39;&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  28:&lt;/span&gt;             &amp;amp;&amp;amp; (content[pos + 2] == &lt;span class="str"&gt;&amp;#39;d&amp;#39;&lt;/span&gt; || content[pos + 2] == &lt;span class="str"&gt;&amp;#39;D&amp;#39;&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  29:&lt;/span&gt;             &amp;amp;&amp;amp; (content[pos + 3] == &lt;span class="str"&gt;&amp;#39;y&amp;#39;&lt;/span&gt; || content[pos + 3] == &lt;span class="str"&gt;&amp;#39;Y&amp;#39;&lt;/span&gt;));&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  30:&lt;/span&gt;     &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  31:&lt;/span&gt;         &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  32:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;u&gt;isScriptTag&lt;/u&gt; and &lt;u&gt;isBodyTag&lt;/u&gt; functions may look weird. The reason for such weird code is pure performance. Instead of doing fancy checks like taking a part of the array out and doing string comparison, this is the fastest way of doing the check. Best thing about .NET IL is that it&amp;#39;s optimized, if any of the condition in the &amp;amp;&amp;amp; pairs fail, it won&amp;#39;t even execute the rest. So, this is&amp;nbsp; as best as it can get to check for certain characters.&lt;/p&gt;
&lt;p&gt;There are some corner cases that are not handled here. For example, what if the buffer contains a partial script tag declaration. For example, &lt;u&gt;&amp;quot;....&amp;lt;scr&amp;quot;&lt;/u&gt; and that&amp;#39;s it. The remaining characters did not finish in the buffer instead next buffer is sent with the remaining characters like &lt;u&gt;&amp;quot;ipt src=&amp;quot;...&amp;quot; &amp;gt;.....&amp;lt;/scrip&amp;quot;&lt;/u&gt;. In such case, the script tag won&amp;#39;t be taken out. One way to handle this would be to make sure you always have enough characters left in the buffer to do a complete tag name check. If not found, store the half finished buffer somewhere and on next call to Write, combine it with the new buffer sent and do the processing.&lt;/p&gt;
&lt;p&gt;In order to install the Filter, you need to hook it in in the Global.asax BeginRequest or some other event that&amp;#39;s fired before the Response is generated.&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Application_BeginRequest(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   3:&lt;/span&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt; (Request.HttpMethod == &lt;span class="str"&gt;&amp;quot;GET&amp;quot;&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   5:&lt;/span&gt;         &lt;span class="kwrd"&gt;if&lt;/span&gt; (Request.AppRelativeCurrentExecutionFilePath.EndsWith(&lt;span class="str"&gt;&amp;quot;.aspx&amp;quot;&lt;/span&gt;))&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:&lt;/span&gt;         {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   7:&lt;/span&gt;             Response.Filter = &lt;span class="kwrd"&gt;new&lt;/span&gt; ScriptDeferFilter(Response);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:&lt;/span&gt;         }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   9:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here I am hooking the Filter only for &lt;u&gt;GET&lt;/u&gt; calls to &lt;u&gt;.aspx&lt;/u&gt; pages. You can hook it to POST calls as well. But asynchronous postbacks are regular &lt;u&gt;POST&lt;/u&gt; and I do not want to do any change in the generated JSON or html fragment. Another way is to hook the filter only when &lt;u&gt;ContentType&lt;/u&gt; is &lt;u&gt;text/html&lt;/u&gt;.&lt;/p&gt;
&lt;p&gt;When this filter is installed, &lt;a href="http://www.dropthings.com"&gt;www.dropthings.com&lt;/a&gt; defers all script loading after the &amp;lt;form&amp;gt; tag completes.&lt;/p&gt;
&lt;p&gt;&lt;img height="224" alt="image" src="http://omar.mvps.org/images/Fastpageloadi.NETAJAXscriptsaftercontent_C72F/image_3.png" width="635" /&gt; &lt;br /&gt;Figure: Script tags are moved after the &amp;lt;form&amp;gt; tag when the filter is used&lt;/p&gt;
&lt;p&gt;You can grab the Filter class from the &lt;u&gt;App_Code\ScriptDeferFilter.cs&lt;/u&gt; of the Dropthings project. Go to &lt;a href="http://www.codeplex.com/dropthings"&gt;CodePlex&lt;/a&gt; site and download the latest code for the latest filter.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1574992" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx">performance</category><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/javascript/default.aspx">javascript</category><category domain="http://msmvps.com/blogs/omar/archive/tags/ajax/default.aspx">ajax</category></item><item><title>HTML and IFRAME widget for Dropthings</title><link>http://msmvps.com/blogs/omar/archive/2008/04/05/html-and-iframe-widget-for-dropthings.aspx</link><pubDate>Fri, 04 Apr 2008 23:42:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1572814</guid><dc:creator>omar</dc:creator><slash:comments>15</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1572814</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/04/05/html-and-iframe-widget-for-dropthings.aspx#comments</comments><description>&lt;p&gt;I made two new widgets for &lt;a href="http://www.codeplex.com/Dropthings"&gt;Dropthings&lt;/a&gt; - one is an HTML widget, that allows you to put any HTML content inside a widget and the other one is an IFRAME widget that allows you to host an IFRAME to any URL. You can see example of these widgets from &lt;a href="http://dropthings.omaralzabir.com"&gt;http://dropthings.omaralzabir.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can write any HTML and Script on the HTML Widget and build your own widget at &lt;b&gt;run time&lt;/b&gt;. You can put Video, Audio, Picture or even ActiveX components right on the widget. An example of HTML widget is the NatGeo widget:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/blogs/omar/WindowsLiveWriter/HTMLandIFRAMEwidgetforDropthings_1878/image_6.png"&gt;&lt;img alt="image" src="http://msmvps.com/blogs/omar/WindowsLiveWriter/HTMLandIFRAMEwidgetforDropthings_1878/image_thumb_2.png" border="0" width="335" height="283" /&gt;&lt;/a&gt; &lt;a href="http://msmvps.com/blogs/omar/WindowsLiveWriter/HTMLandIFRAMEwidgetforDropthings_1878/image_4.png"&gt;&lt;img alt="image" src="http://msmvps.com/blogs/omar/WindowsLiveWriter/HTMLandIFRAMEwidgetforDropthings_1878/image_thumb_1.png" border="0" width="218" height="349" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;This is made of HTML Widget where I have just added some widget snippet that I took from ClearSpring.&lt;/p&gt;
&lt;p&gt;The IFRAME widget is also very useful. IFRAME widget hosts an IFRAME pointing to the URL you specify in the settings. Using this widget, you can include any widget from widget providers like Labpixies, ClearSpring, Google Widgets and so on. For instance, I have built three widgets from Labpixies - Stock, Sports and Travelocity widget using the IFRAME widget. The only thing I need to specify in order to bring this widgets is to provide the URL of the widgets that you can find from the widget snippet provided on their website.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/blogs/omar/WindowsLiveWriter/HTMLandIFRAMEwidgetforDropthings_1878/image_8.png"&gt;&lt;img alt="image" src="http://msmvps.com/blogs/omar/WindowsLiveWriter/HTMLandIFRAMEwidgetforDropthings_1878/image_thumb_3.png" border="0" width="233" height="170" /&gt;&lt;/a&gt; &lt;a href="http://msmvps.com/blogs/omar/WindowsLiveWriter/HTMLandIFRAMEwidgetforDropthings_1878/image_10.png"&gt;&lt;img alt="image" src="http://msmvps.com/blogs/omar/WindowsLiveWriter/HTMLandIFRAMEwidgetforDropthings_1878/image_thumb_4.png" border="0" width="162" height="166" /&gt;&lt;/a&gt; &lt;a href="http://msmvps.com/blogs/omar/WindowsLiveWriter/HTMLandIFRAMEwidgetforDropthings_1878/image_12.png"&gt;&lt;img alt="image" src="http://msmvps.com/blogs/omar/WindowsLiveWriter/HTMLandIFRAMEwidgetforDropthings_1878/image_thumb_5.png" border="0" width="168" height="165" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;HTML Widget&lt;/h3&gt;
&lt;p&gt;The HTML widget basically collects HTML snippet in a text box and then renders the HTML output inside a Literal control. The UI consists of only a text box, a button and a literal control.&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="asp"&gt;&amp;lt;%@ Control Language=&amp;quot;C#&amp;quot; AutoEventWireup=&amp;quot;true&amp;quot; CodeFile=&amp;quot;HtmlWidget.ascx.cs&amp;quot; Inherits=&amp;quot;Widgets_HtmlWidget&amp;quot; %&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:Panel&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;SettingsPanel&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Visible&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;HTML: &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;br&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:TextBox&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;HtmltextBox&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;300&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;200&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;MaxLength&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;2000&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;TextMode&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;MultiLine&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:Button&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;SaveSettings&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;OnClick&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;SaveSettings_Clicked&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Text&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Save&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;asp:Panel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:Literal&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Output&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;On the server side, there&amp;#39;s basically the OnPreRender function that does the HTML rendering. Other code snippets are standard formalities for a widget in Dropthings.&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Widgets_HtmlWidget : System.Web.UI.UserControl, IWidget&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; IWidgetHost _Host;&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; XElement _State;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; XElement State&lt;br /&gt;    {&lt;br /&gt;        get&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; state = &lt;span class="kwrd"&gt;this&lt;/span&gt;._Host.GetState();&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(state))&lt;br /&gt;                state = &lt;span class="str"&gt;&amp;quot;&amp;lt;state&amp;gt;&amp;lt;/state&amp;gt;&amp;quot;&lt;/span&gt;;&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_State == &lt;span class="kwrd"&gt;null&lt;/span&gt;) _State = XElement.Parse(state);&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; _State;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Page_Load(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; IWidget.Init(IWidgetHost host)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;._Host = host;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; IWidget.ShowSettings()&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;.HtmltextBox.Text = &lt;span class="kwrd"&gt;this&lt;/span&gt;.State.Value;&lt;br /&gt;        SettingsPanel.Visible = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; IWidget.HideSettings()&lt;br /&gt;    {   &lt;br /&gt;        SettingsPanel.Visible = &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; IWidget.Minimized()&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; IWidget.Maximized()&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; IWidget.Closed()&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SaveState()&lt;br /&gt;    {&lt;br /&gt;        var xml = &lt;span class="kwrd"&gt;this&lt;/span&gt;.State.Xml();&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;._Host.SaveState(xml);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SaveSettings_Clicked(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;.State.RemoveAll();&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;.State.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; XCData(&lt;span class="kwrd"&gt;this&lt;/span&gt;.HtmltextBox.Text));&lt;br /&gt;        &lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;.SaveState();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnPreRender(EventArgs e)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnPreRender(e);&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;.Output.Text = (&lt;span class="kwrd"&gt;this&lt;/span&gt;.State.FirstNode &lt;span class="kwrd"&gt;as&lt;/span&gt; XCData ?? &lt;span class="kwrd"&gt;new&lt;/span&gt; XCData(&lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;)).Value;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;There you have it, an HTML widget that can take any HTML and render it on the UI.&amp;nbsp; &lt;/p&gt;
&lt;h3&gt;IFRAME Widget&lt;/h3&gt;
&lt;p&gt;Just like the HTML widget, IFRAME widget also has a simple URL text box and it renders an &amp;lt;iframe&amp;gt; tag with the url entered in the URL text box.&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="asp"&gt;&amp;lt;%@ Control Language=&amp;quot;C#&amp;quot; AutoEventWireup=&amp;quot;true&amp;quot; CodeFile=&amp;quot;IFrameWidget.ascx.cs&amp;quot; Inherits=&amp;quot;Widgets_IFrameWidget&amp;quot; %&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:Panel&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;SettingsPanel&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Visible&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;URL: &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:TextBox&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;UrlTextBox&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;br&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;Width: &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:TextBox&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;WidthTextBox&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;br&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;Height: &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:TextBox&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;HeightTextBox&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;br&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;Scrollbar: &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:CheckBox&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;ScrollCheckBox&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Checked&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;false&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:Button&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;SaveSettings&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;OnClick&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;SaveSettings_Clicked&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Text&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Save&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;asp:Panel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;iframe&lt;/span&gt; &lt;span class="attr"&gt;src&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;&amp;lt;%= Url %&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;width&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;&amp;lt;%= Width %&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;height&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;&amp;lt;%= Height %&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;frameborder&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;scrolling&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;&amp;lt;%=Scrollbar ? &amp;quot;&lt;/span&gt;&lt;span class="attr"&gt;yes&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class="attr"&gt;no&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;quot;%&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;allowtransparency&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;Sorry your browser does not support IFRAME&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;iframe&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Here the ascx renders an &amp;lt;iframe&amp;gt; tag using the URL, Width, Height values.&lt;/p&gt;
&lt;p&gt;The code for the widget is nothing but standard formalities for widget to store the properties. &lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Widgets_IFrameWidget : System.Web.UI.UserControl, IWidget&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; IWidgetHost _Host;&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; XElement _State;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; XElement State&lt;br /&gt;    {&lt;br /&gt;        get&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; state = &lt;span class="kwrd"&gt;this&lt;/span&gt;._Host.GetState();&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(state))&lt;br /&gt;                state = &lt;span class="str"&gt;&amp;quot;&amp;lt;state&amp;gt;&amp;lt;url&amp;gt;http://www.labpixies.com/campaigns/notes/notes.html&amp;lt;/url&amp;gt;&amp;lt;width&amp;gt;300&amp;lt;/width&amp;gt;&amp;lt;height&amp;gt;200&amp;lt;/height&amp;gt;&amp;lt;scroll&amp;gt;false&amp;lt;/scroll&amp;gt;&amp;lt;/state&amp;gt;&amp;quot;&lt;/span&gt;;&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_State == &lt;span class="kwrd"&gt;null&lt;/span&gt;) _State = XElement.Parse(state);&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; _State;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; Scrollbar&lt;br /&gt;    {&lt;br /&gt;        get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt;.Parse((State.Element(&lt;span class="str"&gt;&amp;quot;scroll&amp;quot;&lt;/span&gt;) ?? &lt;span class="kwrd"&gt;new&lt;/span&gt; XElement(&lt;span class="str"&gt;&amp;quot;scroll&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;false&amp;quot;&lt;/span&gt;)).Value); }&lt;br /&gt;        set&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (State.Element(&lt;span class="str"&gt;&amp;quot;scroll&amp;quot;&lt;/span&gt;) != &lt;span class="kwrd"&gt;null&lt;/span&gt;) State.Element(&lt;span class="str"&gt;&amp;quot;scroll&amp;quot;&lt;/span&gt;).Value = &lt;span class="kwrd"&gt;value&lt;/span&gt;.ToString();&lt;br /&gt;            &lt;span class="kwrd"&gt;else&lt;/span&gt; State.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; XElement(&lt;span class="str"&gt;&amp;quot;scroll&amp;quot;&lt;/span&gt;, &lt;span class="kwrd"&gt;value&lt;/span&gt;.ToString())); &lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Url&lt;br /&gt;    {&lt;br /&gt;        get { &lt;span class="kwrd"&gt;return&lt;/span&gt; (State.Element(&lt;span class="str"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;) ?? &lt;span class="kwrd"&gt;new&lt;/span&gt; XElement(&lt;span class="str"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;)).Value; }&lt;br /&gt;        set { State.Element(&lt;span class="str"&gt;&amp;quot;url&amp;quot;&lt;/span&gt;).Value = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Width&lt;br /&gt;    {&lt;br /&gt;        get { &lt;span class="kwrd"&gt;return&lt;/span&gt; (State.Element(&lt;span class="str"&gt;&amp;quot;width&amp;quot;&lt;/span&gt;) ?? &lt;span class="kwrd"&gt;new&lt;/span&gt; XElement(&lt;span class="str"&gt;&amp;quot;width&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;300&amp;quot;&lt;/span&gt;)).Value; }&lt;br /&gt;        set { State.Element(&lt;span class="str"&gt;&amp;quot;width&amp;quot;&lt;/span&gt;).Value = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Height&lt;br /&gt;    {&lt;br /&gt;        get { &lt;span class="kwrd"&gt;return&lt;/span&gt; (State.Element(&lt;span class="str"&gt;&amp;quot;height&amp;quot;&lt;/span&gt;) ?? &lt;span class="kwrd"&gt;new&lt;/span&gt; XElement(&lt;span class="str"&gt;&amp;quot;height&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;200&amp;quot;&lt;/span&gt;)).Value; }&lt;br /&gt;        set { State.Element(&lt;span class="str"&gt;&amp;quot;height&amp;quot;&lt;/span&gt;).Value = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Page_Load(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; IWidget.Init(IWidgetHost host)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;._Host = host;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; IWidget.ShowSettings()&lt;br /&gt;    {&lt;br /&gt;        UrlTextBox.Text = &lt;span class="kwrd"&gt;this&lt;/span&gt;.Url;&lt;br /&gt;        WidthTextBox.Text = &lt;span class="kwrd"&gt;this&lt;/span&gt;.Width;&lt;br /&gt;        HeightTextBox.Text = &lt;span class="kwrd"&gt;this&lt;/span&gt;.Height;&lt;br /&gt;        ScrollCheckBox.Checked = &lt;span class="kwrd"&gt;this&lt;/span&gt;.Scrollbar;&lt;br /&gt;&lt;br /&gt;        SettingsPanel.Visible = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; IWidget.HideSettings()&lt;br /&gt;    {&lt;br /&gt;        SettingsPanel.Visible = &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; IWidget.Minimized()&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; IWidget.Maximized()&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;void&lt;/span&gt; IWidget.Closed()&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SaveState()&lt;br /&gt;    {&lt;br /&gt;        var xml = &lt;span class="kwrd"&gt;this&lt;/span&gt;.State.Xml();&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;._Host.SaveState(xml);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SaveSettings_Clicked(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;.Url = UrlTextBox.Text;&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;.Width = WidthTextBox.Text;&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;.Height = HeightTextBox.Text;&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;.Scrollbar = ScrollCheckBox.Checked;&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;.SaveState();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;
&lt;h3&gt;
Hosting &lt;span style="text-decoration:underline;"&gt;dropthings &lt;/span&gt;in a Virtual Private Server (VPS)&lt;/h3&gt;
&lt;p&gt;I recently moved &lt;a href="http://www.dropthings.com"&gt;www.dropthings.com&lt;/a&gt; from a shared hosting to a VPS. The main reason is the ability to configure IIS the way I want. On a shared hosting, you cannot tweak IIS settings, nor can you turn on IIS gzip compression. Without these tweaking, it&amp;#39;s not possible to make a high performance website. So, I bought a VPS from vpsland.com and hosted the website their. Enjoy the new website with lots of new widget, 3x faster performance and the new &lt;a href="http://dev.live.com/livesearch/"&gt;Live Search&lt;/a&gt; on the top right corner. &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1572814" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/ajax/default.aspx">ajax</category></item></channel></rss>