<?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 : performance</title><link>http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx</link><description>Tags: performance</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP2 (Build: 40407.4157)</generator><item><title>Simple way to cache objects and collections for greater performance and scalability</title><link>http://msmvps.com/blogs/omar/archive/2009/11/01/simple-way-to-cache-objects-and-collections-for-greater-performance-and-scalability.aspx</link><pubDate>Sun, 01 Nov 2009 16:41:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1736807</guid><dc:creator>omar</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1736807</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2009/11/01/simple-way-to-cache-objects-and-collections-for-greater-performance-and-scalability.aspx#comments</comments><description>&lt;p&gt;Caching of frequently used data greatly increases the scalability of your application since you can avoid repeated queries on database, file system or to webservices. When objects are cached, it can be retrieved from the cache which is lot faster and more scalable than loading from database, file or web service. However, implementing caching is tricky and monotonous when you have to do it for many classes. Your data access layer gets a whole lot of code that deals with caching objects and collection, updating cache when objects change or get deleted, expire collections when a contained object changes or gets deleted and so on. The more code you write, the more maintenance overhead you add. Here I will show you how you can make the caching a lot easier using Linq to SQL and my library &lt;a title="Fluent way to add Aspect in your code" href="http://code.google.com/p/aspectf/"&gt;AspectF&lt;/a&gt;. It’s a library that helps you get rid of thousands of lines of repeated code from a medium sized project and eliminates plumbing (logging, error handling, retrying etc) type code completely.&lt;/p&gt;  &lt;p&gt;Here’s an example how caching significantly improves the performance and scalabitlity of applications. Dropthings – my open source Web 2.0 AJAX portal, without caching can only serve about 11 request/sec with 10 concurrent users on a dual core 64 bit PC. Here data is loaded from database as well as from external sources. Avg page response time is 1.44 sec.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.metablogapi/4606.LoadTestWithoutCache_5F00_507E9888.png"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="Load Test Without Cache" border="0" alt="Load Test Without Cache" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.metablogapi/0003.LoadTestWithoutCache_5F00_thumb_5F00_4D790E08.png" width="557" height="364" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;After implementing caching, it became significantly faster, around &lt;strong&gt;32 requests/sec&lt;/strong&gt;. Page load time decreased significantly as well to &lt;strong&gt;0.41 sec&lt;/strong&gt; only. During the load test, CPU utilization was around 60%.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.metablogapi/0410.LoadTestwithinmemorycache_5F00_33E15B0E.png"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="Load Test with in memory cache" border="0" alt="Load Test with in memory cache" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.metablogapi/6761.LoadTestwithinmemorycache_5F00_thumb_5F00_7F6088C5.png" width="598" height="411" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;It shows clearly the significant difference it can make to your application. If you are suffering from poor page load performance and high CPU or disk activity on your database and application server, then caching Top 5 most frequently used objects in your application will solve that problem right away. It’s a quick win to make your application a lot faster than doing complex re-engineering in your application.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Common approaches to caching objects and collections&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Sometimes the caching can be simple, for example caching a single object which does not belong to a collection and does not have child collections that are cached separately. In such case, you write simple code like this:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Is the object being requested already in cache?      &lt;ul&gt;       &lt;li&gt;Yes, then serve it from cache. &lt;/li&gt;        &lt;li&gt;No, then load it from database and then cache it. &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;On the other hand, when you are dealing with cached collection where each item in the collection is also cached separately, then the caching logic is not so simple. For example, say you have cached a &lt;code&gt;User&lt;/code&gt; collection. But each &lt;code&gt;User&lt;/code&gt; object is also cached separately because you need to load individual &lt;code&gt;User&lt;/code&gt; objects frequently. Then the caching logic gets more complicated:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Is the collection being requested already in cache?      &lt;ul&gt;       &lt;li&gt;Yes. Get the collection. For each object in the collection:          &lt;ul&gt;           &lt;li&gt;Is that object individually available in cache?              &lt;ul&gt;               &lt;li&gt;Yes, get the individual object from cache. Update it in the collection. &lt;/li&gt;                &lt;li&gt;No, discard the whole collection from cache. Go to next step: &lt;/li&gt;             &lt;/ul&gt;           &lt;/li&gt;         &lt;/ul&gt;       &lt;/li&gt;        &lt;li&gt;No. Load the collection from source (eg database) and cache each item in the collection separately. Then cache the collection. &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;You might be thinking why do we need to read each individual item from cache and why do we need to cache each item in collection separarely when the whole collection is already in cache? There are two scenarios you need to address when you cache a collection and individual items in that collection are also cached separately:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;An individual item has been updated and the updated item is in cache. But the collection, which contains all those individual items, has not been refreshed. So, if you get the collection from cache and return as it is, you will get stale individual items inside that collection. This is why each item needs to be retrieved from cache separately. &lt;/li&gt;    &lt;li&gt;An item in the collection may have been force expired in cache. For ex, something changed in the object or the object has been deleted. So, you expired it in cache so that on next retrieval it comes from database. If you load the collection from cache only, then the collection will contain the stale object. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;If you are doing it the conventional way, you will be writing a lot of repeated code in your data access layer. For example, say you are loading a &lt;code&gt;Page&lt;/code&gt; collection that belongs to a user. If you want to cache the collection of &lt;code&gt;Page&lt;/code&gt; for a user as well as cache individual &lt;code&gt;Page&lt;/code&gt; objects so that each &lt;code&gt;Page&lt;/code&gt; can be retrieved from Cache directly. Then you need to write code like this:&lt;/p&gt;  &lt;pre class="dark"&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;public &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;List&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;Page&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;GetPagesOfUserOldSchool&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#2b91af;"&gt;Guid &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;userGuid&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;)
{
    &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#2b91af;"&gt;ICache &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;cache &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;Services&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;Get&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#2b91af;"&gt;ICache&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;gt;();
    &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;bool &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;isCacheStale &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;false&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;;
    &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;string &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;cacheKey &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;CacheSetup&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;CacheKeys&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;PagesOfUser&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;userGuid&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;);
    &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;cachedPages &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;cache&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;Get&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;cacheKey&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;) &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;as &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;List&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;Page&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;gt;;
    &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;if &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;cachedPages &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;!= &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;)
    {
        &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;resultantPages &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;new &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;List&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;Page&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;gt;();
        &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#7f9f7f;"&gt;// If each item in the collection is no longer in cache, invalidate the collection
        // and load again.
        &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;foreach &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;Page &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;cachedPage &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;in &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;cachedPages&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;)
        {
            &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;individualPageInCache &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;cache&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;Get&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;CacheSetup&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;CacheKeys&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;PageId&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;cachedPage&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;ID&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;)) &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;as &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;Page&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;;
            &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;if &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;null &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;== &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;individualPageInCache&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;)
            {
                &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#7f9f7f;"&gt;// Some item is missing in cache. So, the collection is stale. 
                &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;isCacheStale &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;true&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;;
            }
            &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;else
            &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;{
                &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;resultantPages&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;Add&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;individualPageInCache&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;);
            }
        }

        &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;cachedPages &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;resultantPages&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;;
    }

    &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;if &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;isCacheStale&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;)
    {
        &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#7f9f7f;"&gt;// Collection not cached. Need to load collection from database and then cache it.
        &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;pagesOfUser &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;_database&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;GetList&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;Page&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#2b91af;"&gt;Guid&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;gt;(...&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;);
        &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;pagesOfUser&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;Each&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;page &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;=&amp;gt;
        {
            &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;page&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;Detach&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;();
            &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;cache&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;Add&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;CacheSetup&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;CacheKeys&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;PageId&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;page&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;ID&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;), &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;page&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;);
        });
        &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;cache&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;Add&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;cacheKey&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;pagesOfUser&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;);
        &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;return &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;pagesOfUser&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;;
    }
    &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;else
    &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;{
        &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;return &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;cachedPages&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;;
    }
}&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Imagine writing this kind of code over and over again for each and every entity that you want to cache. This becomes a maintenace nightmare as your project grows.&lt;/p&gt;

&lt;p&gt;Here’s how you could do it using &lt;a title="Fluent way to add Aspect in your code" href="http://code.google.com/p/aspectf/"&gt;AspectF&lt;/a&gt;:&lt;/p&gt;

&lt;pre class="dark"&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;public &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;List&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;Page&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;GetPagesOfUser&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#2b91af;"&gt;Guid &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;userGuid&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;)
{
    &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#eaeaac;"&gt;return &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;AspectF&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;Define
        &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;CacheList&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;Page&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;List&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;Page&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;gt;&amp;gt;(&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;Services&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;Get&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#2b91af;"&gt;ICache&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;gt;()&lt;/span&gt;&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;, &lt;br /&gt;&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;                     CacheSetup&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;CacheKeys&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;PagesOfUser&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;userGuid&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;), &lt;br /&gt;&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;                     page &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;CacheSetup&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;CacheKeys&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;PageId&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;page&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;ID&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;))
        .&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;Return&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;List&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;Page&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;gt;&amp;gt;(() =&amp;gt; 
            &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;_database&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;GetList&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;Page&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#2b91af;"&gt;Guid&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;&amp;gt;(&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#f0dfaf;"&gt;...&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;).&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;Select&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;p &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;p&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;Detach&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;()).&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dfdfbf;"&gt;ToList&lt;/span&gt;&lt;span style="background:#2a2a2a;color:#dcdccc;"&gt;());
}
&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Instead of 42 lines of code, you can do it in 5 lines!&lt;/p&gt;

&lt;p&gt;Read my article &lt;a title="Simple way to cache objects and collections for greater performance and scalability" href="http://www.codeproject.com/KB/web-cache/easycaching.aspx"&gt;Simple way to cache objects and collections for greater performance and scalability&lt;/a&gt; on CodeProject and learn:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Caching Linq to SQL entities &lt;/li&gt;

  &lt;li&gt;Handling update and delete scenarios&lt;/li&gt;

  &lt;li&gt;Expiring dependent objects and collections in cache&lt;/li&gt;

  &lt;li&gt;Handling objects that’s cached with multiple keys&lt;/li&gt;

  &lt;li&gt;Avoid database query optimizations when you cache sets of data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enjoy. Don’t forget to 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%2f11%2f01%2fsimple-way-to-cache-objects-and-collections-for-greater-performance-and-scalability.aspx" rev="vote-for"&gt;&lt;img src="http://dotnetburner.com/image.axd?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2009%2f11%2f01%2fsimple-way-to-cache-objects-and-collections-for-greater-performance-and-scalability.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%2f11%2f01%2fsimple-way-to-cache-objects-and-collections-for-greater-performance-and-scalability.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%2f11%2f01%2fsimple-way-to-cache-objects-and-collections-for-greater-performance-and-scalability.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%2f11%2f01%2fsimple-way-to-cache-objects-and-collections-for-greater-performance-and-scalability.aspx"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2009%2f11%2f01%2fsimple-way-to-cache-objects-and-collections-for-greater-performance-and-scalability.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=1736807" 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/linq/default.aspx">linq</category><category domain="http://msmvps.com/blogs/omar/archive/tags/.net/default.aspx">.net</category></item><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>Memory Leak with delegates and workflow foundation</title><link>http://msmvps.com/blogs/omar/archive/2009/03/14/memory-leak-with-delegates-and-workflow-foundation.aspx</link><pubDate>Sat, 14 Mar 2009 08:35:53 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1678020</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=1678020</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2009/03/14/memory-leak-with-delegates-and-workflow-foundation.aspx#comments</comments><description>&lt;p&gt;Recently after Load Testing my open source project &lt;a href="http://www.dropthings.com" target="_blank"&gt;Dropthings&lt;/a&gt;, I encountered a lot of memory leak. I found lots of Workflow Instances and Linq Entities were left in memory and never collected. After profiling the web application using &lt;a title="Memory Profiler for .NET" href="http://memprofiler.com/" target="_blank"&gt;.NET Memory Profiler&lt;/a&gt;, it showed the real picture:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_41151CF2.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="646" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_416D161B.png" width="605" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;It shows you that instances of the several types are being created but not being removed. You see the “New” column has positive value, but the “Remove” column has 0. That means new instances are being created, but not removed. Basically the way you do Memory Profiling is, you take two snapshots. Say you take one snapshot when you first visit your website. Then you do some action on the website that results in allocation of objects. Then you take another snapshot. When you compare both snapshots, you can see how many instances of classes were created between these two snapshots and how many were removed. If they are not equal, then you have leak. Generally in web application many objects are created on every page hit and the end of the request, all those objects are supposed to be released. If they are not released, then we have a problem. But that’s the scenario for desktop applications because in a desktop application, objects can remain in memory until app is closed. But you should know best from the code which objects were supposed to go out of scope and get released.&lt;/p&gt;  &lt;p&gt;For beginners, leak means objects are being allocated but not being freed because someone is holding reference to the objects. When objects leak, they remain in memory forever, until the process (or app domain) is closed. So, if you have a leaky website, your website is continuously taking up memory until it runs out of memory on the web server and thus crash. So, memory leak is a bad – it prevents you from running your product for long duration and requires frequent restart of app pool. &lt;/p&gt;  &lt;p&gt;So, the above screenshot shows Workflow and Linq related classes are not being removed, and thus leaking. This means somewhere workflow instances are not being released and thus all workflow related objects are remaining. You can see the number is same 48 for all workflow related objects. This is a good indication that, almost every instance of workflow is leaked because there were total 48 workflows created and ran. Moreover it indicates we have a leak from a top Workflow instance level, not in some specific Activity or somewhere deep in the code.&lt;/p&gt;  &lt;p&gt;As the workflows use Linq stuff, they held reference to the Linq stuffs and thus the Linq stuffs leaked as well. Sometimes you might be looking for why A is leaking. But you actually end up finding that since B was holding reference to A and B was leaking and thus A was leaking as well. This is sometimes tricky to figure out and you spend a lot of time looking at the wrong direction.&lt;/p&gt;  &lt;p&gt;Now let me show you the buggy code:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ManualWorkflowSchedulerService manualScheduler &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;br /&gt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;  workflowRuntime&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;GetService&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ManualWorkflowSchedulerService&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;gt;();

&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowInstance instance &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;workflowRuntime&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;CreateWorkflow&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;workflowType&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;properties&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);
&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instance&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Start&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();

&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;EventHandler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowCompletedEventArgs&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;completedHandler &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;completedHandler &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;delegate&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;object &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;o&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowCompletedEventArgs e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
{
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;if &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowInstance&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;InstanceId &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;== &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instance&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;InstanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;) &lt;span style="background:#3f3f3f;color:#7f9f7f;"&gt;// 1. instance&lt;/span&gt;
    {
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;workflowRuntime&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowCompleted &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;-= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;completedHandler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;; &lt;span style="background:#3f3f3f;color:#7f9f7f;"&gt;// 2. terminatedhandler&lt;/span&gt;

        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#7f9f7f;"&gt;// copy the output parameters in the specified properties dictionary
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;Dictionary&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;string&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;,&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;object&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;Enumerator &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;enumerator &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;br /&gt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;            e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;OutputParameters&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;GetEnumerator&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;while&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;( &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;enumerator&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;MoveNext&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;() )
        {
            &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;KeyValuePair&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;string&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;,&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;object&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;pair &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;enumerator&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Current&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
            &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;if&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;( &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;properties&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ContainsKey&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;pair&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Key&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;) )
            {
                &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;properties&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;[&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;pair&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Key&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;] = &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;pair&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Value&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
            }
        }
    }
};

&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;Exception &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;x  &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;EventHandler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowTerminatedEventArgs&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;terminatedHandler &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;terminatedHandler &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;delegate&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;object &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;o&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowTerminatedEventArgs e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
{
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;if &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowInstance&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;InstanceId &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;== &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instance&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;InstanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;) &lt;span style="background:#3f3f3f;color:#7f9f7f;"&gt;// 3. instance&lt;/span&gt;
    {
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;workflowRuntime&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowTerminated &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;-= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;terminatedHandler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;; &lt;span style="background:#3f3f3f;color:#7f9f7f;"&gt;// 4. completeHandler&lt;/span&gt;
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Debug&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WriteLine&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;( &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Exception &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);

        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;x &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Exception&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
    }
};

&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;workflowRuntime&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowCompleted &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;+= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;completedHandler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;workflowRuntime&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowTerminated &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;+= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;terminatedHandler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;

&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;manualScheduler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;RunWorkflow&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instance&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;InstanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Can you spot the code where it leaked?&lt;/p&gt;

&lt;p&gt;I have numbered the lines in comment where the leak is happening. Here the &lt;code&gt;delegate&lt;/code&gt; is acting like a closure and those who are from Javascript background know closure is evil. They leak memory unless very carefully written. Here the &lt;code&gt;delegate&lt;/code&gt; keeps a reference to the &lt;code&gt;instance&lt;/code&gt; object. So, if somehow &lt;code&gt;delegate&lt;/code&gt; is not released, the &lt;code&gt;instance&lt;/code&gt; will remain in memory forever and thus leak. Now can you find a situation when the &lt;code&gt;delegate&lt;/code&gt; will not be released?&lt;/p&gt;

&lt;p&gt;Say the workflow completed. It will fire the &lt;font color="#990000"&gt;completeHandler&lt;code&gt;. &lt;/code&gt;&lt;/font&gt;But the &lt;code&gt;completeHandler&lt;/code&gt; will not release the &lt;code&gt;terminateHandler&lt;code&gt;. &lt;/code&gt;&lt;/code&gt;Thus the &lt;code&gt;terminateHandler&lt;/code&gt; remains in memory and it also holds reference to the &lt;code&gt;instance&lt;/code&gt;. So, we have a leaky &lt;code&gt;delegate&lt;/code&gt; leaking whatever it is holding onto outside it’s scope. Here the only thing outside the scope if the &lt;code&gt;instance&lt;/code&gt;, which it is tried to access from the parent function.&lt;/p&gt;

&lt;p&gt;Since the workflow instance is not released, all the properties the workflow and all the activities inside it are holding onto remains in memory. Most of the workflows and activities expose public properties which are Linq Entities. Thus the Linq Entities remain in memory. Now Linq Entities keep a reference to the &lt;code&gt;DataContext&lt;/code&gt; from where it is produced. Thus we have &lt;code&gt;DataContext&lt;/code&gt; remaining in memory. Moreover, &lt;code&gt;DataContext&lt;/code&gt; keeps reference to many internal objects and metadata cacahe, so they remain in memory as well.&lt;/p&gt;

&lt;p&gt;So, the correct code is:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;ManualWorkflowSchedulerService &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;manualScheduler &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;workflowRuntime&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;GetService&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;ManualWorkflowSchedulerService&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;gt;();

&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;WorkflowInstance &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instance &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;workflowRuntime&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;CreateWorkflow&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;workflowType&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;properties&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);
&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instance&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Start&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instanceId &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instance&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;InstanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;

&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;EventHandler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;WorkflowCompletedEventArgs&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;completedHandler &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;completedHandler &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;delegate&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;object &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;o&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;WorkflowCompletedEventArgs &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
{
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;if &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowInstance&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;InstanceId &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;== &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;) &lt;span style="background:#3f3f3f;color:#7f9f7f;"&gt;// 1. instanceId is a Guid&lt;/span&gt;
    {
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#7f9f7f;"&gt;// copy the output parameters in the specified properties dictionary
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;Dictionary&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;string&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;,&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;object&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;Enumerator &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;enumerator &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;br /&gt;                &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;OutputParameters&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;GetEnumerator&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;while&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;( &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;enumerator&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;MoveNext&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;() )
        {
            &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;KeyValuePair&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;string&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;,&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;object&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;pair &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;enumerator&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Current&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
            &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;if&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;( &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;properties&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ContainsKey&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;pair&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Key&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;) )
            {
                &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;properties&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;[&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;pair&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Key&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;] = &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;pair&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Value&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
            }
        }
    }
};

&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;Exception &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;x  &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;EventHandler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;WorkflowTerminatedEventArgs&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;terminatedHandler &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;terminatedHandler &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;delegate&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;object &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;o&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;WorkflowTerminatedEventArgs &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
{
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;if &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowInstance&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;InstanceId &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;== &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;) &lt;span style="background:#3f3f3f;color:#7f9f7f;"&gt;// 2. instanceId is a Guid&lt;/span&gt;
    {
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;x &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Exception&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;Debug&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WriteLine&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Exception&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);
    }
};

&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;workflowRuntime&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowCompleted &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;+= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;completedHandler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;workflowRuntime&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowTerminated &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;+= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;terminatedHandler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;

&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;manualScheduler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;RunWorkflow&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instance&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;InstanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);
&lt;span style="background:#3f3f3f;color:#7f9f7f;"&gt;// 3. Both delegates are now released&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;workflowRuntime&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowTerminated &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;-= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;terminatedHandler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;workflowRuntime&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowCompleted &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;-= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;completedHandler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;There are two changes – in both delegates, the &lt;code&gt;instanceId&lt;/code&gt; variable is passed, instead of the instance. Since &lt;code&gt;instanceId&lt;/code&gt; is a &lt;code&gt;Guid&lt;/code&gt;, which is a struct type data type, not a class, there’s no issue of referencing. Structs are copied, not referenced. So, they don’t leak memory. Secondly, both &lt;code&gt;delegate&lt;/code&gt;s are released at the end of the workflow execution, thus releasing both references.&lt;/p&gt;

&lt;p&gt;In Dropthings, I am using the famous &lt;a title="CallWorkflow Activity" href="http://www.masteringbiztalk.com/blogs/jon/PermaLink,guid,7be9fb53-0ddf-4633-b358-01c3e9999088.aspx" target="_blank"&gt;CallWorkflow Activity by John Flanders&lt;/a&gt;, which is widely used to execute one Workflow from another synchronously. There’s a &lt;code&gt;CallWorkflowService&lt;/code&gt; class which is responsible for synchronously executing another workflow and that has similar memory leak problem. The original code of the service is as following:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;public class &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;CallWorkflowService &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;: &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowRuntimeService
&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;{
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfaf8f;"&gt;#region &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;Methods

    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;public void &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;StartWorkflow&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;Type &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;workflowType&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;,&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;Dictionary&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;string&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;,&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;object&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;inparms&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;br /&gt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;           Guid &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;caller&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;,&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;IComparable &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;qn&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
    {
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowRuntime wr &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;this&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Runtime&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowInstance wi &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wr&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;CreateWorkflow&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;workflowType&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;,&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;inparms&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wi&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Start&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ManualWorkflowSchedulerService ss &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;br /&gt;             &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wr&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;GetService&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ManualWorkflowSchedulerService&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;gt;();
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;if &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ss &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;!= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
            &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ss&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;RunWorkflow&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wi&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;InstanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;EventHandler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowCompletedEventArgs&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;d  &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;d &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;delegate&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;object &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;o&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowCompletedEventArgs e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
        {
            &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;if &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowInstance&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;InstanceId &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;==&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wi&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;InstanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
            {
                &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wr&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowCompleted &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;-= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;d&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
                &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowInstance c &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wr&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;GetWorkflow&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;caller&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);
                &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;c&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;EnqueueItem&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;qn&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;OutputParameters&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);
            }
        };
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;EventHandler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowTerminatedEventArgs&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;te &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;te &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;delegate&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;object &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;o&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowTerminatedEventArgs e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
        {
            &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;if &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowInstance&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;InstanceId &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;== &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wi&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;InstanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
            {
                &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wr&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowTerminated &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;-= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;te&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
                &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowInstance c &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wr&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;GetWorkflow&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;caller&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);
                &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;c&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;EnqueueItem&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;qn&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;new &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;Exception&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#c89191;"&gt;&amp;quot;Called Workflow Terminated&amp;quot;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;br /&gt;                  &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Exception&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;), &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);
            }
        };
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wr&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowCompleted &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;+= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;d&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wr&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowTerminated &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;+= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;te&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
    }

    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfaf8f;"&gt;#endregion &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;Methods
}&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;As you see, it has that same delegate holding reference to instance object problem. Moreover, there’s some queue stuff there, which requires the &lt;code&gt;caller&lt;/code&gt; and &lt;code&gt;qn&lt;/code&gt; parameter passed to the &lt;code&gt;StartWorkflow&lt;/code&gt; function. So, not a straight forward fix. &lt;/p&gt;

&lt;p&gt;I tried to rewrite the whole &lt;code&gt;CallWorkflowService&lt;/code&gt; so that it does not require two delegates to be created per Workflow. Then I took the delegates out. Thus there’s no chance of closure holding reference to unwanted objects. The result looks like this:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;public class &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;CallWorkflowService &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;: &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;WorkflowRuntimeService
&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;{
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfaf8f;"&gt;#region &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;Fields

    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;private &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;EventHandler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;WorkflowCompletedEventArgs&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;_CompletedHandler &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;private &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;EventHandler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;WorkflowTerminatedEventArgs&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;_TerminatedHandler &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;private &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;Dictionary&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;Guid&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;WorkflowInfo&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;_WorkflowQueue &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;br /&gt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;       new &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;Dictionary&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;Guid&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;WorkflowInfo&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;gt;();

    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfaf8f;"&gt;#endregion &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;Fields

    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfaf8f;"&gt;#region &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;Methods

    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;public void &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;StartWorkflow&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;Type &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;workflowType&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;,&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;Dictionary&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;string&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;,&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;object&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;inparms&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;,&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;Guid &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;caller&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;,&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;IComparable &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;qn&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
    {
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;WorkflowRuntime &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wr &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;this&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Runtime&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;WorkflowInstance &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wi &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wr&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;CreateWorkflow&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;workflowType&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;,&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;inparms&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wi&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Start&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();

        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instanceId &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wi&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;InstanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;_WorkflowQueue&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;[&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;] = &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;new &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;WorkflowInfo &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;{ &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Caller &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;caller&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;qn &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;qn &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;};

        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;ManualWorkflowSchedulerService &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ss &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;br /&gt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;           wr&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;GetService&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;ManualWorkflowSchedulerService&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;&amp;gt;();
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;if &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ss &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;!= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
            &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ss&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;RunWorkflow&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wi&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;InstanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);
    }

    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;protected override void &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;OnStarted&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;()
    {
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;base&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;OnStarted&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();

        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;if &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;== &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;_CompletedHandler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
        {
            &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;_CompletedHandler &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;delegate&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;object &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;o&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;WorkflowCompletedEventArgs &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
            {
                &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instanceId &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowInstance&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;InstanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
                &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;if &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;_WorkflowQueue&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ContainsKey&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;))
                {
                    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;WorkflowInfo &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wf &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;_WorkflowQueue&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;[&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;];
                    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;WorkflowInstance &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;c &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;this&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Runtime&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;GetWorkflow&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wf&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Caller&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);
                    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;c&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;EnqueueItem&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wf&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;qn&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;OutputParameters&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);
                    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;_WorkflowQueue&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Remove&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);
                }
            };
            &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;this&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Runtime&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowCompleted &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;+= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;_CompletedHandler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
        }

        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;if &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;== &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;_TerminatedHandler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
        {
            &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;_TerminatedHandler &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;delegate&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;object &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;o&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;WorkflowTerminatedEventArgs &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
            {
                &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instanceId &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowInstance&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;InstanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
                &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;if &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;_WorkflowQueue&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ContainsKey&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;))
                {
                    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;WorkflowInfo &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wf &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;_WorkflowQueue&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;[&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;];
                    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;WorkflowInstance &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;c &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;this&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Runtime&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;GetWorkflow&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wf&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Caller&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);
                    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;c&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;EnqueueItem&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;wf&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;qn&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;br /&gt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;                      new &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;Exception&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#c89191;"&gt;&amp;quot;Called Workflow Terminated&amp;quot;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;e&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Exception&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;), &lt;br /&gt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;                      null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);
                    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;_WorkflowQueue&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Remove&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;instanceId&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);
                }
            };

            &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;this&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Runtime&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;WorkflowTerminated &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;+= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;_TerminatedHandler&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
        }
    }

    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;protected override void &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;OnStopped&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;()
    {
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;_WorkflowQueue&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Clear&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();

        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;base&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;OnStopped&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
    }

    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfaf8f;"&gt;#endregion &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;Methods

    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfaf8f;"&gt;#region &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;Nested Types

    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;private struct &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;WorkflowInfo
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;{
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfaf8f;"&gt;#region &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;Fields

        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;public &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;Guid &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Caller&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;public &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;IComparable &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;qn&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;;

        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfaf8f;"&gt;#endregion &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;Fields
    }

    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfaf8f;"&gt;#endregion &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;Nested Types
}&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;After fixing the problem, another Memory Profile result showed the leak is gone:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_0CF441A2.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="601" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_2BCA8B51.png" width="564" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;As you see, the numbers vary, which means there’s no consistent leak. Moreover, looking at the types that remains in memory, they look more like metadata than instances of classes.&amp;#160; So, they are basically cached instances of metadata, not instances allocated during workflow execution which are supposed to be freed. So, we solved the memory leak!&lt;/p&gt;

&lt;p&gt;Now you know how to write anonymous delegates without leaking memory and how to run workflow without leaking them. Basically, the principle theory is – if you are referencing some outside object from an anonymous &lt;code&gt;delegate&lt;/code&gt;, make sure that object is not holding reference to the &lt;code&gt;delegate&lt;/code&gt; in some way, may be directly or may be via some child objects of its own. Because then you have a circular reference. If possible, do not try to access objects e.g. &lt;code&gt;instance&lt;/code&gt; inside an anonymous delegate that is declared outside the delegate. Try accessing instrinsic data types like int, string, DateTime, Guid etc which are not reference type variables. So, instead of referencing to an object, you should declare local variables e.g. &lt;code&gt;instanceId&lt;/code&gt; that gets the value of properties (e.g. &lt;code&gt;instance.InstanceId&lt;/code&gt;) from the object and then use those local variables inside the anonymous delegate.&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/03/14/memory-leak-with-delegates-and-workflow-foundation.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http://msmvps.com/blogs/omar/archive/2009/03/14/memory-leak-with-delegates-and-workflow-foundation.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=1678020" 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/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/.net/default.aspx">.net</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>Linq to SQL solve Transaction deadlock and Query timeout problem using uncommitted reads</title><link>http://msmvps.com/blogs/omar/archive/2009/03/07/linq-to-sql-solve-transaction-deadlock-and-query-timeout-problem-using-uncommitted-reads.aspx</link><pubDate>Sat, 07 Mar 2009 07:30:52 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1676241</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=1676241</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2009/03/07/linq-to-sql-solve-transaction-deadlock-and-query-timeout-problem-using-uncommitted-reads.aspx#comments</comments><description>&lt;p&gt;When your database tables start accumulating thousands of rows and many users start working on the same table concurrently, SELECT queries on the tables start producing lock contentions and transaction deadlocks. This is a common problem in any high volume website. As soon as you start getting several concurrent users hitting your website that results in SELECT queries on some large table like &lt;u&gt;aspnet_users&lt;/u&gt; table that are also being updated very frequently, you end up having one of these errors:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Transaction (Process ID ##) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction. &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Or,&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Timeout Expired. The Timeout Period Elapsed Prior To Completion Of The Operation Or The Server Is Not Responding. &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The solution to these problems are – use proper index on the table and use transaction isolation level &lt;u&gt;Read Uncommitted&lt;/u&gt; or &lt;u&gt;WITH (NOLOCK)&lt;/u&gt; in your SELECT queries. So, if you had a query like this:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;SELECT * FORM aspnet_users &lt;br /&gt;&lt;span class="kwrd"&gt;where&lt;/span&gt; ApplicationID =’xxx’ AND LoweredUserName = &lt;span class="str"&gt;&amp;#39;someuser&amp;#39;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;You should end up having any of the above errors under high load. There are two ways to solve this:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;SET TRANSACTION LEVEL READ UNCOMMITTED;
SELECT * FROM aspnet_Users &lt;br /&gt;WHERE ApplicationID =’xxx’ AND LoweredUserName = &lt;span class="str"&gt;&amp;#39;someuser&amp;#39;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Or use the WITH (NOLOCK):&lt;/p&gt;

&lt;pre class="csharpcode"&gt;SELECT * FROM aspnet_Users WITH (NOLOCK) &lt;br /&gt;WHERE ApplicationID =’xxx’ AND LoweredUserName = &lt;span class="str"&gt;&amp;#39;someuser&amp;#39;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;The reason for the errors are that since &lt;u&gt;aspnet_users&lt;/u&gt; is a high read and high write table, during read, the table is partially locked and during write, it is also locked. So, when the locks overlap on each other from several queries and especially when there’s a query that’s trying to read a large number of rows and thus locking large number of rows, some of the queries either timeout or produce deadlocks.&lt;/p&gt;

&lt;p&gt;Linq to Sql does not produce queries with the &lt;u&gt;WITH (NOLOCK)&lt;/u&gt; option nor does it use &lt;u&gt;READ UNCOMMITTED&lt;/u&gt;. So, if you are using Linq to SQL queries, you are going to end up with any of these problems on production pretty soon when your site becomes highly popular.&lt;/p&gt;

&lt;p&gt;For example, here’s a very simple query:&lt;/p&gt;

&lt;pre class="code" style="background:#3f3f3f;"&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;using (&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;db &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;new &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;DropthingsDataContext&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;())
{
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;user &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;db&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;aspnet_Users&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;First&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;pages &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;user&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Pages&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ToList&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
}&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;&lt;u&gt;DropthingsDataContext&lt;/u&gt; is a &lt;u&gt;DataContext&lt;/u&gt; built from &lt;a title="Dropthings - Open Source AJAX Portal" href="http://www.dropthings.com/" target="_blank"&gt;Dropthings&lt;/a&gt; database.&lt;/p&gt;

&lt;p&gt;When you attach SQL Profiler, you get this:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_2B685BF8.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="174" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_7A197197.png" width="639" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;You see none of the queries have READ UNCOMMITTED or WITH (NOLOCK). &lt;/p&gt;

&lt;p&gt;The fix is to do this:&lt;/p&gt;

&lt;pre class="code" style="background:#3f3f3f;"&gt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;using (&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;db &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;new &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;DropthingsDataContext2&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;())
{
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;db&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Connection&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Open&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;db&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ExecuteCommand&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#c89191;"&gt;&amp;quot;SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;&amp;quot;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);

    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;user &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;db&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;aspnet_Users&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;First&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;pages &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;user&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Pages&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ToList&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
}&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;This will result in the following profiler output&lt;/p&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_5DBC09AA.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="91" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_09202AA5.png" width="630" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;As you see, both queries execute within the same connection and the isolation level is set before the queries execute. So, both queries enjoy the isolation level.&lt;/p&gt;

&lt;p&gt;Now there’s a catch, the connection does not close. This seems to be a bug in the DataContext that when it is disposed, it does not dispose the connection it is holding onto. &lt;/p&gt;

&lt;p&gt;In order to solve this, I have made a child class of the &lt;u&gt;DropthingsDataContext&lt;/u&gt; named &lt;u&gt;DropthingsDataContext2&lt;/u&gt; which overrides the &lt;u&gt;Dispose&lt;/u&gt; method and closes the connection.&lt;/p&gt;

&lt;pre class="code" style="background:#3f3f3f;"&gt;   &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;class &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;DropthingsDataContext2 &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;: &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;DropthingsDataContext&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;IDisposable
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;{
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;public new void &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Dispose&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;()
        {
            &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;if &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;base&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Connection &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;!= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
                &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;if &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;base&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Connection&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;State &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;!= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;System&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Data&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;ConnectionState&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Closed&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
                {
                    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;base&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Connection&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Close&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
                    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;base&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Connection&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Dispose&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
                }

            &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;base&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Dispose&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();            
        }
    }&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;This solved the connection problem.&lt;/p&gt;

&lt;p&gt;There you have it, no more transaction deadlock or lock contention from Linq to SQL queries. But remember, this is only to eliminate such problems when your database already has the right indexes. If you do not have the proper index, then you will end up having lock contention and query timeouts anyway.&lt;/p&gt;

&lt;p&gt;There’s one more catch, READ UNCOMMITTED will return rows from transactions that have not completed yet. So, you might be reading rows from transactions that will rollback. Since that’s generally an exceptional scenario, you are more or less safe with uncommitted read, but not for financial applications where transaction rollback is a common scenario. In such case, go for committed read or repeatable read.&lt;/p&gt;

&lt;p&gt;There’s another way you can achieve the same, which seems to work, that is using .NET Transactions. Here’s the code snippet:&lt;/p&gt;

&lt;pre class="code" style="background:#3f3f3f;"&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;using &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;transaction &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;new &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;TransactionScope&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;TransactionScopeOption&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;RequiresNew&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;,
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;new &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;TransactionOptions&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;()
    {
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;IsolationLevel &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;IsolationLevel&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ReadUncommitted&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;,
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Timeout &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;TimeSpan&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;FromSeconds&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#8acccf;"&gt;30&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
    }))
{
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;using &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;db &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;new &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;DropthingsDataContext&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;())
    {
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;user &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;db&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;aspnet_Users&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;First&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;pages &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;user&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Pages&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ToList&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();

        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;transaction&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Complete&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
    }
}&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Profiler shows a transaction begins and ends:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_48683F55.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="273" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_0F118CC6.png" width="499" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The downside is it wraps your calls in a transaction. So, you are unnecessarily creating transactions even for SELECT operations. When you do this hundred times per second on a web application, it’s a significant over head. &lt;/p&gt;

&lt;p&gt;Some really good examples of deadlocks are given in this article:&lt;/p&gt;

&lt;p&gt;&lt;a title="http://www.code-magazine.com/article.aspx?quickid=0309101&amp;amp;page=2" href="http://www.code-magazine.com/article.aspx?quickid=0309101&amp;amp;page=2"&gt;http://www.code-magazine.com/article.aspx?quickid=0309101&amp;amp;page=2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I highly recommend it.&lt;/p&gt;
&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2009%2f03%2f07%2flinq-to-sql-solve-transaction-deadlock-and-query-timeout-problem-using-uncommitted-reads.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%2f2009%2f03%2f07%2flinq-to-sql-solve-transaction-deadlock-and-query-timeout-problem-using-uncommitted-reads.aspx" border="0" /&gt;&lt;/a&gt;&lt;div class="wlWriterHeaderFooter" style="text-align:left;margin:0px;padding:4px 4px 4px 4px;"&gt;&lt;script type="text/javascript"&gt;var dzone_url = &amp;#39;http://msmvps.com/blogs/omar/archive/2009/03/07/linq-to-sql-solve-transaction-deadlock-and-query-timeout-problem-using-uncommitted-reads.aspx&amp;#39;;&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = &amp;#39;Linq to SQL solve Transaction deadlock and Query timeout problem using uncommitted reads&amp;#39;;&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = &amp;#39;Linq to SQL solve Transaction deadlock and Query timeout problem using uncommitted reads&amp;#39;;&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = &amp;#39;2&amp;#39;;&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt; &lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1676241" 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/linq/default.aspx">linq</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>Linq to SQL: Delete an entity using Primary Key only</title><link>http://msmvps.com/blogs/omar/archive/2008/10/30/linq-to-sql-delete-an-entity-using-primary-key-only.aspx</link><pubDate>Thu, 30 Oct 2008 00:27:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1652462</guid><dc:creator>omar</dc:creator><slash:comments>18</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1652462</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/10/30/linq-to-sql-delete-an-entity-using-primary-key-only.aspx#comments</comments><description>&lt;p&gt;Linq to Sql does not come with a function like &lt;span style="text-decoration:underline;"&gt;.Delete(ID)&lt;/span&gt; which allows you to delete an entity using it&amp;rsquo;s primary key. You have to first get the object that you want to delete and then call &lt;span style="text-decoration:underline;"&gt;.DeleteOnSubmit(obj)&lt;/span&gt; to queue it for delete. Then you have to call &lt;span style="text-decoration:underline;"&gt;DataContext.SubmitChanges()&lt;/span&gt; to play the delete queries on database. So, how to delete object without getting them from database and avoid database roundtrip?&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_600F7C48.png"&gt;&lt;img title="Delete an object without getting it - Linq to Sql" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Delete an object without getting it - Linq to Sql" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_7AABF294.png" border="0" height="168" width="486" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;You can call this function using &lt;span style="text-decoration:underline;"&gt;DeleteByPK&amp;lt;Employee, int&amp;gt;(10, dataContext);&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;First type is the entity type and second one is the type of the primary key. If your object&amp;rsquo;s primary key is a &lt;span style="text-decoration:underline;"&gt;Guid&lt;/span&gt; field, specify &lt;span style="text-decoration:underline;"&gt;Guid&lt;/span&gt; instead of &lt;span style="text-decoration:underline;"&gt;int&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;How it works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It figures out the table name and the primary key field name from the entity &lt;/li&gt;
&lt;li&gt;Then it uses the table name and primary key field name to build a DELETE query &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Figuring out the table name and primary key field name is a bit hard. There&amp;rsquo;s some reflection involved. The &lt;span style="text-decoration:underline;"&gt;GetTableDef&amp;lt;TSource&amp;gt;()&lt;/span&gt; returns the table name and primary key field name for an entity.&lt;/p&gt;
&lt;p&gt;Every Linq Entity class is decorated with a &lt;span style="text-decoration:underline;"&gt;Table&lt;/span&gt; attribute that has the table name:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_3E337DEA.png"&gt;&lt;img title="Lint entity declaration" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Lint entity declaration" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_3AD1E642.png" border="0" height="67" width="551" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Then the primary key field is decorated with a &lt;span style="text-decoration:underline;"&gt;Column&lt;/span&gt; attribute with &lt;span style="text-decoration:underline;"&gt;IsPrimaryKey = true&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_7C1CE8DB.png"&gt;&lt;img title="Primary Key field has Column attribute with IsPrimaryKey = true" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Primary Key field has Column attribute with IsPrimaryKey = true" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_031BD9BA.png" border="0" height="77" width="709" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;So, using reflection we can figure out the table name and the primary key property and the field name.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the code that does it:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_600B6849.png"&gt;&lt;img title="Using reflection find the Table attribute and the Column attribute" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Using reflection find the Table attribute and the Column attribute" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_722FCF72.png" border="0" height="615" width="685" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Before you scream &amp;ldquo;Reflection is SLOW!!!!&amp;rdquo; the definition is cached. So, reflection is used only once per appDomain per entity. Subsequent call is just a dictionary lookup away, which is as fast as it can get.&lt;/p&gt;
&lt;p&gt;You can also delete a collection of object without ever getting any one of them. The the following function to delete a whole bunch of objects:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_57CF1AB4.png"&gt;&lt;img title="Delete a list of objects using Linq to SQL" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Delete a list of objects using Linq to SQL" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_3925043E.png" border="0" height="398" width="553" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;The code is available here:&lt;/p&gt;
&lt;p&gt;&lt;a title="http://code.msdn.microsoft.com/DeleteEntitiesLinq" href="http://code.msdn.microsoft.com/DeleteEntitiesLinq"&gt;http://code.msdn.microsoft.com/DeleteEntitiesLinq&lt;/a&gt;&lt;/p&gt;
&lt;div class="wlWriterHeaderFooter" style="text-align:left;margin:0px;padding:4px 4px 4px 4px;"&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f10%2f30%2flinq-to-sql-delete-an-entity-using-primary-key-only.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f10%2f30%2flinq-to-sql-delete-an-entity-using-primary-key-only.aspx" alt="kick it on DotNetKicks.com" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1652462" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx">performance</category><category domain="http://msmvps.com/blogs/omar/archive/tags/linq/default.aspx">linq</category><category domain="http://msmvps.com/blogs/omar/archive/tags/.net/default.aspx">.net</category></item><item><title>Solving common problems with Compiled Queries in Linq to Sql for high demand ASP.NET websites</title><link>http://msmvps.com/blogs/omar/archive/2008/10/27/solving-common-problems-with-compiled-queries-in-linq-to-sql-for-high-demand-asp-net-websites.aspx</link><pubDate>Mon, 27 Oct 2008 13:31:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1652150</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=1652150</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/10/27/solving-common-problems-with-compiled-queries-in-linq-to-sql-for-high-demand-asp-net-websites.aspx#comments</comments><description>&lt;p&gt;If you are using Linq to SQL, instead of writing regular Linq Queries, you should be using &lt;a href="http://linqinaction.net/blogs/jwooley/archive/2007/09/04/linq-to-sql-compiled-queries.aspx"&gt;Compiled Queries&lt;/a&gt;. if you are building an ASP.NET web application that&amp;rsquo;s going to get thousands of hits per hour, the execution overhead of Linq queries is going to consume too much CPU and make your site slow. There&amp;rsquo;s a runtime cost associated with each and every Linq Query you write. The queries are parsed and converted to a nice SQL Statement on *every* hit. It&amp;rsquo;s not done at compile time because there&amp;rsquo;s no way to figure out what you might be sending as the parameters in the queries during runtime. So, if you have common Linq to Sql statements like the following one throughout your growing web application, you are soon going to have scalability nightmares:&lt;/p&gt;
&lt;div&gt;
&lt;pre class="csharpcode"&gt;var query = from widget &lt;span class="kwrd"&gt;in&lt;/span&gt; dc.Widgets&lt;br /&gt;                &lt;span class="kwrd"&gt;where&lt;/span&gt; widget.ID == id &amp;amp;&amp;amp; widget.PageID == pageId&lt;br /&gt;                select widget;&lt;br /&gt;&lt;br /&gt;var widget = query.SingleOrDefault();&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;There&amp;rsquo;s &lt;a href="http://www.jdconley.com/blog/archive/2007/11/28/linq-to-sql-surprise-performance-hit.aspx"&gt;a nice blog post by JD Conley&lt;/a&gt; that shows how evil Linq to Sql queries are:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_03BBB56F.png"&gt;&lt;img title="image" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_481BA6AE.png" border="0" height="389" width="654" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You see how many times &lt;span style="text-decoration:underline;"&gt;SqlVisitor.Visit&lt;/span&gt; is called to convert a Linq Query to its SQL representation? The runtime cost to convert a Linq query to its SQL Command representation is just way too high.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/ricom/archive/2008/01/14/performance-quiz-13-linq-to-sql-compiled-query-cost-solution.aspx"&gt;Rico Mariani has a very informative performance comparison&lt;/a&gt; of regular Linq queries vs Compiled Linq queries performance:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_6C608B30.png"&gt;&lt;img title="image" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_3BEA06BA.png" border="0" height="252" width="531" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Compiled Query wins on every case.&lt;/p&gt;
&lt;p&gt;So, now you know about the benefits of compiled queries. If you are building ASP.NET web application that is going to get high traffic and you have a lot of Linq to Sql queries throughout your project, you have to go for compiled queries. Compiled Queries are built for this specific scenario. &lt;/p&gt;
&lt;p&gt;In this article, I will show you some steps to convert regular Linq to Sql queries to their Compiled representation and how to avoid the dreaded exception &amp;ldquo;&lt;b&gt;Compiled queries across DataContexts with different LoadOptions not supported.&amp;rdquo;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Here are some step by step instruction on converting a Linq to Sql query to its compiled form:&lt;/p&gt;
&lt;p&gt;First we need to find out all the external decision factors in a query. It mostly means parameters in the WHERE clause. Say, we are trying to get a user from &lt;span style="text-decoration:underline;"&gt;aspnet_users&lt;/span&gt; table using Username and Application ID:&lt;/p&gt;
&lt;div&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_674E27B4.png"&gt;&lt;img title="Query to get a user from aspnet_users table" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Query to get a user from aspnet_users table" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_66098ED5.png" border="0" height="57" width="544" /&gt;&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;Here, we have two external decision factor &amp;ndash; one is the Username and another is the Application ID. So, first think this way, if you were to wrap this query in a function that will just return this query as it is, what would you do? You would create a function that takes the &lt;span style="text-decoration:underline;"&gt;DataContext&lt;/span&gt; (dc named here), then two parameters named &lt;span style="text-decoration:underline;"&gt;userName&lt;/span&gt; and &lt;span style="text-decoration:underline;"&gt;applicationID,&lt;/span&gt; right?&lt;/p&gt;
&lt;p&gt;So, be it. We create one function that returns just this query:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_443DB644.png"&gt;&lt;img title="Converting a LInq Query to a function" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Converting a LInq Query to a function" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_4F1A978C.png" border="0" height="103" width="693" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Next step is to replace this function with a &lt;span style="text-decoration:underline;"&gt;Func&amp;lt;&amp;gt;&lt;/span&gt; representation that returns the query. This is the hard part. If you haven&amp;rsquo;t dealt with &lt;span style="text-decoration:underline;"&gt;Func&amp;lt;&amp;gt;&lt;/span&gt; and Lambda expression before, then I suggest you read &lt;a title="Lambda Expression" href="http://blogs.msdn.com/ericwhite/pages/Lambda-Expressions.aspx"&gt;this&lt;/a&gt; and &lt;a title="Lambda Expression" href="http://blah.winsmarts.com/2006/05/19/demystifying-c-30--part-4-lambda-expressions.aspx"&gt;this&lt;/a&gt; and then continue.&lt;/p&gt;
&lt;p&gt;So, here&amp;rsquo;s the delegate representation of the above function:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_262F8283.png"&gt;&lt;img title="Creating a delegate out of Linq Query" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Creating a delegate out of Linq Query" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_4F571AC1.png" border="0" height="114" width="573" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Couple of things to note here. I have declared the delegate as &lt;span style="text-decoration:underline;"&gt;static readonly&lt;/span&gt; because a compiled query is declared only once and reused by all threads. If you don&amp;rsquo;t declare Compiled Queries as static, then you don&amp;rsquo;t get the performance gain because compiling queries everytime when needed is even worse than regular Linq queries. &lt;/p&gt;
&lt;p&gt;Then there&amp;rsquo;s the complex &lt;span style="text-decoration:underline;"&gt;Func&amp;lt;DropthingsDataContext, string, Guid, IQueryable&amp;lt;aspnet_User&amp;gt;&amp;gt;&lt;/span&gt; thing. Basically the generic &lt;span style="text-decoration:underline;"&gt;Func&amp;lt;&amp;gt;&lt;/span&gt; is declared to have three parameters from the &lt;span style="text-decoration:underline;"&gt;GetQuery&lt;/span&gt; function and a return type of &lt;span style="text-decoration:underline;"&gt;IQueryable&amp;lt;aspnet_User&amp;gt;&lt;/span&gt;. Here the parameter types are specified so that the delegate is created strongly typed. &lt;span style="text-decoration:underline;"&gt;Func&amp;lt;&amp;gt;&lt;/span&gt; allows up to 4 parameters and 1 return type. &lt;/p&gt;
&lt;p&gt;Next comes the real business, compiling the query. Now that we have the query in delegate form, we can pass this to &lt;span style="text-decoration:underline;"&gt;CompiledQuery.Compile&lt;/span&gt; function which compiles the delegate and returns a handle to us. Instead of directly assigning the lambda expression to the func, we will pass the expression through the &lt;span style="text-decoration:underline;"&gt;CompiledQuery.Compile&lt;/span&gt; function.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_0D703573.png"&gt;&lt;img title="Converting a Linq Query to Compiled Query" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Converting a Linq Query to Compiled Query" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_093637E1.png" border="0" height="133" width="677" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s where head starts to spin. This is so hard to read and maintain. Bear with me. I just wrapped the lambda expression on the right side inside the &lt;span style="text-decoration:underline;"&gt;CompiledQuery.Compile&lt;/span&gt; function. Basically that&amp;rsquo;s the only change. Also, when you call &lt;span style="text-decoration:underline;"&gt;CompiledQuery.Compile&amp;lt;&amp;gt;&lt;/span&gt;, the generic types must match and be in exactly the same order as the &lt;span style="text-decoration:underline;"&gt;Func&amp;lt;&amp;gt;&lt;/span&gt; declaration.&lt;/p&gt;
&lt;p&gt;Fortunately, calling a compiled query is as simple as calling a function:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_42D8D1CB.png"&gt;&lt;img title="Running Compiled Query" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Running Compiled Query" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_3F773A23.png" border="0" height="89" width="716" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;There you have it, a lot faster Linq Query execution. The hard work of converting all your queries into Compiled Query pays off when you see the performance difference.&lt;/p&gt;
&lt;p&gt;Now, there are some challenges to Compiled Queries. Most common one is, what do you do when you have more than 4 parameters to supply to a Compiled Query? You can&amp;rsquo;t declare a &lt;span style="text-decoration:underline;"&gt;Func&amp;lt;&amp;gt;&lt;/span&gt; with more than 4 types. Solution is to use a &lt;span style="text-decoration:underline;"&gt;struct&lt;/span&gt; to encapsulate all the parameters. Here&amp;rsquo;s an example:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_2F87F55F.png"&gt;&lt;img title="Using struct in compiled query as parameter" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Using struct in compiled query as parameter" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_7CF4721F.png" border="0" height="245" width="736" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Calling the query is quite simple:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_7660F28F.png"&gt;&lt;img title="Calling compiled query with struct parameter" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Calling compiled query with struct parameter" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_575ACEF1.png" border="0" height="55" width="674" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now to the dreaded challenge of using &lt;span style="text-decoration:underline;"&gt;LoadOptions&lt;/span&gt; with Compiled Query. You will notice that the following code results in an exception:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_039755D6.png"&gt;&lt;img title="Using DataLoadOptions with Compiled Query" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Using DataLoadOptions with Compiled Query" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_2D4AAAFC.png" border="0" height="133" width="647" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The above &lt;span style="text-decoration:underline;"&gt;DataLoadOption&lt;/span&gt; runs perfectly when you use regular Linq Queries. But it does not work with compiled queries. When you run this code and the query hits the second time, it produces an exception:&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Compiled queries across DataContexts with different LoadOptions not supported&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;A compiled query remembers the &lt;span style="text-decoration:underline;"&gt;DataLoadOption&lt;/span&gt; once its called. It does not allow executing the same compiled query with a different &lt;span style="text-decoration:underline;"&gt;DataLoadOption&lt;/span&gt; again. Although you are creating the same &lt;span style="text-decoration:underline;"&gt;DataLoadOption&lt;/span&gt; with the same &lt;span style="text-decoration:underline;"&gt;LoadWith&amp;lt;&amp;gt;&lt;/span&gt; calls, it still produces exception because it remembers the exact instance that was used when the compiled query was called for the first time. Since next call creates a new instance of &lt;span style="text-decoration:underline;"&gt;DataLoadOptions&lt;/span&gt;, it does not match and the exception is thrown. You can read details about the problem in &lt;a title="Compiled Queries cannot take same DataLoadOption" href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2558764&amp;amp;SiteID=1"&gt;this forum post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The solution is to use a static &lt;span style="text-decoration:underline;"&gt;DataLoadOption&lt;/span&gt;. You cannot create a local &lt;span style="text-decoration:underline;"&gt;DataLoadOption&lt;/span&gt; instance and use in compiled queries. It needs to be &lt;span style="text-decoration:underline;"&gt;static&lt;/span&gt;. Here&amp;rsquo;s how you can do it:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_240E6FBB.png"&gt;&lt;img title="image" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_08F5A0AD.png" border="0" height="146" width="589" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Basically the idea is to construct a &lt;span style="text-decoration:underline;"&gt;static&lt;/span&gt; instance of &lt;span style="text-decoration:underline;"&gt;DataLoadOptions&lt;/span&gt; using a static function. As writing function for every single &lt;span style="text-decoration:underline;"&gt;DataLoadOptions&lt;/span&gt; combination is painful, I created a static delegate here and executed it right on the declaration line. This is in interesting way to declare a variable that requires more than one statement to prepare it. &lt;/p&gt;
&lt;p&gt;Using this option is very simple:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_4DC1C4E1.png"&gt;&lt;img title="image" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_4A602D39.png" border="0" height="73" width="670" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Now you can use &lt;span style="text-decoration:underline;"&gt;DataLoadOptions&lt;/span&gt; with compiled queries. &lt;/p&gt;
&lt;div class="wlWriterHeaderFooter" style="text-align:left;margin:0px;padding:4px 4px 4px 4px;"&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f10%2f27%2fsolving-common-problems-with-compiled-queries-in-linq-to-sql-for-high-demand-asp-net-websites.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f10%2f27%2fsolving-common-problems-with-compiled-queries-in-linq-to-sql-for-high-demand-asp-net-websites.aspx" alt="kick it on DotNetKicks.com" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1652150" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx">performance</category><category domain="http://msmvps.com/blogs/omar/archive/tags/linq/default.aspx">linq</category><category domain="http://msmvps.com/blogs/omar/archive/tags/.net/default.aspx">.net</category></item><item><title>Using multiple broadband connections without using any special router or software</title><link>http://msmvps.com/blogs/omar/archive/2008/10/05/using-multiple-broadband-connections-without-using-any-special-router-or-software.aspx</link><pubDate>Sun, 05 Oct 2008 10:29:18 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1649771</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=1649771</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/10/05/using-multiple-broadband-connections-without-using-any-special-router-or-software.aspx#comments</comments><description>&lt;p&gt;I have two broadband connections. One cheap connection, which I mostly use for browsing and downloading. Another very expensive connection that I use for voice chat, remote desktop connection etc. Now, using these two connections at the same time required two computers before. But I figured out a way to use both connections at the same time using the same computer. Here&amp;#39;s how:&lt;/p&gt; &lt;p&gt;Connect the cheap internet connection that is used mostly for non-critical purpose like downloading, browsing to a wireless router.&lt;/p&gt; &lt;p&gt;Connect the expensive connection that is used for network latency sensitive work like Voice Conference, Remote Desktop directly via LAN.&lt;/p&gt; &lt;p&gt;When you want to establish a critical connection like starting voice conf app (Skype) or remote desktop client, momentarily disconnect the wireless. This will make your LAN connection the only available internet. So, all the new connections will be established over the LAN. Now you can start Skype and initiate a voice conference or use Remote Desktop client and connect to a computer. The connection will be established over LAN.&lt;/p&gt; &lt;p&gt;Now turn on wireless. Wireless will now become the first preference for Windows to go to internet. So, now you can start Outlook, browser etc and they will be using the wireless internet connection. During this time, Skype and Terminal Client is still connected over the LAN connection. As they use persisted connection, they keep using the LAN connection and do not switch to the wireless. &lt;/p&gt; &lt;p&gt;This way you get to use two broadband connections simultaneously.&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Usingmultiplebroadbandconnectionswithout_5F00_E7D0/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="267" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Usingmultiplebroadbandconnectionswithout_5F00_E7D0/image_5F00_thumb.png" width="162" border="0" /&gt;&lt;/a&gt;&amp;nbsp; &lt;/p&gt; &lt;p&gt;Here you see I have data transfer going on through two different connection. The bottom one is the LAN which is maintaining a continuous voice data stream. The upper one is the wireless connection that sometimes consumes bandwidth when I browse.&lt;/p&gt; &lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Usingmultiplebroadbandconnectionswithout_5F00_E7D0/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="304" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar.Usingmultiplebroadbandconnectionswithout_5F00_E7D0/image_5F00_thumb_5F00_1.png" width="343" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Using Sysinternal&amp;#39;s TCPView, I can see some connection is going through LAN and some through Belkin router. The selected ones - the terminal client and the MSN Messenger is using LAN where the Internet Explorer and Outlook is working over Wireless connection. &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1649771" 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/ideas/default.aspx">ideas</category><category domain="http://msmvps.com/blogs/omar/archive/tags/misc/default.aspx">misc</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>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>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>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>10 ASP.NET Performance and Scalability Secrets</title><link>http://msmvps.com/blogs/omar/archive/2008/01/30/10-asp-net-performance-and-scalability-secrets.aspx</link><pubDate>Wed, 30 Jan 2008 15:47:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1486901</guid><dc:creator>omar</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1486901</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/01/30/10-asp-net-performance-and-scalability-secrets.aspx#comments</comments><description>&lt;p&gt;ASP.NET 2.0 has many secrets, when revealed, can give you big performance and
scalability boost. For instance, there are secret bottlenecks in Membership and Profile
provider which can be solved easily to make authentication and authorization faster.
Furthermore, ASP.NET Http pipeline can be tweaked to avoid executing unnecessary code
that gets hit on each and every request. Not only that, ASP.NET Worker Process can be
pushed to its limit to squeeze out every drop of performance out of it. Page fragment
output caching on the browser (not on the server) can save significant amount of download
time on repeated visits. On demand UI loading can give your site a fast and smooth
feeling. Finally, Content Delivery Networks (CDN) and proper use of HTTP Cache headers
can make your website screaming fast when implemented properly. In this article, you will
learn these techniques that can give your ASP.NET application a big performance and
scalability boost and prepare it to perform well under 10 times to 100 times more
traffic.&lt;/p&gt;
&lt;p&gt;
&lt;a title="http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx" href="http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx"&gt;http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;In this article I have shown the following techniques:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ASP.NET Pipeline optimization&lt;/li&gt;
&lt;li&gt;ASP.NET Process configuration optimization&lt;/li&gt;
&lt;li&gt;Things you must do for ASP.NET before going live&lt;/li&gt;
&lt;li&gt;Content Delivery Network&lt;/li&gt;
&lt;li&gt;Caching AJAX calls on browser&lt;/li&gt;
&lt;li&gt;Making best use of Browser Cache&lt;/li&gt;
&lt;li&gt;On demand progressive UI loading for fast smooth experience&lt;/li&gt;
&lt;li&gt;Optimize ASP.NET 2.0 Profile provider&lt;/li&gt;
&lt;li&gt;How to query ASP.NET 2.0 Membership tables without bringing down the site&lt;/li&gt;
&lt;li&gt;Prevent Denial of Service (DOS) attack&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The above techniques can be implemented on any ASP.NET website especially those who
use ASP.NET 2.0&amp;#39;s Membership and Profile provider.&lt;/p&gt;
&lt;p&gt;You can learn a lot more about performance and scalability improvement of ASP.NET and
ASP.NET AJAX websites from my book - 
&lt;a href="http://www.oreilly.com/catalog/9780596510503/"&gt;Building a Web 2.0 portal using
ASP.NET 3.5&lt;/a&gt;.&lt;/p&gt;
&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1486901" 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/ajax/default.aspx">ajax</category><category domain="http://msmvps.com/blogs/omar/archive/tags/.net/default.aspx">.net</category></item><item><title>Making best use of cache for high performance website</title><link>http://msmvps.com/blogs/omar/archive/2007/11/29/making-best-use-of-cache-for-high-performance-website.aspx</link><pubDate>Thu, 29 Nov 2007 16:21:36 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1369310</guid><dc:creator>omar</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1369310</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2007/11/29/making-best-use-of-cache-for-high-performance-website.aspx#comments</comments><description>&lt;h5&gt;&lt;strong&gt;Use URLs &lt;/strong&gt;&lt;strong&gt;consistently&lt;/strong&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/h5&gt; &lt;p&gt;Browsers cache content based on the URL. When URL changes, browser fetches a new version from origin server. URL can be changed by changing the query string parameters. For example, “/default.aspx” is cached on the browser. If you request “/default.aspx?123” it will fetch new content from server. Response from the new URL can also be cached in browser if you return proper caching headers. In that case, changing the query parameter to something else like “/default.aspx?456” will return new content from server. So, you need to make sure you use URL consistently everywhere when you want to get cached response. From homepage, if you have requested a file with URL “/welcome.gif”, make sure from another page you request the same file using the same URL. One common mistake is to sometimes omit the “www” subdomain from the url. &lt;a href="http://www.pageflakes.com/default.aspx"&gt;www.pageflakes.com/default.aspx&lt;/a&gt; is not same as &lt;a href="http://www.pageflakes.com/default.aspx"&gt;pageflakes.com/default.aspx&lt;/a&gt;. Both will be cached separately.  &lt;h5&gt;Cache static content for longer period&lt;/h5&gt; &lt;p&gt;Static files can be cached for longer period like one month. If you are thinking that you should cache for couple of days so that when you change the file, users will pick it up sooner, you’re mistaken. If you update a file which was cached by Expires header, new users will immediately get the new file while old users will see the old content until it expires on their browser. So, as long as you are using Expires header to cache static files, you should use as high value as possible.  &lt;p&gt;For example, if you have set expires header to cache a file for three days, one user will get the file today and store it in cache for next three days. Another user will get the file tomorrow and cache it for three days after tomorrow. If you change the file on the day after tomorrow, the first user will see it on fourth day and the second user will see it on fifth day. So, different users will see different versions of the file. As a result, it does not help setting a lower value assuming all users will pick up the latest file soon. You will have to change the url of the file in order to ensure everyone gets the exact same file immediately.  &lt;p&gt;You can setup Expires header from static files from IIS Manager. You’ll learn how to do it in later section.  &lt;h5&gt;&lt;strong&gt;Use cache friendly folder structure&lt;/strong&gt;&lt;/h5&gt; &lt;p&gt;Store cached content under a common folder. For example, store all images of your site under the “/static” folder instead of storing images separately under different subfolders. This will help you use consistent URL throughout the site because from anywhere you can use “/static/images/somefile.gif”. Later on, we will learn it’s easier to move to a Content Delivery Network when you have static cacheable files under a common root folder.  &lt;h5&gt;&lt;strong&gt;Reuse common graphics files&lt;/strong&gt;&lt;/h5&gt; &lt;p&gt;Sometimes we put common graphics files under several virtual directories so that we can write smaller paths. For example, say you have indicator.gif in root folder, some subfolders and under CSS folder. You did it because you need not worry about paths from different places and you could just use the file name as relative URL. This does not help in caching. Each copy of the file is cached in browser separately. So, you should collect all graphics files in the whole solution and put them under the same root “static” folder after eliminating duplicates and use the same URL from all the pages and CSS files.  &lt;h5&gt;&lt;strong&gt;Change file name when you want to expire cache&lt;/strong&gt;&lt;/h5&gt; &lt;p&gt;When you want a static file to be changed, don’t just update the file because it’s already cached in user’s browser. You need to change the file name and update all references everywhere so that browser downloads the new file. You can also store the file names in database or configuration files and use data binding to generate the URL dynamically. This way you can change the URL from one place and have the whole site receive the change immediately.  &lt;h5&gt;Use a version number while accessing static files&lt;/h5&gt; &lt;p&gt;If you do not want to clutter your static folder with multiple copies of the same file, you can use query string to differentiate versions of same file. For example, a GIF can be accessed with a dummy query string like “/static/images/indicator.gif?v=1”. When you change the indicator.gif, you can overwrite the same file and then update all references to the file to “/static/images/indicator.gif?v=2”. This way you can keep changing the same file again and again and just update the references to access the graphics using the new version number.  &lt;h5&gt;Store cacheable files in a different domain&lt;/h5&gt; &lt;p&gt;It’s always a good idea to put static contents in a different domain. First of all, browser can open another two concurrent connections to download the static files. Another benefit is that you don’t need to send the cookies to the static files. When you put the static files on the same domain as your web application, browser sends all the ASP.NET cookies and all other cookies that your web application is producing. This makes the request headers be unnecessarily large and waste bandwidth. You don’t need to send these cookies to access the static files. So, if you put the static files in a different domain, those cookies will not be sent. For example, put your static files in &lt;a href="http://www.staticcontent.com/"&gt;www.staticcontent.com&lt;/a&gt; domain while your website is running on &lt;a href="http://www.dropthings.com/"&gt;www.dropthings.com&lt;/a&gt;. The other domain does not need to be a completely different web site. It can just be an alias and share the same web application path.  &lt;h5&gt;&lt;strong&gt;SSL is not cached, so minimize SSL use&lt;/strong&gt;&lt;/h5&gt; &lt;p&gt;Any content that is served over SSL is not cached. So, you need to put static content outside SSL. Moreover, you should try limiting SSL to only secure pages like Login page or Payment page. Rest of the site should be outside SSL over regular HTTP. SSL encrypts request and response and thus puts extra load on server. Encrypted content is also larger than the original content and thus takes more bandwidth.  &lt;h5&gt;HTTP POST requests are never cached&lt;/h5&gt; &lt;p&gt;Cache only happens for HTTP GET requests. HTTP POST requests are never cached. So, any kind of AJAX call you want to make cacheable, it needs to be HTTP GET enabled.  &lt;h5&gt;Generate Content-Length response header&lt;/h5&gt; &lt;p&gt;When you are dynamically serving content via web service calls or HTTP handlers, make sure you emit &lt;u&gt;Content-Length&lt;/u&gt; header. Browsers have several optimizations for downloading contents faster when it knows how many bytes to download from the response by looking at the &lt;u&gt;Content-Length&lt;/u&gt; header. Browsers can use persisted connections more effectively when this header is present. This saves browser from opening a new connection for each request. When there’s no Content-Length header, browser doesn’t know how many bytes it’s going to receive from the server and thus keeps the connection open as long as it gets bytes delivered from the server until the connection closes. So, you miss the benefit of Persisted Connections that can greatly reduce download time of several small files like css, javascripts, and images.  &lt;h4&gt;How to configure static content caching in IIS&lt;/h4&gt; &lt;p&gt;In IIS Manager, Web site properties dialog box has “HTTP Headers” tab where you can define Expires header for all requests that IIS handles. There you can define whether to expire content immediately or expire after certain number of days or on a specific date. The second option (Expire after) uses sliding expiration, not absolute expiration. This is very useful because it works per request. Whenever someone requests a static file, IIS will calculate the expiration date based on the number of days/months from the Expire after.  &lt;p&gt;&lt;a href="http://omar.mvps.org/images/Makingbestuseofcacheforbestsiteperforman_15143/clip_image001.gif"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="458" alt="clip_image001" src="http://omar.mvps.org/images/Makingbestuseofcacheforbestsiteperforman_15143/clip_image001_thumb.gif" width="472" border="0" /&gt;&lt;/a&gt;  &lt;p&gt;For dynamic pages that are served by ASP.NET, a handler can modify the expires header and override IIS default setting.  &lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1369310" 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/production/default.aspx">production</category></item></channel></rss>