<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://msmvps.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5 : asp.net ajax</title><link>http://msmvps.com/blogs/omar/archive/tags/asp.net+ajax/default.aspx</link><description>Tags: asp.net ajax</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP2 (Build: 40407.4157)</generator><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>Request format is unrecognized for URL unexpectedly ending in /SomeWebServiceMethod</title><link>http://msmvps.com/blogs/omar/archive/2007/09/19/request-format-is-unrecognized-for-url-unexpectedly-ending-in-somewebservicemethod.aspx</link><pubDate>Wed, 19 Sep 2007 05:08:19 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1205419</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=1205419</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2007/09/19/request-format-is-unrecognized-for-url-unexpectedly-ending-in-somewebservicemethod.aspx#comments</comments><description>&lt;p&gt;At &lt;a href="http://www.pageflakes.com"&gt;Pageflakes&lt;/a&gt;, our webservers; event logs are being flooded with this error. In ASP.NET AJAX 1.0 version, Microsoft added a check for all web service calls to have &lt;u&gt;Content-Type: application/json&lt;/u&gt; in the request headers. Unless this request header is present, ASMX handler fires an exception. This exception is raised directly from the &lt;u&gt;ScriptHandler&lt;/u&gt; which handles all web service calls made via ASP.NET AJAX. &lt;/p&gt; &lt;p&gt;This is done for security reason. This prevents anyone from feeding off from your webservices. For example, you might have a webservice that returns some useful information that others might be interested to consume. So, any one could just add a &amp;lt;script&amp;gt; tag pointing to that web service URL and get the json. If that webservice is a very expensive webservice in terms of I/O and/or CPU, then other websites feeding off from your webservice could easily bog down your server.&lt;/p&gt; &lt;p&gt;Now, this back fires when you have HTTP GET supported webservice calls that produce response headers to cache the response. For example, you might have a webmethod that returns Stock Quotes. You have used response caching so that browser caches the response of that webmethod and repeated visit do not produce repeated calls to that I/O costly webservice. What will happen is proxy gateways or proxy servers will see that their client users are making this request frequently and it can be cached. So, they will make periodic calls to that webservice and try to precache them on behalf of their client users. However, during precache, they won&amp;#39;t send the &lt;u&gt;Content-Type: application/json&lt;/u&gt; header. That&amp;#39;s what I have seen for several proxy servers. As a result, it produces exception and you get your event log flooded with this exception.&lt;/p&gt; &lt;p&gt;The reason why MS might have not seen this or anyone else is because there&amp;#39;s no way to make HTTP GET response cacheable on browser from webservice calls unless you do the &lt;a href="http://msmvps.com/blogs/omar/archive/2006/08/02/106485.aspx"&gt;hack I mentioned in earlier blog post&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;However, one thing that puzzles me is we get this error so frequently and the request headers look so legitimate that I am not 100% sure whether it&amp;#39;s the proxies not producing the content-type header properly all the time. Somehow the error patterns look like an registered user is trying to use the site and failing. It is possible that some firewall might see this content-type as invalid content type and filter out the header. &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1205419" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net+ajax/default.aspx">asp.net ajax</category></item><item><title>ASP.NET Ajax Extender for multi-column widget drag &amp; drop</title><link>http://msmvps.com/blogs/omar/archive/2007/03/22/asp-net-ajax-extender-for-multi-column-widget-drag-drop.aspx</link><pubDate>Thu, 22 Mar 2007 20:03:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:702124</guid><dc:creator>omar</dc:creator><slash:comments>142</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=702124</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2007/03/22/asp-net-ajax-extender-for-multi-column-widget-drag-drop.aspx#comments</comments><description>&lt;p&gt;My open source Ajax Start Page 
&lt;a href="http://www.dropthings.com/"&gt;www.dropthings.com&lt;/a&gt; has an
ASP.NET Ajax Extender which provides multi-column drag &amp;amp; drop
for widgets. It allows reordering of widgets on the same column and
also drag &amp;amp; drop between column. It also supports client side
notification so that you can call web service and store the
position of the widgets behind the scene without (async)
postback.&lt;/p&gt;
&lt;p&gt;
&lt;img height="279" src="http://omar.mvps.org/images/ASP.NETAjaxExtenderformulticolumnwidgetd_12D5/image01.png" width="574" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;I first thought of going for a plain vanilla Javascript based
solution for drag &amp;amp; drop. It requires less code, less
architectural complexity and provides better speed. Another reason
was the high learning curve for making Extenders in proper way in
Asp.net Ajax given that there&amp;rsquo;s hardly any documentation
available on the web (during the time of writing this blog).
However, writing a proper extender which pushes Asp.net Ajax to the
limit is a very good way to learn under-the-hood secrets of Asp.net
Ajax framework itself. So, the two extenders I will introduce here
will tell you almost everything you need to know about Asp.net Ajax
Extenders.&lt;/p&gt;
&lt;p&gt;Ajax Control Toolkit comes with a 
&lt;code&gt;DragPanel&lt;/code&gt; extender which I could use to provide drag
&amp;amp; drop support to panels. It also has a ReorderList control
which I could use to provide reordering of items in a single list.
Widgets are basically panels that flow vertically in each column.
So, it might be possible that I could create reorder list in each
column and use the 
&lt;code&gt;DragPanel&lt;/code&gt; to drag the widgets. But I could not use 
&lt;code&gt;ReorderList&lt;/code&gt; because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ReorderList&lt;/code&gt; strictly uses Html Table to render its
items in a column. I have no table inside the columns. Only one
Panel is there inside an UpdatePanel.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ReorderList&lt;/code&gt; takes a Drag Handle template and creates a
drag handle for each item at runtime. I already have drag handle
created inside a Widget which is the widget header. So, I cannot
allow 
&lt;code&gt;ReorderList&lt;/code&gt; to create another drag handle.&lt;/li&gt;
&lt;li&gt;I need client side callback on drag &amp;amp; drop so that I can
make Ajax calls and persist the widget positions. The callback must
give me the Panel where the widget is dropped, which is dropped and
at what position.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Next challenge is with the DragPanel extender. The default
implement of Drag &amp;amp; Drop in Ajax Control Toolkit has some
problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When you start dragging, the item becomes absolutely
positioned, but when you drop it, it does not become static
positioned. There&amp;#39;s a small hack needed for restoring the original
position to &amp;quot;static&amp;quot;.&lt;/li&gt;
&lt;li&gt;It does not put the dragging item on top of all items. As a
result, when you start dragging, you see the item being dragged
below other items which makes the drag get stuck especially when
there&amp;#39;s an IFRAME.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, I have made a 
&lt;code&gt;CustomDragDropExtender&lt;/code&gt; and a 
&lt;code&gt;CustomFloatingExtender&lt;/code&gt;. 
&lt;code&gt;CustomDragDropExtender&lt;/code&gt; is for the column containers
where widgets are placed. It provides the reordering support. You
can attach this extender to any Panel control.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s how you can attach this extender to any 
&lt;code&gt;Panel&lt;/code&gt; and make that 
&lt;code&gt;Panel&lt;/code&gt; support drag &amp;amp; drop of
Widgets:&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; 
&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;
&lt;span class="html"&gt;asp:Panel&lt;/span&gt; 
&lt;span class="attr"&gt;ID&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;LeftPanel&amp;quot;&lt;/span&gt; 
&lt;span class="attr"&gt;runat&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt;  
&lt;span class="attr"&gt;class&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;widget_holder&amp;quot;&lt;/span&gt; 
&lt;span class="attr"&gt;columnNo&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;0&amp;quot;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;         
&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;
&lt;span class="html"&gt;div&lt;/span&gt; 
&lt;span class="attr"&gt;id&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;DropCue1&amp;quot;&lt;/span&gt; 
&lt;span class="attr"&gt;class&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;widget_dropcue&amp;quot;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt;         
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;
&lt;span class="html"&gt;div&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt; 
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;
&lt;span class="html"&gt;asp:Panel&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&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;&amp;lt;&lt;/span&gt;
&lt;span class="html"&gt;cdd:CustomDragDropExtender&lt;/span&gt; 
&lt;span class="attr"&gt;ID&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;CustomDragDropExtender1&amp;quot;&lt;/span&gt; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   7:&lt;/span&gt;     
&lt;span class="attr"&gt;runat&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; 
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   8:&lt;/span&gt;     
&lt;span class="attr"&gt;TargetControlID&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;LeftPanel&amp;quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   9:&lt;/span&gt;     
&lt;span class="attr"&gt;DragItemClass&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;widget&amp;quot;&lt;/span&gt; 
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  10:&lt;/span&gt;     
&lt;span class="attr"&gt;DragItemHandleClass&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;widget_header&amp;quot;&lt;/span&gt; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  11:&lt;/span&gt;     
&lt;span class="attr"&gt;DropCueID&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;DropCue1&amp;quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  12:&lt;/span&gt;     
&lt;span class="attr"&gt;OnClientDrop&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;onDrop&amp;quot;&lt;/span&gt; 
&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;code&gt;&amp;lt;cdd:CustomDragDropExtender&amp;gt;&lt;/code&gt; offers the
following properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TargetControlID &amp;ndash; ID of the Panel which becomes the Drop
zone&lt;/li&gt;
&lt;li&gt;DragItemClass &amp;ndash; All child elements inside the Panel
having this class will become draggable. E.g. Widget DIV has this
class so that it can become draggable.&lt;/li&gt;
&lt;li&gt;DragItemHandleClass &amp;ndash; Any child element having this class
inside the draggable elements will become the drag handle for the
draggable element. E.g. Widget Header area has this class, so it
acts as the drag handle for the Widget.&lt;/li&gt;
&lt;li&gt;DropCueID &amp;ndash; ID of an element inside the Panel which acts
as Drop Cue.&lt;/li&gt;
&lt;li&gt;OnClientDrop &amp;ndash; Name of a Javascript function which is
called when widget is dropped on the Panel.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;LeftPanel becomes a widget container which allows widgets to be
dropped on it and reordered. The DragItemClass attribute on the
extender defines the items which can be ordered. This prevents from
non-widget Html Divs from getting ordered. Only the DIVs with the
class &amp;quot;widget&amp;quot; are ordered. Say there are 5 DIVs with the class
named &amp;quot;widget&amp;quot;. It will allow reordering of only these five
divs:&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; 
&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;
&lt;span class="html"&gt;div&lt;/span&gt; 
&lt;span class="attr"&gt;id&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;LeftPanel&amp;quot;&lt;/span&gt; 
&lt;span class="attr"&gt;class&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;widget_holder&amp;quot;&lt;/span&gt; 
&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;         
&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;
&lt;span class="html"&gt;div&lt;/span&gt; 
&lt;span class="attr"&gt;class&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;widget&amp;quot;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; ... 
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;
&lt;span class="html"&gt;div&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt;         
&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;
&lt;span class="html"&gt;div&lt;/span&gt; 
&lt;span class="attr"&gt;class&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;widget&amp;quot;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; ... 
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;
&lt;span class="html"&gt;div&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt;  
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt;         
&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;
&lt;span class="html"&gt;div&lt;/span&gt; 
&lt;span class="attr"&gt;class&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;widget&amp;quot;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; ... 
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;
&lt;span class="html"&gt;div&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt;         
&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;
&lt;span class="html"&gt;div&lt;/span&gt; 
&lt;span class="attr"&gt;class&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;widget&amp;quot;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; ... 
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;
&lt;span class="html"&gt;div&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   7:&lt;/span&gt;         
&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;
&lt;span class="html"&gt;div&lt;/span&gt; 
&lt;span class="attr"&gt;class&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;widget&amp;quot;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; ... 
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;
&lt;span class="html"&gt;div&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   8:&lt;/span&gt;  
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   9:&lt;/span&gt;         
&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;
&lt;span class="html"&gt;div&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;This DIV will not move
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;
&lt;span class="html"&gt;div&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  10:&lt;/span&gt;         
&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;
&lt;span class="html"&gt;div&lt;/span&gt; 
&lt;span class="attr"&gt;id&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;DropCue1&amp;quot;&lt;/span&gt; 
&lt;span class="attr"&gt;class&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;widget_dropcue&amp;quot;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;
&lt;span class="html"&gt;div&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  11:&lt;/span&gt; 
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;
&lt;span class="html"&gt;div&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;When a widget is dropped on the panel, the extender fires the
function specified in 
&lt;code&gt;OnClientDrop&lt;/code&gt;. It offers standard Ajax Events. But
unlike basic Ajax events where you have to programmatically bind to
events, you can define property and specify the function name to
call. So, instead of doing this:&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; 
&lt;span class="kwrd"&gt;function&lt;/span&gt; pageLoad( sender, e ) {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;  
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt;   
&lt;span class="kwrd"&gt;var&lt;/span&gt; extender1 =
$get(&amp;lsquo;CustomDragDropExtender1&amp;rsquo;);
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt;   extender1.add_onDrop( onDrop );
&lt;/pre&gt;
&lt;pre class="alt"&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;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can do this:&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; 
&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;
&lt;span class="html"&gt;cdd:CustomDragDropExtender&lt;/span&gt; 
&lt;span class="attr"&gt;ID&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;CustomDragDropExtender1&amp;quot;&lt;/span&gt; 
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;     
&lt;span class="attr"&gt;runat&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt;     
&lt;span class="attr"&gt;OnClientDrop&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;onDrop&amp;quot;&lt;/span&gt; 
&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;When the event is raised, the function named 
&lt;code&gt;onDrop&lt;/code&gt; gets fired. This is done with the help of some
handy library available in ACT project.&lt;/p&gt;
&lt;p&gt;When the event is fired, it sends the container, the widget and
the position of the widget where the widget is dropped.&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; 
&lt;span class="kwrd"&gt;function&lt;/span&gt; onDrop( sender, e )
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt; {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt;     
&lt;span class="kwrd"&gt;var&lt;/span&gt; container = e.get_container();
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt;     
&lt;span class="kwrd"&gt;var&lt;/span&gt; item = e.get_droppedItem();
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt;     
&lt;span class="kwrd"&gt;var&lt;/span&gt; position = e.get_position();
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt;     
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   7:&lt;/span&gt;     
&lt;span class="rem"&gt;//alert( String.format( &amp;quot;Container: {0}, Item:
{1}, Position: {2}&amp;quot;, container.id, item.id, position ) );&lt;/span&gt;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   8:&lt;/span&gt;     
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   9:&lt;/span&gt;     
&lt;span class="kwrd"&gt;var&lt;/span&gt; instanceId =
parseInt(item.getAttribute(
&lt;span class="str"&gt;&amp;quot;InstanceId&amp;quot;&lt;/span&gt;));
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  10:&lt;/span&gt;     
&lt;span class="kwrd"&gt;var&lt;/span&gt; columnNo =
parseInt(container.getAttribute(
&lt;span class="str"&gt;&amp;quot;columnNo&amp;quot;&lt;/span&gt;));
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  11:&lt;/span&gt;     
&lt;span class="kwrd"&gt;var&lt;/span&gt; row = position;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  12:&lt;/span&gt;     
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  13:&lt;/span&gt;    
WidgetService.MoveWidgetInstance( instanceId, columnNo, row );
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  14:&lt;/span&gt; }
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The widget location is updated by calling the 
&lt;code&gt;WidgetService.MoveWidgetInstance&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;CustomDragDropExtender&lt;/code&gt; has 3 files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CustomDragDropExtender.cs &amp;ndash; The server side extender
implementation&lt;/li&gt;
&lt;li&gt;CustomDragDropDesigner.cs &amp;ndash; Designer class for the
extender&lt;/li&gt;
&lt;li&gt;CustomDragDropExtender.js &amp;ndash; Client side scriptfor the
extender&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Server side class CustomDragDropExtender.cs has the following
code:&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; [assembly:
System.Web.UI.WebResource(
&lt;span class="str"&gt;&amp;quot;CustomDragDrop.CustomDragDropBehavior.js&amp;quot;&lt;/span&gt;,

&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;)]
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;  
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt; 
&lt;span class="kwrd"&gt;namespace&lt;/span&gt; CustomDragDrop
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt; {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt;     [Designer(
&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(CustomDragDropDesigner))]
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt;     [ClientScriptResource(
&lt;span class="str"&gt;&amp;quot;CustomDragDrop.CustomDragDropBehavior&amp;quot;&lt;/span&gt;, 
&lt;span class="str"&gt;&amp;quot;CustomDragDrop.CustomDragDropBehavior.js&amp;quot;&lt;/span&gt;)]
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   7:&lt;/span&gt;     [TargetControlType(
&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(WebControl))]
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   8:&lt;/span&gt;     [RequiredScript(
&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(CustomFloatingBehaviorScript))]
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   9:&lt;/span&gt;     [RequiredScript(
&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(DragDropScripts))]
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  10:&lt;/span&gt;     
&lt;span class="kwrd"&gt;public&lt;/span&gt; 
&lt;span class="kwrd"&gt;class&lt;/span&gt; CustomDragDropExtender :
ExtenderControlBase
&lt;/pre&gt;
&lt;pre class="alt"&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="rem"&gt;// TODO: Add your property accessors here.&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  13:&lt;/span&gt;         
&lt;span class="rem"&gt;//&lt;/span&gt;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  14:&lt;/span&gt;         [ExtenderControlProperty]
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  15:&lt;/span&gt;         
&lt;span class="kwrd"&gt;public&lt;/span&gt; 
&lt;span class="kwrd"&gt;string&lt;/span&gt; DragItemClass
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  16:&lt;/span&gt;         {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  17:&lt;/span&gt;             get
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  18:&lt;/span&gt;             {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  19:&lt;/span&gt;                 
&lt;span class="kwrd"&gt;return&lt;/span&gt; GetPropertyValue&amp;lt;String&amp;gt;(
&lt;span class="str"&gt;&amp;quot;DragItemClass&amp;quot;&lt;/span&gt;, 
&lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty);
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  20:&lt;/span&gt;             }
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  21:&lt;/span&gt;             set
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  22:&lt;/span&gt;             {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  23:&lt;/span&gt;                
SetPropertyValue&amp;lt;String&amp;gt;(
&lt;span class="str"&gt;&amp;quot;DragItemClass&amp;quot;&lt;/span&gt;, 
&lt;span class="kwrd"&gt;value&lt;/span&gt;);
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  24:&lt;/span&gt;             }
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  25:&lt;/span&gt;         }
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  26:&lt;/span&gt;  
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  27:&lt;/span&gt;         [ExtenderControlProperty]
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  28:&lt;/span&gt;         
&lt;span class="kwrd"&gt;public&lt;/span&gt; 
&lt;span class="kwrd"&gt;string&lt;/span&gt; DragItemHandleClass
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  29:&lt;/span&gt;         {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  30:&lt;/span&gt;             get
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  31:&lt;/span&gt;             {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  32:&lt;/span&gt;                 
&lt;span class="kwrd"&gt;return&lt;/span&gt; GetPropertyValue&amp;lt;String&amp;gt;(
&lt;span class="str"&gt;&amp;quot;DragItemHandleClass&amp;quot;&lt;/span&gt;, 
&lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty);
&lt;/pre&gt;
&lt;pre class="alt"&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;             set
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  35:&lt;/span&gt;             {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  36:&lt;/span&gt;                
SetPropertyValue&amp;lt;String&amp;gt;(
&lt;span class="str"&gt;&amp;quot;DragItemHandleClass&amp;quot;&lt;/span&gt;, 
&lt;span class="kwrd"&gt;value&lt;/span&gt;);
&lt;/pre&gt;
&lt;pre class="alt"&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;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  39:&lt;/span&gt;  
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  40:&lt;/span&gt;         [ExtenderControlProperty]
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  41:&lt;/span&gt;         [IDReferenceProperty(
&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(WebControl))]
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  42:&lt;/span&gt;         
&lt;span class="kwrd"&gt;public&lt;/span&gt; 
&lt;span class="kwrd"&gt;string&lt;/span&gt; DropCueID
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  43:&lt;/span&gt;         {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  44:&lt;/span&gt;             get
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  45:&lt;/span&gt;             {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  46:&lt;/span&gt;                 
&lt;span class="kwrd"&gt;return&lt;/span&gt; GetPropertyValue&amp;lt;String&amp;gt;(
&lt;span class="str"&gt;&amp;quot;DropCueID&amp;quot;&lt;/span&gt;, 
&lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty);
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  47:&lt;/span&gt;             }
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  48:&lt;/span&gt;             set
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  49:&lt;/span&gt;             {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  50:&lt;/span&gt;                
SetPropertyValue&amp;lt;String&amp;gt;(
&lt;span class="str"&gt;&amp;quot;DropCueID&amp;quot;&lt;/span&gt;, 
&lt;span class="kwrd"&gt;value&lt;/span&gt;);
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  51:&lt;/span&gt;             }
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  52:&lt;/span&gt;         }
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  53:&lt;/span&gt;  
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  54:&lt;/span&gt;         [ExtenderControlProperty()]
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  55:&lt;/span&gt;         [DefaultValue(
&lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;)]
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  56:&lt;/span&gt;         [ClientPropertyName(
&lt;span class="str"&gt;&amp;quot;onDrop&amp;quot;&lt;/span&gt;)]
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  57:&lt;/span&gt;         
&lt;span class="kwrd"&gt;public&lt;/span&gt; 
&lt;span class="kwrd"&gt;string&lt;/span&gt; OnClientDrop
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  58:&lt;/span&gt;         {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  59:&lt;/span&gt;             get
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  60:&lt;/span&gt;             {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  61:&lt;/span&gt;                 
&lt;span class="kwrd"&gt;return&lt;/span&gt; GetPropertyValue&amp;lt;String&amp;gt;(
&lt;span class="str"&gt;&amp;quot;OnClientDrop&amp;quot;&lt;/span&gt;, 
&lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty);
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  62:&lt;/span&gt;             }
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  63:&lt;/span&gt;             set
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  64:&lt;/span&gt;             {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  65:&lt;/span&gt;                
SetPropertyValue&amp;lt;String&amp;gt;(
&lt;span class="str"&gt;&amp;quot;OnClientDrop&amp;quot;&lt;/span&gt;, 
&lt;span class="kwrd"&gt;value&lt;/span&gt;);
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  66:&lt;/span&gt;             }
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  67:&lt;/span&gt;         }
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  68:&lt;/span&gt;  
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  69:&lt;/span&gt;     }
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  70:&lt;/span&gt; }
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Most of the code in the extender defines the property. The
important part is the declaration of the class:&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; [assembly:
System.Web.UI.WebResource(
&lt;span class="str"&gt;&amp;quot;CustomDragDrop.CustomDragDropBehavior.js&amp;quot;&lt;/span&gt;,

&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;)]
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;  
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt; 
&lt;span class="kwrd"&gt;namespace&lt;/span&gt; CustomDragDrop
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt; {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt;     [Designer(
&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(CustomDragDropDesigner))]
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt;     [ClientScriptResource(
&lt;span class="str"&gt;&amp;quot;CustomDragDrop.CustomDragDropBehavior&amp;quot;&lt;/span&gt;, 
&lt;span class="str"&gt;&amp;quot;CustomDragDrop.CustomDragDropBehavior.js&amp;quot;&lt;/span&gt;)]
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   7:&lt;/span&gt;     [TargetControlType(
&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(WebControl))]
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   8:&lt;/span&gt;     [RequiredScript(
&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(CustomFloatingBehaviorScript))]
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   9:&lt;/span&gt;     [RequiredScript(
&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(DragDropScripts))]
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  10:&lt;/span&gt;     
&lt;span class="kwrd"&gt;public&lt;/span&gt; 
&lt;span class="kwrd"&gt;class&lt;/span&gt; CustomDragDropExtender :
ExtenderControlBase
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  11:&lt;/span&gt;     {
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The extender class inherits from 
&lt;code&gt;ExtenderControlBase&lt;/code&gt; defined in ACT project. This base
class has additional features over Ajax runtime provided Extender
base class. It allows you to define 
&lt;code&gt;RequiredScript&lt;/code&gt; attribute, which makes sure all the
required scripts are downloaded before the extender script is
downloaded and initialized. This extender has dependency over
another extender named 
&lt;code&gt;CustomFloatingBehavior&lt;/code&gt;. It also depends on ACT&amp;rsquo;s

&lt;code&gt;DragDropManager&lt;/code&gt;. So, the 
&lt;code&gt;RequiredScript&lt;/code&gt; attribute makes sure those are
downloaded before this extender&amp;rsquo;s script is downloaded. The 
&lt;code&gt;ExtenderControlBase&lt;/code&gt; is a pretty big class and does a
lot of work for us. It contains default implementations for
discovering all the script files for the extender and rendering
them properly.&lt;/p&gt;
&lt;p&gt;The 
&lt;code&gt;[assembly:System.Web.UI.WebResource]&lt;/code&gt; attribute defines
the script file containing the script for extender. The script file
is an embedded resource file.&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;[ClientScriptResource]&lt;/code&gt; attribute defines the scripts
required for the extender. This class is also defined in ACT.
ExtenderControlBase uses this attribute to find out which .js files
are working for the extender and renders them properly.&lt;/p&gt;
&lt;p&gt;The challenge is to make the client side javascript for the
extender. On the js file, there&amp;rsquo;s a Javascript pseudo
class:&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; Type.registerNamespace(
&lt;span class="str"&gt;&amp;#39;CustomDragDrop&amp;#39;&lt;/span&gt;);
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;  
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt;
CustomDragDrop.CustomDragDropBehavior = 
&lt;span class="kwrd"&gt;function&lt;/span&gt;(element) {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt;  
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt;    
CustomDragDrop.CustomDragDropBehavior.initializeBase(
&lt;span class="kwrd"&gt;this&lt;/span&gt;, [element]);
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt;     
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   7:&lt;/span&gt;     
&lt;span class="kwrd"&gt;this&lt;/span&gt;._DragItemClassValue = 
&lt;span class="kwrd"&gt;null&lt;/span&gt;;    
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   8:&lt;/span&gt;     
&lt;span class="kwrd"&gt;this&lt;/span&gt;._DragItemHandleClassValue = 
&lt;span class="kwrd"&gt;null&lt;/span&gt;;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   9:&lt;/span&gt;     
&lt;span class="kwrd"&gt;this&lt;/span&gt;._DropCueIDValue = 
&lt;span class="kwrd"&gt;null&lt;/span&gt;;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  10:&lt;/span&gt;     
&lt;span class="kwrd"&gt;this&lt;/span&gt;._dropCue = 
&lt;span class="kwrd"&gt;null&lt;/span&gt;;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  11:&lt;/span&gt;     
&lt;span class="kwrd"&gt;this&lt;/span&gt;._floatingBehaviors = [];
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  12:&lt;/span&gt; }
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;During initialize, it hooks on the Panel it is attached to and
the drop cue to show while drag &amp;amp; drop is going on over the
Panel:&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt;
CustomDragDrop.CustomDragDropBehavior.prototype = {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;     
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt;     initialize : 
&lt;span class="kwrd"&gt;function&lt;/span&gt;() {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt;         
&lt;span class="rem"&gt;// Register ourselves as a drop target.&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt;        
AjaxControlToolkit.DragDropManager.registerDropTarget(
&lt;span class="kwrd"&gt;this&lt;/span&gt;); 
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt;         
&lt;span class="rem"&gt;//Sys.Preview.UI.DragDropManager.registerDropTarget(this);&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&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;         
&lt;span class="rem"&gt;// Initialize drag behavior after a while&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   9:&lt;/span&gt;         window.setTimeout(
Function.createDelegate( 
&lt;span class="kwrd"&gt;this&lt;/span&gt;, 
&lt;span class="kwrd"&gt;this&lt;/span&gt;._initializeDraggableItems ), 3000 );
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  10:&lt;/span&gt;         
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  11:&lt;/span&gt;         
&lt;span class="kwrd"&gt;this&lt;/span&gt;._dropCue = $get(
&lt;span class="kwrd"&gt;this&lt;/span&gt;.get_DropCueID());
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  12:&lt;/span&gt;     },
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;After initializing the DragDropManager and marking the Panel as
a drop target, it starts a timer to discover the dragable items
inside the panel and create Floating behavior for them. Floating
behavior is the one which makes a DIV draggable.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;FloatingBehavior makes one DIV freely draggable on the page. But
it does not offer drop functionality. DragDropBehavior offers the
drop functionality which allows a freely moving DIV to rest on a
fixed position.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Discovering and initializing floating behavior for the dragable
items is the challenging work:&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; 
&lt;span class="rem"&gt;// Find all items with the drag item class and
make each item&lt;/span&gt;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt; 
&lt;span class="rem"&gt;// draggable        &lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt; _initializeDraggableItems : 
&lt;span class="kwrd"&gt;function&lt;/span&gt;() 
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt; {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt;     
&lt;span class="kwrd"&gt;this&lt;/span&gt;._clearFloatingBehaviors();
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt;     
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   7:&lt;/span&gt;     
&lt;span class="kwrd"&gt;var&lt;/span&gt; el = 
&lt;span class="kwrd"&gt;this&lt;/span&gt;.get_element();
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   8:&lt;/span&gt;     
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   9:&lt;/span&gt;     
&lt;span class="kwrd"&gt;var&lt;/span&gt; child = el.firstChild;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  10:&lt;/span&gt;     
&lt;span class="kwrd"&gt;while&lt;/span&gt;( child != 
&lt;span class="kwrd"&gt;null&lt;/span&gt; )
&lt;/pre&gt;
&lt;pre class="alt"&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;if&lt;/span&gt;( child.className == 
&lt;span class="kwrd"&gt;this&lt;/span&gt;._DragItemClassValue &amp;amp;&amp;amp; child
!= 
&lt;span class="kwrd"&gt;this&lt;/span&gt;._dropCue)
&lt;/pre&gt;
&lt;pre class="alt"&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;var&lt;/span&gt; handle = 
&lt;span class="kwrd"&gt;this&lt;/span&gt;._findChildByClass(child, 
&lt;span class="kwrd"&gt;this&lt;/span&gt;._DragItemHandleClassValue);
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  15:&lt;/span&gt;             
&lt;span class="kwrd"&gt;if&lt;/span&gt;( handle )
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  16:&lt;/span&gt;             {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  17:&lt;/span&gt;                 
&lt;span class="kwrd"&gt;var&lt;/span&gt; handleId = handle.id;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  18:&lt;/span&gt;                 
&lt;span class="kwrd"&gt;var&lt;/span&gt; behaviorId = child.id + 
&lt;span class="str"&gt;&amp;quot;_WidgetFloatingBehavior&amp;quot;&lt;/span&gt;;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  19:&lt;/span&gt;                 
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  20:&lt;/span&gt;                 
&lt;span class="rem"&gt;// make the item draggable by adding floating
behaviour to it                    &lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  21:&lt;/span&gt;                 
&lt;span class="kwrd"&gt;var&lt;/span&gt; floatingBehavior =
$create(CustomDragDrop.CustomFloatingBehavior, 
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  22:&lt;/span&gt;                         {
&lt;span class="str"&gt;&amp;quot;DragHandleID&amp;quot;&lt;/span&gt;:handleId, 
&lt;span class="str"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;:behaviorId, 
&lt;span class="str"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;: behaviorId}, {}, {}, child);
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  23:&lt;/span&gt;                 
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  24:&lt;/span&gt;                 Array.add( 
&lt;span class="kwrd"&gt;this&lt;/span&gt;._floatingBehaviors, floatingBehavior
);
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  25:&lt;/span&gt;             }
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  26:&lt;/span&gt;         }            
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  27:&lt;/span&gt;         child = child.nextSibling;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  28:&lt;/span&gt;     }
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  29:&lt;/span&gt; },
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here&amp;rsquo;s the algorithm:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run through all immediate child elements of the control where
the extender is attached to&lt;/li&gt;
&lt;li&gt;If the child item has the class for draggable item, then:
&lt;ul&gt;
&lt;li&gt;Find any element under the child item which has the class for
Drag handle&lt;/li&gt;
&lt;li&gt;If such item found, then attach a CustomFloatingBehavior with
the child item&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The 
&lt;code&gt;_findChildByClass&lt;/code&gt; function recursively iterates
through all the child elements and looks for an element which has
the defined class. It&amp;rsquo;s an expensive function. So, it is
important that the drag handle is very close to the dragable
element.&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; _findChildByClass : 
&lt;span class="kwrd"&gt;function&lt;/span&gt;(item, className)
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt; {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt;     
&lt;span class="rem"&gt;// First check all immediate child items&lt;/span&gt;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt;     
&lt;span class="kwrd"&gt;var&lt;/span&gt; child = item.firstChild;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt;     
&lt;span class="kwrd"&gt;while&lt;/span&gt;( child != 
&lt;span class="kwrd"&gt;null&lt;/span&gt; )
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt;     {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   7:&lt;/span&gt;         
&lt;span class="kwrd"&gt;if&lt;/span&gt;( child.className == className ) 
&lt;span class="kwrd"&gt;return&lt;/span&gt; child;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   8:&lt;/span&gt;         child = child.nextSibling;
&lt;/pre&gt;
&lt;pre class="alt"&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;pre class="alt"&gt;
&lt;span class="lnum"&gt;  11:&lt;/span&gt;     
&lt;span class="rem"&gt;// Not found, recursively check all child
items&lt;/span&gt;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  12:&lt;/span&gt;     child = item.firstChild;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  13:&lt;/span&gt;     
&lt;span class="kwrd"&gt;while&lt;/span&gt;( child != 
&lt;span class="kwrd"&gt;null&lt;/span&gt; )
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  14:&lt;/span&gt;     {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  15:&lt;/span&gt;         
&lt;span class="kwrd"&gt;var&lt;/span&gt; found = 
&lt;span class="kwrd"&gt;this&lt;/span&gt;._findChildByClass( child, className
);
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  16:&lt;/span&gt;         
&lt;span class="kwrd"&gt;if&lt;/span&gt;( found != 
&lt;span class="kwrd"&gt;null&lt;/span&gt; ) 
&lt;span class="kwrd"&gt;return&lt;/span&gt; found;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  17:&lt;/span&gt;         child = child.nextSibling;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  18:&lt;/span&gt;     }
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  19:&lt;/span&gt; },
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;When user drags an item over the Panel where the extender is
attached to, 
&lt;code&gt;DragDropManager&lt;/code&gt; fires the following events:&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; onDragEnterTarget : 
&lt;span class="kwrd"&gt;function&lt;/span&gt;(dragMode, type, data) {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;     
&lt;span class="kwrd"&gt;this&lt;/span&gt;._showDropCue(data);    
&lt;/pre&gt;
&lt;pre class="alt"&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;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt; onDragLeaveTarget : 
&lt;span class="kwrd"&gt;function&lt;/span&gt;(dragMode, type, data) {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt;     
&lt;span class="kwrd"&gt;this&lt;/span&gt;._hideDropCue(data);
&lt;/pre&gt;
&lt;pre class="alt"&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;  
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   9:&lt;/span&gt; onDragInTarget : 
&lt;span class="kwrd"&gt;function&lt;/span&gt;(dragMode, type, data) {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  10:&lt;/span&gt;     
&lt;span class="kwrd"&gt;this&lt;/span&gt;._repositionDropCue(data);
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  11:&lt;/span&gt; },
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here we deal with the drop cue. The challenging work is to find
out the right position for the drop cue.&lt;/p&gt;
&lt;p&gt;
&lt;img height="470" src="http://omar.mvps.org/images/ASP.NETAjaxExtenderformulticolumnwidgetd_12D5/image08.png" width="524" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;We need to find out where we should show the drop cue based on
where user is dragging the item. The idea is to find out the widget
which is immediately below the dragged item. The item is pushed
down by one position and the drop cue takes its place. While
dragging, the position of the drag item can be found easily. Based
on that, I locate the widget below the drag item:&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; _findItemAt : 
&lt;span class="kwrd"&gt;function&lt;/span&gt;(x,y, item)
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;     {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt;         
&lt;span class="kwrd"&gt;var&lt;/span&gt; el = 
&lt;span class="kwrd"&gt;this&lt;/span&gt;.get_element();
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt;         
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt;         
&lt;span class="kwrd"&gt;var&lt;/span&gt; child = el.firstChild;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt;         
&lt;span class="kwrd"&gt;while&lt;/span&gt;( child != 
&lt;span class="kwrd"&gt;null&lt;/span&gt; )
&lt;/pre&gt;
&lt;pre class="alt"&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;             
&lt;span class="kwrd"&gt;if&lt;/span&gt;( child.className == 
&lt;span class="kwrd"&gt;this&lt;/span&gt;._DragItemClassValue &amp;amp;&amp;amp; child
!= 
&lt;span class="kwrd"&gt;this&lt;/span&gt;._dropCue &amp;amp;&amp;amp; child != item )
&lt;/pre&gt;
&lt;pre class="alt"&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;var&lt;/span&gt; pos =
Sys.UI.DomElement.getLocation(child);
&lt;/pre&gt;
&lt;pre class="alt"&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;if&lt;/span&gt;( y &amp;lt;= pos.y )
&lt;/pre&gt;
&lt;pre class="alt"&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;return&lt;/span&gt; child;
&lt;/pre&gt;
&lt;pre class="alt"&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;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  17:&lt;/span&gt;             child =
child.nextSibling;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  18:&lt;/span&gt;         }
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  19:&lt;/span&gt;         
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  20:&lt;/span&gt;         
&lt;span class="kwrd"&gt;return&lt;/span&gt; 
&lt;span class="kwrd"&gt;null&lt;/span&gt;;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  21:&lt;/span&gt;     },
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This function returns the widget which is immediately under the
dragged item. Now I add the drop cue immediately above the
widget:&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; _repositionDropCue : 
&lt;span class="kwrd"&gt;function&lt;/span&gt;(data)
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;     {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt;         
&lt;span class="kwrd"&gt;var&lt;/span&gt; location =
Sys.UI.DomElement.getLocation(data.item);
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt;         
&lt;span class="kwrd"&gt;var&lt;/span&gt; nearestChild = 
&lt;span class="kwrd"&gt;this&lt;/span&gt;._findItemAt(location.x, location.y,
data.item);
&lt;/pre&gt;
&lt;pre class="alt"&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;var&lt;/span&gt; el = 
&lt;span class="kwrd"&gt;this&lt;/span&gt;.get_element();        
&lt;/pre&gt;
&lt;pre class="alt"&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;         
&lt;span class="kwrd"&gt;if&lt;/span&gt;( 
&lt;span class="kwrd"&gt;null&lt;/span&gt; == nearestChild )
&lt;/pre&gt;
&lt;pre class="alt"&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;( el.lastChild != 
&lt;span class="kwrd"&gt;this&lt;/span&gt;._dropCue )
&lt;/pre&gt;
&lt;pre class="alt"&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;                 el.removeChild(
&lt;span class="kwrd"&gt;this&lt;/span&gt;._dropCue);
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  13:&lt;/span&gt;                 el.appendChild(
&lt;span class="kwrd"&gt;this&lt;/span&gt;._dropCue);
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  14:&lt;/span&gt;             }
&lt;/pre&gt;
&lt;pre class="alt"&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;else&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&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;span class="kwrd"&gt;if&lt;/span&gt;( nearestChild.previousSibling != 
&lt;span class="kwrd"&gt;this&lt;/span&gt;._dropCue )
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  19:&lt;/span&gt;             {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  20:&lt;/span&gt;                 el.removeChild(
&lt;span class="kwrd"&gt;this&lt;/span&gt;._dropCue);
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  21:&lt;/span&gt;                 el.insertBefore(
&lt;span class="kwrd"&gt;this&lt;/span&gt;._dropCue, nearestChild);            
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  22:&lt;/span&gt;             }            
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  23:&lt;/span&gt;         }
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  24:&lt;/span&gt;     },
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;One exception to consider here is that there can be no widget
immediately below the dragged item. It happens when user is trying
to drop the widget at the bottom of column. In that case, the drop
cue is shown at the bottom of the column.&lt;/p&gt;
&lt;p&gt;When user releases the widget, it drops right on top of drop cue
and the drop cue disappears. After the drop the 
&lt;code&gt;onDrop&lt;/code&gt; event is raised to notify where the widget is
dropped.&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; _placeItem : 
&lt;span class="kwrd"&gt;function&lt;/span&gt;(data)
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;     {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt;         
&lt;span class="kwrd"&gt;var&lt;/span&gt; el = 
&lt;span class="kwrd"&gt;this&lt;/span&gt;.get_element();
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt;                 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt;        
data.item.parentNode.removeChild( data.item );
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt;         el.insertBefore( data.item,

&lt;span class="kwrd"&gt;this&lt;/span&gt;._dropCue );
&lt;/pre&gt;
&lt;pre class="alt"&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;         
&lt;span class="rem"&gt;// Find the position of the dropped item&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   9:&lt;/span&gt;         
&lt;span class="kwrd"&gt;var&lt;/span&gt; position = 0;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  10:&lt;/span&gt;         
&lt;span class="kwrd"&gt;var&lt;/span&gt; item = el.firstChild;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  11:&lt;/span&gt;         
&lt;span class="kwrd"&gt;while&lt;/span&gt;( item != data.item )
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  12:&lt;/span&gt;         {  
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  13:&lt;/span&gt;             
&lt;span class="kwrd"&gt;if&lt;/span&gt;( item.className == 
&lt;span class="kwrd"&gt;this&lt;/span&gt;._DragItemClassValue ) position++; 
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  14:&lt;/span&gt;             item =
item.nextSibling; 
&lt;/pre&gt;
&lt;pre class="alt"&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;._raiseDropEvent( 
&lt;span class="rem"&gt;/* Container */&lt;/span&gt; el, 
&lt;span class="rem"&gt;/* droped item */&lt;/span&gt; data.item, 
&lt;span class="rem"&gt;/* position */&lt;/span&gt; position );
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  17:&lt;/span&gt;     }
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;Generally you can make events in extenders by adding two
functions in the extender:&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; add_onDrop : 
&lt;span class="kwrd"&gt;function&lt;/span&gt;(handler) {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;     
&lt;span class="kwrd"&gt;this&lt;/span&gt;.get_events().addHandler(
&lt;span class="str"&gt;&amp;quot;onDrop&amp;quot;&lt;/span&gt;, handler);
&lt;/pre&gt;
&lt;pre class="alt"&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;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt; remove_onDrop : 
&lt;span class="kwrd"&gt;function&lt;/span&gt;(handler) {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt;     
&lt;span class="kwrd"&gt;this&lt;/span&gt;.get_events().removeHandler(
&lt;span class="str"&gt;&amp;quot;onDrop&amp;quot;&lt;/span&gt;, handler);
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   7:&lt;/span&gt; },
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;But this does not give you the support for defining the event
listener name in the ASP.NET declaration:&lt;/div&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; 
&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;
&lt;span class="html"&gt;cdd:CustomDragDropExtender&lt;/span&gt; 
&lt;span class="attr"&gt;ID&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;CustomDragDropExtender1&amp;quot;&lt;/span&gt; 
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;     
&lt;span class="attr"&gt;runat&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt;     
&lt;span class="attr"&gt;OnClientDrop&lt;/span&gt;
&lt;span class="kwrd"&gt;=&amp;quot;onDrop&amp;quot;&lt;/span&gt; 
&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The declaration only allows properties. In order to support such
declarative assignment of events, we need to first introduce a
property named 
&lt;code&gt;OnClientDrop&lt;/code&gt; in the extender. Then during assignment
of the property, we need to find out the function specified there
and attach event notification on that function. The discovery of
the function from its name is done by 
&lt;code&gt;CommonToolkitScripts.resolveFunction&lt;/code&gt; which is
available in ACT project.&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; 
&lt;span class="rem"&gt;// onDrop property maps to onDrop event&lt;/span&gt;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;     get_onDrop : 
&lt;span class="kwrd"&gt;function&lt;/span&gt;() {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt;         
&lt;span class="kwrd"&gt;return&lt;/span&gt; 
&lt;span class="kwrd"&gt;this&lt;/span&gt;.get_events().getHandler(
&lt;span class="str"&gt;&amp;quot;onDrop&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 class="alt"&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;     set_onDrop : 
&lt;span class="kwrd"&gt;function&lt;/span&gt;(value) {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   7:&lt;/span&gt;         
&lt;span class="kwrd"&gt;if&lt;/span&gt; (value &amp;amp;&amp;amp; (0 &amp;lt;
value.length)) {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   8:&lt;/span&gt;             
&lt;span class="kwrd"&gt;var&lt;/span&gt; func =
CommonToolkitScripts.resolveFunction(value);
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   9:&lt;/span&gt;             
&lt;span class="kwrd"&gt;if&lt;/span&gt; (func) { 
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  10:&lt;/span&gt;                 
&lt;span class="kwrd"&gt;this&lt;/span&gt;.add_onDrop(func);
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  11:&lt;/span&gt;             } 
&lt;span class="kwrd"&gt;else&lt;/span&gt; {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  12:&lt;/span&gt;                 
&lt;span class="kwrd"&gt;throw&lt;/span&gt; Error.argumentType(
&lt;span class="str"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;, 
&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(value), 
&lt;span class="str"&gt;&amp;#39;Function&amp;#39;&lt;/span&gt;, 
&lt;span class="str"&gt;&amp;#39;resize handler not a function, function name, or
function text.&amp;#39;&lt;/span&gt;);
&lt;/pre&gt;
&lt;pre class="alt"&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;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  15:&lt;/span&gt;     },
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;Raising the event is same as basic Ajax events:&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; _raiseEvent : 
&lt;span class="kwrd"&gt;function&lt;/span&gt;( eventName, eventArgs ) {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;         
&lt;span class="kwrd"&gt;var&lt;/span&gt; handler = 
&lt;span class="kwrd"&gt;this&lt;/span&gt;.get_events().getHandler(eventName);
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt;         
&lt;span class="kwrd"&gt;if&lt;/span&gt;( handler ) {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt;             
&lt;span class="kwrd"&gt;if&lt;/span&gt;( !eventArgs ) eventArgs =
Sys.EventArgs.Empty;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt;             handler(
&lt;span class="kwrd"&gt;this&lt;/span&gt;, eventArgs);
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt;         }
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   7:&lt;/span&gt;     },
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;This is all about the 
&lt;code&gt;CustomDragDropExtender&lt;/code&gt;. Next challenge is to make the 
&lt;code&gt;CustomFloatingBehavior&lt;/code&gt;. The server side class is
declared as:&lt;/div&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; [assembly:
System.Web.UI.WebResource(
&lt;span class="str"&gt;&amp;quot;CustomDragDrop.CustomFloatingBehavior.js&amp;quot;&lt;/span&gt;,

&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;)]
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;  
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt; 
&lt;span class="kwrd"&gt;namespace&lt;/span&gt; CustomDragDrop
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt; {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt;     [Designer(
&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(CustomFloatingBehaviorDesigner))]
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt;     [ClientScriptResource(
&lt;span class="str"&gt;&amp;quot;CustomDragDrop.CustomFloatingBehavior&amp;quot;&lt;/span&gt;, 
&lt;span class="str"&gt;&amp;quot;CustomDragDrop.CustomFloatingBehavior.js&amp;quot;&lt;/span&gt;)]
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   7:&lt;/span&gt;     [TargetControlType(
&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(WebControl))]
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   8:&lt;/span&gt;     [RequiredScript(
&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(DragDropScripts))]
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   9:&lt;/span&gt;     
&lt;span class="kwrd"&gt;public&lt;/span&gt; 
&lt;span class="kwrd"&gt;class&lt;/span&gt; CustomFloatingBehaviorExtender :
ExtenderControlBase
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  10:&lt;/span&gt;     {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  11:&lt;/span&gt;         [ExtenderControlProperty]
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  12:&lt;/span&gt;         [IDReferenceProperty(
&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(WebControl))]
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  13:&lt;/span&gt;         
&lt;span class="kwrd"&gt;public&lt;/span&gt; 
&lt;span class="kwrd"&gt;string&lt;/span&gt; DragHandleID
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  14:&lt;/span&gt;         {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  15:&lt;/span&gt;             get
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  16:&lt;/span&gt;             {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  17:&lt;/span&gt;                 
&lt;span class="kwrd"&gt;return&lt;/span&gt; GetPropertyValue&amp;lt;String&amp;gt;(
&lt;span class="str"&gt;&amp;quot;DragHandleID&amp;quot;&lt;/span&gt;, 
&lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty);
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  18:&lt;/span&gt;             }
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  19:&lt;/span&gt;             set
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  20:&lt;/span&gt;             {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  21:&lt;/span&gt;                
SetPropertyValue&amp;lt;String&amp;gt;(
&lt;span class="str"&gt;&amp;quot;DragHandleID&amp;quot;&lt;/span&gt;, 
&lt;span class="kwrd"&gt;value&lt;/span&gt;);
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  22:&lt;/span&gt;             }
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  23:&lt;/span&gt;         }
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  24:&lt;/span&gt;     }
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  25:&lt;/span&gt; }
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;There&amp;rsquo;s only one property &amp;ndash; 
&lt;code&gt;DragHandleID&lt;/code&gt;. Widget&amp;rsquo;s header works as the drag
handle. So, the header ID is specified here.&lt;/p&gt;
&lt;p&gt;This extender has dependency on 
&lt;code&gt;DragDropManager&lt;/code&gt; so the 
&lt;code&gt;[RequiredScript(typeof(DragDropScripts))]&lt;/code&gt; attribute is
there.&lt;/p&gt;
&lt;p&gt;Besides the designer class, there&amp;rsquo;s one more class which 
&lt;code&gt;CustomDragDropExtender&lt;/code&gt; need in order to specify its
dependency over this floating behavior:&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; [ClientScriptResource(
&lt;span class="kwrd"&gt;null&lt;/span&gt;, 
&lt;span class="str"&gt;&amp;quot;CustomDragDrop.CustomFloatingBehavior.js&amp;quot;&lt;/span&gt;)]
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;   
&lt;span class="kwrd"&gt;public&lt;/span&gt; 
&lt;span class="kwrd"&gt;static&lt;/span&gt; 
&lt;span class="kwrd"&gt;class&lt;/span&gt; CustomFloatingBehaviorScript
&lt;/pre&gt;
&lt;pre class="alt"&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;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This class can be used inside 
&lt;code&gt;RequiredScript&lt;/code&gt; attribute. It only defines which script
file contains the client side code for the extender.&lt;/p&gt;
&lt;p&gt;The client side Javascript is same as 
&lt;code&gt;FloatingBehavior&lt;/code&gt; that comes with ACT. The only
difference is some hack when drag starts. 
&lt;code&gt;DragDropManager&lt;/code&gt; does not return the item being dragged
to static position once it makes it absolute. It also does not
increase the 
&lt;code&gt;zIndex&lt;/code&gt; of the item. If the drag item does not become
the top most item, while dragging it goes below other elements on
the page. So, I have made some changes in the mouseDownHandler of
the behavior to add these features:&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; 
&lt;span class="kwrd"&gt;function&lt;/span&gt; mouseDownHandler(ev) {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;     window._event = ev;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt;     
&lt;span class="kwrd"&gt;var&lt;/span&gt; el = 
&lt;span class="kwrd"&gt;this&lt;/span&gt;.get_element();
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt;     
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt;     
&lt;span class="kwrd"&gt;if&lt;/span&gt; (!
&lt;span class="kwrd"&gt;this&lt;/span&gt;.checkCanDrag(ev.target)) 
&lt;span class="kwrd"&gt;return&lt;/span&gt;;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt;     
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   7:&lt;/span&gt;     
&lt;span class="rem"&gt;// Get the location before making the element
absolute&lt;/span&gt;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   8:&lt;/span&gt;     _location =
Sys.UI.DomElement.getLocation(el);
&lt;/pre&gt;
&lt;pre class="alt"&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="rem"&gt;// Make the element absolute &lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  11:&lt;/span&gt;     el.style.width = el.offsetWidth
+ 
&lt;span class="str"&gt;&amp;quot;px&amp;quot;&lt;/span&gt;;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  12:&lt;/span&gt;     el.style.height =
el.offsetHeight + 
&lt;span class="str"&gt;&amp;quot;px&amp;quot;&lt;/span&gt;;            
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  13:&lt;/span&gt;    
Sys.UI.DomElement.setLocation(el, _location.x, _location.y);       
       
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  14:&lt;/span&gt;     
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  15:&lt;/span&gt;     _dragStartLocation =
Sys.UI.DomElement.getLocation(el);        
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  16:&lt;/span&gt;     
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  17:&lt;/span&gt;     ev.preventDefault();
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  18:&lt;/span&gt;     
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  19:&lt;/span&gt;     
&lt;span class="kwrd"&gt;this&lt;/span&gt;.startDragDrop(el);
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  20:&lt;/span&gt;     
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  21:&lt;/span&gt;     
&lt;span class="rem"&gt;// Hack for restoring position to static&lt;/span&gt;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  22:&lt;/span&gt;     el.originalPosition = 
&lt;span class="str"&gt;&amp;quot;static&amp;quot;&lt;/span&gt;;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  23:&lt;/span&gt;     el.originalZIndex =
el.style.zIndex;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  24:&lt;/span&gt;     el.style.zIndex = 
&lt;span class="str"&gt;&amp;quot;60000&amp;quot;&lt;/span&gt;;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  25:&lt;/span&gt; }
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Setting 
&lt;code&gt;el.originalPosition = static&lt;/code&gt; fixes the bug in 
&lt;code&gt;DragDropManager&lt;/code&gt;. It incorrectly stores absolute has
the 
&lt;code&gt;originalPosition&lt;/code&gt; when 
&lt;code&gt;startDragDrop&lt;/code&gt; is called. So, after calling this
function, I set it to correct 
&lt;code&gt;originalPosition&lt;/code&gt; which is &amp;ldquo;static&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;When drag completes, the original zIndex is restored and left,
top, width and height is cleared. DragDropManager makes the item
position static, but it does not clear the left, top, width and
height attributes. This moves the element away from the place where
it is dropped. This bug is fixed in the onDragEnd event:&lt;/p&gt;
&lt;div&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; 
&lt;span class="kwrd"&gt;this&lt;/span&gt;.onDragEnd = 
&lt;span class="kwrd"&gt;function&lt;/span&gt;(canceled) {
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;     
&lt;span class="kwrd"&gt;if&lt;/span&gt; (!canceled) {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt;         
&lt;span class="kwrd"&gt;var&lt;/span&gt; handler = 
&lt;span class="kwrd"&gt;this&lt;/span&gt;.get_events().getHandler(
&lt;span class="str"&gt;&amp;#39;move&amp;#39;&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;(handler) {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt;             
&lt;span class="kwrd"&gt;var&lt;/span&gt; cancelArgs = 
&lt;span class="kwrd"&gt;new&lt;/span&gt; Sys.CancelEventArgs();
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt;             handler(
&lt;span class="kwrd"&gt;this&lt;/span&gt;, cancelArgs);
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   7:&lt;/span&gt;             canceled =
cancelArgs.get_cancel();
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;   8:&lt;/span&gt;         }            
&lt;/pre&gt;
&lt;pre class="alt"&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;pre class="alt"&gt;
&lt;span class="lnum"&gt;  11:&lt;/span&gt;     
&lt;span class="kwrd"&gt;var&lt;/span&gt; el = 
&lt;span class="kwrd"&gt;this&lt;/span&gt;.get_element();
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  12:&lt;/span&gt;     el.style.width =
el.style.height = el.style.left = el.style.top = 
&lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  13:&lt;/span&gt;     el.style.zIndex =
el.originalZIndex;
&lt;/pre&gt;
&lt;pre&gt;
&lt;span class="lnum"&gt;  14:&lt;/span&gt; }
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;That&amp;#39;s all folks!&lt;/p&gt;
&lt;p&gt;You can get the 
&lt;a href="http://omar.mvps.org/images/CustomDragDrop.zip"&gt;code for
the extenders here&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=702124" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net+ajax/default.aspx">asp.net ajax</category></item><item><title>ASP.NET Ajax in-depth performance analysis</title><link>http://msmvps.com/blogs/omar/archive/2007/03/16/asp-net-ajax-in-depth-performance-analysis.aspx</link><pubDate>Fri, 16 Mar 2007 09:24:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:685327</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=685327</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2007/03/16/asp-net-ajax-in-depth-performance-analysis.aspx#comments</comments><description>&lt;p&gt;Let&amp;#39;s do some ASP.NET runtime analysis on 
&lt;a href="http://www.dropthings.com"&gt;www.dropthings.com&lt;/a&gt;. Those
who don&amp;#39;t know what it is, it&amp;#39;s an open source start page I made
using ASP.NET Ajax, .NET 3.0 and Linq.&lt;/p&gt;
&lt;p&gt;
&lt;img height="337" src="http://omar.mvps.org/images/ASP.NETAjaxindepthperformanceanalysis_D871/image0.png" width="607" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;ASP.NET Ajax has a pretty big runtime which consists of Core
Framework, scripts for UpdatePanel, Preview Script required for
Drag &amp;amp; Drop. Additionally&amp;nbsp;I need Ajax Control Toolkit
(ACT). All these add up to a staggering 564 KB of download in 12
script references on the page. The download size mostly depends on
the usage of extenders and Ajax features. A moderate use of
extender results in the following download:&lt;/p&gt;
&lt;p&gt;
&lt;img height="303" src="http://omar.mvps.org/images/ASP.NETAjaxindepthperformanceanalysis_D871/image03.png" width="660" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a simulation of 256kbps internet speed on 200ms
network latency. I use a tool named Charles (
&lt;a href="http://www.xk72.com/charles"&gt;www.xk72.com/charles&lt;/a&gt;) to
capture traffic and simulate slow internet speed by throttling data
transfer speed. From the durations, we see almost 20 sec is spent
on downloading the runtime over a 256kbps line!&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s explain which script in the above list does what. I
will be identifying the scripts using their file size in order of
their appearance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;21.64 KB &amp;ndash; Handy script for Postbacks&lt;/li&gt;
&lt;li&gt;83.38 KB &amp;ndash; Microsoft Ajax Core runtime&lt;/li&gt;
&lt;li&gt;30.16 KB - UpdatePanel, partial update, asynchronous postback
scripts.&lt;/li&gt;
&lt;li&gt;136.38 KB &amp;ndash; Preview version of Ajax which allows Drag
&amp;amp; Drop script&lt;/li&gt;
&lt;li&gt;36.02 KB &amp;ndash; The actual drag &amp;amp; drop script in Preview
library&lt;/li&gt;
&lt;li&gt;45.25 KB &amp;ndash; Ajax Control Toolkit&lt;/li&gt;
&lt;li&gt;4.08 KB &amp;ndash; Timer script&lt;/li&gt;
&lt;li&gt;140.86 KB &amp;ndash; ACT Animation framework&lt;/li&gt;
&lt;li&gt;18.05 KB &amp;ndash; ACT Behavior base implementation. Required for
Behaviors provided in the Ajax Control Toolkit project.&lt;/li&gt;
&lt;li&gt;16.48 KB &amp;ndash; ACT Animation Behavior&lt;/li&gt;
&lt;li&gt;7.32 KB &amp;ndash; My Custom Drag Drop behavior&lt;/li&gt;
&lt;li&gt;9.73 KB &amp;ndash; My Custom Floating Behavior&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The total payload for only the runtime is too high to accept
because we cannot make a user wait for 20 sec just to download Ajax
scripts before user can actually start interacting on the page. So,
I&amp;nbsp;took several approaches to reduce the size of the
download:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Eliminate Preview version of Ajax completely and use ACT for
Drag &amp;amp; Drop&lt;/li&gt;
&lt;li&gt;Use IIS 6 compression to deliver compressed scripts from the
client&lt;/li&gt;
&lt;li&gt;Combine multiple script files into one file&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ACT comes with its own DragDropManager which we need for Drag
&amp;amp; Drop. So far I thought of using
Sys.Preview.UI.DragDropManager in the ASP.NET Ajax January CTP. But
just for the DragDropManager, I need to add nearly 180 KB of
scripts for the entire Preview Library runtime. If I use
ACT&amp;rsquo;s DrgaDropManager, I can get rid of the Preview
runtime.&lt;/p&gt;
&lt;p&gt;Without the preview scripts, the scripts downloaded are:&lt;/p&gt;
&lt;p&gt;
&lt;img height="272" src="http://omar.mvps.org/images/ASP.NETAjaxindepthperformanceanalysis_D871/image04.png" width="707" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;The following downloads are missing here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;136.38 KB &amp;ndash; Preview version of Ajax which allows Drag
&amp;amp; Drop script&lt;/li&gt;
&lt;li&gt;36.02 KB &amp;ndash; The actual drag &amp;amp; drop script in Preview
library&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;nbsp;saved about 180 KB, nearly 7 sec from total download. So,
user gets to work on the page 7 secs earlier than before.&lt;/p&gt;
&lt;p&gt;When I enabled IIS 6 compression, the situation improved
dramatically. Here&amp;rsquo;s the data transfers when compression is
enabled:&lt;/p&gt;
&lt;p&gt;
&lt;img height="261" src="http://omar.mvps.org/images/ASP.NETAjaxindepthperformanceanalysis_D871/image07.png" width="627" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;The total download comes down from 448 KB to 163 KB! Total 64%
download bytes reduction! This results in 3 times faster page
download.&lt;/p&gt;
&lt;p&gt;The scripts are downloaded in two steps &amp;ndash; first the core
runtimes download and then ACT and other scripts download. The
content is displayed after the core runtime is downloaded. So, the
time it takes to show the content on the browser reduces
significantly because now it takes only 50KB to download before
something is visible on the screen compared to 130 KB on
non-compressed mode.&lt;/p&gt;
&lt;p&gt;
&lt;font color="#804040"&gt;ScriptManager&lt;/font&gt; control has 
&lt;font color="#804040"&gt;LoadScriptsBeforeUI&lt;/font&gt; property which you
can set to &amp;ldquo;False&amp;rdquo; in order to postpone several script
downloads after the content is downloaded. This adds the script
references end of the &amp;lt;body&amp;gt; tag. As a result, you see the
content first and then the additional scripts, exteders, ACT
scripts get downloaded and initialized.&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:59db7987-cafa-46ac-9d55-0de4da375b5d" style="padding-right:0px;display:inline;padding-left:0px;float:none;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;

&lt;pre style="background-color:White;"&gt;&lt;/pre&gt;
&lt;div&gt;

&lt;span style="color:#0000FF;"&gt;&amp;lt;&lt;/span&gt;
&lt;span style="color:#800000;"&gt;asp:ScriptManager&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;ID&lt;/span&gt;
&lt;span style="color:#0000FF;"&gt;=&amp;quot;ScriptManager1&amp;quot;&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;runat&lt;/span&gt;
&lt;span style="color:#0000FF;"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;EnablePartialRendering&lt;/span&gt;
&lt;span style="color:#0000FF;"&gt;=&amp;quot;true&amp;quot;&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;LoadScriptsBeforeUI&lt;/span&gt;
&lt;span style="color:#0000FF;"&gt;=&amp;quot;false&amp;quot;&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;ScriptMode&lt;/span&gt;
&lt;span style="color:#0000FF;"&gt;=&amp;quot;Release&amp;quot;&lt;/span&gt;
&lt;span style="color:#0000FF;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#000000;"&gt;...&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;&amp;lt;/&lt;/span&gt;
&lt;span style="color:#800000;"&gt;asp:ScriptManager&lt;/span&gt;
&lt;span style="color:#0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can explicitly set ScriptMode=false in order to emit release
mode highly optimized Ajax runtime scripts during local
debugging.&lt;/p&gt;
&lt;img src="http://msmvps.com/aggbug.aspx?PostID=685327" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net+ajax/default.aspx">asp.net ajax</category></item><item><title>Article of the month - vote for me</title><link>http://msmvps.com/blogs/omar/archive/2007/02/13/article-of-the-month-vote-for-me.aspx</link><pubDate>Tue, 13 Feb 2007 18:29:45 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:574742</guid><dc:creator>omar</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=574742</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2007/02/13/article-of-the-month-vote-for-me.aspx#comments</comments><description>&lt;p&gt;My article &amp;quot;&lt;a href="http://www.codeproject.com/Ajax/MakingGoogleIG.asp"&gt;Build Google IG like Ajax Start Page in 7 days using ASP.NET Ajax and .NET 3.0&lt;/a&gt;&amp;quot; is now on the nomination list of Codeproject. If you found this article helpful, please give me a vote here: &lt;p&gt;&lt;a href="http://www.codeproject.com/script/survey/survey.asp?survey=647"&gt;http://www.codeproject.com/script/survey/survey.asp?survey=647&lt;/a&gt; &lt;p&gt;If you have not read it yet, I would request you to take a look at it. You can learn about ASP.NET Ajax, ASP.NET 2.0 tricks, Workflow Foundation, real use of WF from ASP.NET and finally how to make real use of Dlinq, XLinq and Linq. &lt;/p&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=574742" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net+ajax/default.aspx">asp.net ajax</category></item><item><title>Build Google IG like AJAX Start Page in 7 days using ASP.NET AJAX and .NET 3.0</title><link>http://msmvps.com/blogs/omar/archive/2007/01/04/build-google-ig-like-ajax-start-page-in-7-days-using-asp-net-ajax-and-net-3-0.aspx</link><pubDate>Thu, 04 Jan 2007 08:38:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:468728</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=468728</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2007/01/04/build-google-ig-like-ajax-start-page-in-7-days-using-asp-net-ajax-and-net-3-0.aspx#comments</comments><description>&lt;p&gt;I will show you how I built a start page similar to Google IG in
7 nights using ASP.Net Ajax, .NET 3.0, Linq, DLinq and XLinq. I
have logged my day to day development experience in this article
and documented all the technical challenges, interesting
discoveries and important design &amp;amp; architectural decisions. You
will find the implementation quite close to actual 
&lt;a href="http://www.google.com/ig"&gt;Google IG&lt;/a&gt;. It has drag &amp;amp;
drop enabled widgets, complete personalization of the pages, multi
page feature and so on. It&amp;#39;s not just a prototype or a sample
project. It&amp;#39;s a real living and breathing open source start page
running at 
&lt;a href="http://www.dropthings.com/"&gt;http://www.dropthings.com/&lt;/a&gt;
which you can use everyday. You are welcome to participate in the
development and make widgets for the project.&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.codeproject.com/Ajax/MakingGoogleIG/Screenshot.png" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;You can find the article on CodeProject:&lt;/p&gt;
&lt;p&gt;
&lt;a title="Build Google IG like Ajax Start Page" href="http://www.codeproject.com/Ajax/MakingGoogleIG.asp" target="_blank"&gt;Build Google IG like AJAX Start Page in 7 days
using ASP.NET AJAX and .NET 3.0&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;If you like it, please vote for me. &amp;nbsp;&lt;/p&gt;
&lt;img src="http://msmvps.com/aggbug.aspx?PostID=468728" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net+ajax/default.aspx">asp.net ajax</category></item><item><title>ASP.net Ajax under the hood secrets</title><link>http://msmvps.com/blogs/omar/archive/2006/12/01/asp-net-ajax-under-the-hood-secrets.aspx</link><pubDate>Fri, 01 Dec 2006 16:48:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:359520</guid><dc:creator>omar</dc:creator><slash:comments>10</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=359520</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2006/12/01/asp-net-ajax-under-the-hood-secrets.aspx#comments</comments><description>&lt;p&gt;I have published a new article in codeproject:&lt;/p&gt;
&lt;p&gt;
&lt;a title="ASP.net Ajax under the hood secrets" href="http://www.codeproject.com/Ajax/aspnetajaxtips.asp" target="_blank"&gt;ASP.net Ajax under the hood secrets&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;You will find the following tricks on it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Batch call advantages and disadvantages&lt;/li&gt;
&lt;li&gt;Implement auto retry in all web method call by modifying Ajax
core framework&lt;/li&gt;
&lt;li&gt;Implement queue based web method call in order to prevent
browser from getting stuck with too many Ajax calls&lt;/li&gt;
&lt;li&gt;Caching web method response, fix bug in ASP.net 2.0 cache
header problem&lt;/li&gt;
&lt;li&gt;How slow is Http Post, capture data transfer over the wire and
see&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some of the techniques may be known to you if you have read my
earlier posts. But I have converted all code to the latest ASP.net
Ajax Beta 2 version which is not available in the blog posts.&lt;/p&gt;
&lt;p&gt;Please rate the article if you like it at codeproject.&lt;/p&gt;
&lt;p&gt;Also please 
&lt;a title="ASP.net Ajax under the hood secrets" href="http://www.digg.com/programming/Ajax_advanced_tips_and_tricks"&gt;
digg this article&lt;/a&gt;.&lt;/p&gt;
&lt;img src="http://msmvps.com/aggbug.aspx?PostID=359520" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net+ajax/default.aspx">asp.net ajax</category></item><item><title>Atlas 7: Caching web service response on browser and save bandwidth significantly</title><link>http://msmvps.com/blogs/omar/archive/2006/09/23/Atlas-7_3A00_-Caching-web-service-response-on-browser-and-save-bandwidth-significantly.aspx</link><pubDate>Sat, 23 Sep 2006 17:04:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:137685</guid><dc:creator>omar</dc:creator><slash:comments>54</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=137685</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2006/09/23/Atlas-7_3A00_-Caching-web-service-response-on-browser-and-save-bandwidth-significantly.aspx#comments</comments><description>&lt;p&gt;Browser can cache images, javascripts, css files on users hard
drive and it can also cache Xml Http calls if the call is a Http
Get. The cache is based on Url. If it&amp;#39;s the same Url and it&amp;#39;s
cached on the computer then the response is loaded from cache, not
from the server when it is requested again. Basically, browser can
cache any Http Get call and return cached data based on Url. If you
make a Xml Http call as Http GET and server returns some special
header which informs the browser to cache the response; on future
calls, the response will be immediately returned from the cache and
thus save the delay of network roundtrip and download time.&lt;/p&gt;
&lt;p&gt;At 
&lt;a href="http://www.pageflakes.com"&gt;Pageflakes&lt;/a&gt;, we cache user&amp;#39;s
state so that when user visits again the following day, user gets a
cached page which loads instantly from browser cache, not from the
server. Thus second time load becomes very fast. We also cache
several small parts of the page which appears on users action. When
user does the same action again, a cached result is loaded
immediately from local cache and thus saves the network roundtrip
time. User gets a fast loading site and a very responsive site. The
perceived speed increases dramatically.&lt;/p&gt;
&lt;p&gt;The idea is to make Http Get calls while making Atlas web
service calls and return some specific Http Response headers which
tells the browser to cache the response for some specific duration.
If you return &amp;quot;Expires&amp;quot; header during the response, browser will
cache the Xml Http response. There are 2 headers that you need to
return with response which will instruct browser to cache the
response:&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="F2210F5F-69EB-4d4c-AFF7-B8A050E9CC72:4fc3b9d5-e83e-4036-b91c-12caaef9958f" style="padding-right:0px;display:inline;padding-left:0px;float:none;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;

&lt;div&gt;
&lt;span style="color:#000000;"&gt;HTTP/&lt;/span&gt;
&lt;span style="color:#000000;"&gt;1.1&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;200&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;OK Expires: Fri&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;1&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;Jan&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;2030&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;Cache-Control: public&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This will instruct browser to cache the response till Jan 2030.
As long as you make the same Xml Http call with the same
parameters, you will get cached response from the computer and no
call will go to the server. There are more advanced ways to get
further control over response caching. For example, here is a
header which will instruct browser to cache for 60 seconds but do
contact server and get a fresh response after 60 seconds. It will
also prevent proxies from returning cached response when browser
local cache expires after 60 seconds.&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="F2210F5F-69EB-4d4c-AFF7-B8A050E9CC72:088e809c-6a10-4bb9-9a2a-c80c6339e1c5" style="padding-right:0px;display:inline;padding-left:0px;float:none;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;

&lt;div&gt;
&lt;span style="color:#000000;"&gt;HTTP/&lt;/span&gt;
&lt;span style="color:#000000;"&gt;1.1&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;200&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;OK Cache-Control: private&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;must-revalidate&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;proxy-revalidate&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;max-age&lt;/span&gt;
&lt;span style="color:#000000;"&gt;=&lt;/span&gt;
&lt;span style="color:#000000;"&gt;60&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Let&amp;#39;s try to produce such response headers from ASP.NET web
service call:&lt;/p&gt;
&lt;p&gt;
&lt;img height="226" src="http://omar.mvps.org/images/Atlas7Cachingwebserviceresponseonbrowser_14173/clip_image0011.png" width="687" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;This will result in the following response headers:&lt;/p&gt;
&lt;p&gt;
&lt;img height="125" src="http://omar.mvps.org/images/Atlas7Cachingwebserviceresponseonbrowser_14173/clip_image0021.png" width="427" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;Expires header is set properly. But the problem is with
Cache-Control. It is showing &amp;quot;max-age&amp;quot; is set to zero which will
prevent browser from doing any kind of caching. If you seriously
want to prevent caching, you should emit such cache-control header.
Looks like exactly the opposite thing happened.&lt;/p&gt;
&lt;p&gt;There&amp;#39;s a bug in ASP.NET 2.0 that you cannot change &amp;quot;max-age&amp;quot;
header. As max-age is set to zero, ASP.NET 2.0 sets Cache-Control
to private because max-age = 0 means no cache needed. So, there&amp;#39;s
no way you can make ASP.NET 2.0 return proper headers which caches
the response.&lt;/p&gt;
&lt;p&gt;Time for a hack. After decompiling the code of HttpCachePolicy
class (Context.Response.Cache object&amp;#39;s class), I found the
following code:&lt;/p&gt;
&lt;p&gt;
&lt;img height="260" src="http://omar.mvps.org/images/Atlas7Cachingwebserviceresponseonbrowser_14173/clip_image0031.png" width="441" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;Somehow, this._maxAge is getting set to zero and the check: &amp;quot;if
(!this._isMaxAgeSet || (delta &amp;lt; this._maxAge))&amp;quot; is preventing it
from getting set to a bigger value. Due to this problem, we need to
bypass the SetMaxAge function and set the value of the _maxAge
field directly using Reflection.&lt;/p&gt;
&lt;p&gt;
&lt;img height="292" src="http://omar.mvps.org/images/Atlas7Cachingwebserviceresponseonbrowser_14173/clip_image0041.png" width="687" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;This will return the following headers:&lt;/p&gt;
&lt;p&gt;
&lt;img height="125" src="http://omar.mvps.org/images/Atlas7Cachingwebserviceresponseonbrowser_14173/clip_image0051.png" width="439" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;Now max-age is set to 60 and thus browser will cache the
response for 60 seconds. If you make the same call again within 60
seconds, it will return the same response. Here&amp;#39;s a test output
which shows the date time returned from the server:&lt;/p&gt;
&lt;p&gt;
&lt;img height="199" src="http://omar.mvps.org/images/Atlas7Cachingwebserviceresponseonbrowser_14173/clip_image0061.png" width="268" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;The client side code is like this:&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="F2210F5F-69EB-4d4c-AFF7-B8A050E9CC72:c1142e91-42af-4b2b-ba8b-149ed5064b27" style="padding-right:0px;display:inline;padding-left:0px;float:none;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;

&lt;div&gt;

&lt;span style="color:#0000FF;"&gt;function&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;cachedHttpGet() {
WebService.CachedGet( { useGetMethod:&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;true&lt;/span&gt;
&lt;span style="color:#000000;"&gt;, onMethodComplete:&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;function&lt;/span&gt;
&lt;span style="color:#000000;"&gt;(result) { debug.dump(result); } } );
}&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here you see, the response is cached for 60 seconds and after
the time elapsed, there was a server call made and new date was
returned. That response was again cached for 60 seconds.&lt;/p&gt;
&lt;img src="http://msmvps.com/aggbug.aspx?PostID=137685" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net+ajax/default.aspx">asp.net ajax</category></item><item><title>Atlas 6: When 'this' is not really 'this'</title><link>http://msmvps.com/blogs/omar/archive/2006/09/23/Atlas-6_3A00_-When-_2700_this_2700_-is-not-really-_2700_this_2700_.aspx</link><pubDate>Sat, 23 Sep 2006 16:46:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:137665</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=137665</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2006/09/23/Atlas-6_3A00_-When-_2700_this_2700_-is-not-really-_2700_this_2700_.aspx#comments</comments><description>&lt;p&gt;Atlas callbacks are not executed on the same context where they
are called. For ex, if you are making a Page method call from a
javascript class like this:&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="F2210F5F-69EB-4d4c-AFF7-B8A050E9CC72:9e15f2f7-c03c-466c-9a5f-aabe3f8cd647" style="padding-right:0px;display:inline;padding-left:0px;float:none;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;

&lt;div&gt;
&lt;span style="color:#0000FF;"&gt;function&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;SampleClass() {&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;this&lt;/span&gt;
&lt;span style="color:#000000;"&gt;.id&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;=&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;1&lt;/span&gt;
&lt;span style="color:#000000;"&gt;;&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;this&lt;/span&gt;
&lt;span style="color:#000000;"&gt;.call&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;=&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;function&lt;/span&gt;
&lt;span style="color:#000000;"&gt;() { PageMethods.DoSomething(&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;&amp;quot;&lt;/span&gt;
&lt;span style="color:#000000;"&gt;Hi&lt;/span&gt;
&lt;span style="color:#000000;"&gt;&amp;quot;&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;function&lt;/span&gt;
&lt;span style="color:#000000;"&gt;(result) { debug.dump(&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;this&lt;/span&gt;
&lt;span style="color:#000000;"&gt;.id ); } ); } }&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;What happens when you call the &amp;quot;call&amp;quot; method? Do you get &amp;quot;1&amp;quot; on
the debug console? No, you get &amp;quot;null&amp;quot; on the debug console because
&amp;quot;this&amp;quot; is no longer the instance of the class. This is a common
mistake everyone makes. As this is not yet documented in Atlas
documentations, I have seen many developers spend time finding out
what&amp;#39;s wrong.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s the reason. We know whenever Javascript events are raised
&amp;quot;this&amp;quot; refers to the html element which produced the event. So, if
you do this:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="F2210F5F-69EB-4d4c-AFF7-B8A050E9CC72:6a7f0ffe-214c-469d-adb2-e32ddce9837b" style="padding-right:0px;display:inline;padding-left:0px;float:none;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;

&lt;div&gt;
&lt;span style="color:#0000FF;"&gt;function&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;SampleClass() {&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;this&lt;/span&gt;
&lt;span style="color:#000000;"&gt;.id&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;=&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;1&lt;/span&gt;
&lt;span style="color:#000000;"&gt;;&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;this&lt;/span&gt;
&lt;span style="color:#000000;"&gt;.call&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;=&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;function&lt;/span&gt;
&lt;span style="color:#000000;"&gt;() { PageMethods.DoSomething(&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;&amp;quot;&lt;/span&gt;
&lt;span style="color:#000000;"&gt;Hi&lt;/span&gt;
&lt;span style="color:#000000;"&gt;&amp;quot;&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;function&lt;/span&gt;
&lt;span style="color:#000000;"&gt;(result) { debug.dump(&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;this&lt;/span&gt;
&lt;span style="color:#000000;"&gt;.id ); } ); } }&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;lt;input type=&amp;quot;button&amp;quot; id=&amp;quot;ButtonID&amp;quot; onclick=&amp;quot;o.onclick&amp;quot;
/&amp;gt;&lt;/p&gt;
&lt;p&gt;If you click the button, you see &amp;quot;ButtonID&amp;quot; instead of &amp;quot;1&amp;quot;. The
reason is that, the button is making the call. So, the call is made
within button object&amp;#39;s context and thus &amp;quot;this&amp;quot; maps to the button
object.&lt;/p&gt;
&lt;p&gt;Similarly, when Xml Http raises the event onreadystatechanged
which Atlas traps and fires the callback, the code execution is
still on the Xml Http&amp;#39;s context. It&amp;#39;s Xml Http object which raises
the event. As a result, &amp;quot;this&amp;quot; refer to the Xml Http object, not to
your own class where the callback is declared.&lt;/p&gt;
&lt;p&gt;In order to make the callback fire on the context of the
instance of the class so that &amp;quot;this&amp;quot; refers to the instance of the
class, you need to make the following change:&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="F2210F5F-69EB-4d4c-AFF7-B8A050E9CC72:a6c09e5d-0bb0-48c5-a5b8-921b80b26069" style="padding-right:0px;display:inline;padding-left:0px;float:none;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;

&lt;div&gt;
&lt;span style="color:#0000FF;"&gt;function&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;SampleClass() {&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;this&lt;/span&gt;
&lt;span style="color:#000000;"&gt;.id&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;=&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;1&lt;/span&gt;
&lt;span style="color:#000000;"&gt;;&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;this&lt;/span&gt;
&lt;span style="color:#000000;"&gt;.call&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;=&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;function&lt;/span&gt;
&lt;span style="color:#000000;"&gt;() { PageMethods.DoSomething(&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;&amp;quot;&lt;/span&gt;
&lt;span style="color:#000000;"&gt;Hi&lt;/span&gt;
&lt;span style="color:#000000;"&gt;&amp;quot;&lt;/span&gt;
&lt;span style="color:#000000;"&gt;, Function.createDelegate(&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;this&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;function&lt;/span&gt;
&lt;span style="color:#000000;"&gt;(result) { debug.dump(&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;this&lt;/span&gt;
&lt;span style="color:#000000;"&gt;.id ); } ) ); } }&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here, the Function.createDelegate is used to create a delegate
which calls the given function under the &amp;quot;this&amp;quot; context.
Function.createDelegate is defined in AtlasRuntime:&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="F2210F5F-69EB-4d4c-AFF7-B8A050E9CC72:85795f90-4690-4086-8198-679f8ae51b72" style="padding-right:0px;display:inline;padding-left:0px;float:none;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;

&lt;div&gt;
&lt;span style="color:#000000;"&gt;Function.createDelegate&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;=&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;function&lt;/span&gt;
&lt;span style="color:#000000;"&gt;(instance, method) {&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;return&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;function&lt;/span&gt;
&lt;span style="color:#000000;"&gt;() {&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;return&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;method.apply(instance, arguments); }
}&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;img src="http://msmvps.com/aggbug.aspx?PostID=137665" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net+ajax/default.aspx">asp.net ajax</category></item><item><title>Atlas 4: Only 2 calls at a time and don't expect any order</title><link>http://msmvps.com/blogs/omar/archive/2006/09/23/Atlas-4_3A00_-Only-2-calls-at-a-time-and-don_2700_t-expect-any-order.aspx</link><pubDate>Sat, 23 Sep 2006 16:37:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:137653</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=137653</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2006/09/23/Atlas-4_3A00_-Only-2-calls-at-a-time-and-don_2700_t-expect-any-order.aspx#comments</comments><description>&lt;p&gt;Browsers make 2 concurrent AJAX calls at a time to a domain. If
you make 5 AJAX calls, browser is going to make 2 calls first, then
wait for any one of them to complete and then make another call
until all remaining 4 calls are complete. Moreover, you cannot
expect calls to execute in the same order as you make the calls.
Here&amp;#39;s why:&lt;/p&gt;
&lt;p&gt;
&lt;img height="300" src="http://omar.mvps.org/images/Atlas4Only2callsatatimeanddontexpectanyo_13DEE/clip_image00111.png" width="617" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;Here you see, call 3&amp;#39;s response download is quite big and thus
takes longer than Call 5. So, Call 5 actually gets executed before
Call 3.&lt;/p&gt;
&lt;p&gt;So, the world of HTTP is unpredictable.&lt;/p&gt;
&lt;img src="http://msmvps.com/aggbug.aspx?PostID=137653" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net+ajax/default.aspx">asp.net ajax</category></item><item><title>Atlas 5: Bad calls make good calls timeout</title><link>http://msmvps.com/blogs/omar/archive/2006/09/23/Atlas-5_3A00_-Bad-calls-make-good-calls-timeout.aspx</link><pubDate>Sat, 23 Sep 2006 16:31:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:137650</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=137650</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2006/09/23/Atlas-5_3A00_-Bad-calls-make-good-calls-timeout.aspx#comments</comments><description>&lt;p&gt;If 2 http calls somehow get stuck for too long, those two bad
calls are going to make some good calls expire too which in the
meantime got queued. Here&amp;#39;s a nice example:&lt;/p&gt;
&lt;p&gt;function timeoutTest()&lt;/p&gt;
&lt;p&gt;{&lt;/p&gt;
&lt;p&gt;PageMethods.Timeout( { timeoutInterval : 3000, onMethodTimeout:
function() { debug.dump(&amp;quot;Call 1 timed out&amp;quot;); } } );&lt;/p&gt;
&lt;p&gt;PageMethods.Timeout( { timeoutInterval : 3000, onMethodTimeout:
function() { debug.dump(&amp;quot;Call 2 timed out&amp;quot;); } } );&lt;/p&gt;
&lt;p&gt;PageMethods.DoSomething( &amp;#39;Call 1&amp;#39;, { timeoutInterval : 3000,
onMethodTimeout: function() { debug.dump(&amp;quot;DoSomething 1 timed
out&amp;quot;); } } );&lt;/p&gt;
&lt;p&gt;PageMethods.DoSomething( &amp;#39;Call 2&amp;#39;, { timeoutInterval : 3000,
onMethodTimeout: function() { debug.dump(&amp;quot;DoSomething 2 timed
out&amp;quot;); } } );&lt;/p&gt;
&lt;p&gt;PageMethods.DoSomething( &amp;#39;Call 3&amp;#39;, { timeoutInterval : 3000,
onMethodTimeout: function() { debug.dump(&amp;quot;DoSomething 3 timed
out&amp;quot;); } } );&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;I am calling a method named &amp;quot;Timeout&amp;quot; on the server which does
nothing but to wait for a long time so that the call gets timed
out. After that I am calling a method which does not timeout. But
guess what the output is:&lt;/p&gt;
&lt;p&gt;
&lt;img height="127" src="http://omar.mvps.org/images/Atlas5Badcallsmakegoodcallstimeout_13C77/clip_image0011.png" width="393" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;Only one call succeeded &amp;quot;Do Something 1&amp;quot;. Try again and you
might see this:&lt;/p&gt;
&lt;p&gt;
&lt;img height="109" src="http://omar.mvps.org/images/Atlas5Badcallsmakegoodcallstimeout_13C77/clip_image0021.png" width="387" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;Now two calls succeeded. So, if at any moment, browser&amp;#39;s two
connections get jammed, then you can expect other waiting calls are
going to timeout also.&lt;/p&gt;
&lt;p&gt;In Pageflakes, we used to get nearly 400 to 600 timeout error
reports from users&amp;#39; browsers. We could never find out how this can
happen. First we suspected slow internet connection. But that
cannot happen for so many users. Then we suspected something is
wrong with the hosting providers network. We did a lot of network
analysis to find out whether there&amp;#39;s any problem on the network.
But we could not detect any. We used SQL Profiler to see whether
there&amp;#39;s any long running query which times out ASP.NET request
execution time. But no luck. We finally discovered that, it mostly
happened due to some bad calls which got stuck and made the good
calls expire too. So, we modified the Atlas Runtime and introduce
automatic retry on it and the problem disappeared completely.
However, this auto retry requires a sophisticated open heart bypass
surgery on Atlas Runtime javascript code which you have to perform
again and again whenever Microsoft releases newer version of Atlas
Runtime. You also can no longer use the &amp;lt;atlas:scriptmanager&amp;gt;
tag which produces Atlas runtime references instead you have to
manually put links to Atlas runtime and compatibility javascript
files. So, you better do auto retry yourself in your own code from
Day 1. On the onMethodTimeout method, just make one retry all the
time to be on the safe side.&lt;/p&gt;
&lt;img src="http://msmvps.com/aggbug.aspx?PostID=137650" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net+ajax/default.aspx">asp.net ajax</category></item><item><title>Atlas 3: Atlas batch calls are not always faster</title><link>http://msmvps.com/blogs/omar/archive/2006/09/23/Atlas-3_3A00_-Atlas-batch-calls-are-not-always-faster.aspx</link><pubDate>Sat, 23 Sep 2006 15:59:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:137636</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=137636</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2006/09/23/Atlas-3_3A00_-Atlas-batch-calls-are-not-always-faster.aspx#comments</comments><description>&lt;p&gt;Atlas provides you 
&lt;a href="http://atlas.asp.net/docs/atlas/doc/services/consuming.aspx"&gt;
batch call feature&lt;/a&gt; which combines multiple web service calls
into one call. It works transparently, you won&amp;#39;t notice anything
nor do you need not write any special code. Once you turn on the
Batch feature, all web service calls made within a duration gets
batched into one call. Thus saves roundtrip time and total response
time.&lt;/p&gt;
&lt;p&gt;The actual response time might be reduced but the perceived
delay is higher. If 3 web service calls are batched, the 1st call
does not finish first. All 3 calls finish at the same time. If you
are doing some UI updates upon completion of each WS calls, it does
not happen one by one. All of the calls complete in one shot and
then the UI gets updated in one shot. As a result, you do not see
incremental updates on the UI, instead a long delay before the UI
updates. If any of the call, say the 3rd call downloads a lot of
data, user sees nothing happening until all 3 calls complete. So,
the duration of the 1st call becomes nearly the duration of the sum
of all 3 calls. Although actual total duration is reduced, but the
perceived duration is higher. Batch calls are handy when each call
is transmitting small amount of data. Thus 3 small calls gets
executed in one roundtrip.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s work on a scenario where 3 calls are made one by one.
Here&amp;#39;s how the calls actually get executed.&lt;/p&gt;
&lt;p&gt;
&lt;img height="156" src="http://omar.mvps.org/images/Atlas3Atlasbatchcallsarenotalwaysfaster_13523/clip_image001.png" width="786" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;The second call takes a bit time to reach the server because
first call is eating up bandwidth. The same reason it takes longer
to download. Browsers open 2 simultaneous connections to the
server. So at a time, only 2 calls are made. Once the second/first
call completes, the third call is made.&lt;/p&gt;
&lt;p&gt;When these 3 calls are batched into one:&lt;/p&gt;
&lt;p&gt;
&lt;img height="69" src="http://omar.mvps.org/images/Atlas3Atlasbatchcallsarenotalwaysfaster_13523/clip_image002.png" width="687" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;Here the total download time is reduced (if IIS compression
enabled) and there&amp;#39;s only one network latency overhead. All 3 calls
get executed on the server in one shot and the combined response is
downloaded in one call. But to the user, the perceived speed is
slower because all the UI update happens after the entire batch
call completes. The total duration the batch call will take to
complete will always be higher than 2 calls. Moreover, if you do a
lot of UI update one after another, Internet Explorer freezes for a
while giving user a bad impression. Sometimes expensive update on
the UI makes the browser screen go blank and white. But Firefox and
Opera does not have this problem.&lt;/p&gt;
&lt;p&gt;Batch call has some advantages too. Total download time is less
than downloading individual call responses because if you use gzip
compression in IIS, the total result is compressed instead of
individually compressing each result. So, generally batch call is
better for small calls. But if a call is going to send a large
amount of data or is going to return say 20KB of response, then
it&amp;#39;s better not to use batch. Another problem with batch call is,
say 2 calls are very small but the 3rd call is quite big. If these
3 call gets batched, the smaller calls are going to suffer from
long delay due to the 3rd larger call.&lt;/p&gt;
&lt;img src="http://msmvps.com/aggbug.aspx?PostID=137636" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net+ajax/default.aspx">asp.net ajax</category></item><item><title>Atlas 2: HTTP POST is slower and it's default in Atlas</title><link>http://msmvps.com/blogs/omar/archive/2006/09/22/Atlas-2_3A00_-HTTP-POST-is-slower-and-it_2700_s-default-in-Atlas.aspx</link><pubDate>Fri, 22 Sep 2006 18:11:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:136469</guid><dc:creator>omar</dc:creator><slash:comments>97</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=136469</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2006/09/22/Atlas-2_3A00_-HTTP-POST-is-slower-and-it_2700_s-default-in-Atlas.aspx#comments</comments><description>&lt;p&gt;Atlas by default makes HTTP POST for all AJAX calls. Http POST
is more expensive than Http GET. It transmits more bytes over the
wire, thus taking precious network time and it also makes ASP.NET
do extra processing on the server end. So, you should use Http Get
as much as possible. However, Http Get does not allow you to pass
objects as parameters. You can pass numeric, string and date only.
When you make a Http Get call, Atlas builds an encoded url and
makes a hit to that url. So, you must not pass too much content
which makes the url become larger than 2048 chars. As far as I
know, that&amp;#39;s what is the max length of any url.&lt;/p&gt;
&lt;p&gt;Another evil thing about http post is, it&amp;#39;s actually 2 calls.
First browser sends the http post headers and server replies with
&amp;quot;HTTP 100 Continue&amp;quot;. When browser receives this, it sends the
actual body. Here&amp;#39;s what the headers look like:&lt;/p&gt;
&lt;p&gt;Request:&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="F2210F5F-69EB-4d4c-AFF7-B8A050E9CC72:241b442a-dddf-4eca-974c-9a90c650da9b" style="padding-right:0px;display:inline;padding-left:0px;float:none;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;

&lt;div&gt;

&lt;span style="color:#000000;"&gt;POST&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;/&lt;/span&gt;
&lt;span style="color:#000000;"&gt;Atlas1&lt;/span&gt;
&lt;span style="color:#000000;"&gt;/&lt;/span&gt;
&lt;span style="color:#000000;"&gt;Default&lt;/span&gt;
&lt;span style="color:#000000;"&gt;.&lt;/span&gt;
&lt;span style="color:#000000;"&gt;aspx HTTP&lt;/span&gt;
&lt;span style="color:#000000;"&gt;/&lt;/span&gt;
&lt;span style="color:#000000;"&gt;1.1&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;__serviceMethodName&lt;/span&gt;
&lt;span style="color:#000000;"&gt;=&lt;/span&gt;
&lt;span style="color:#000000;"&gt;Timeout&amp;amp;__serviceMethodParams&lt;/span&gt;
&lt;span style="color:#000000;"&gt;=&lt;/span&gt;
&lt;span style="color:#000000;"&gt;{}&amp;amp;__VIEWSTATE&lt;/span&gt;
&lt;span style="color:#000000;"&gt;=/&lt;/span&gt;
&lt;span style="color:#000000;"&gt;wEPDwUJMTY3NTY1MjM2ZGSlWDXIdYj44hhTUd0z8yyp1q&lt;/span&gt;
&lt;span style="color:#800080;"&gt;%2&lt;/span&gt;
&lt;span style="color:#000000;"&gt;bUtw&lt;/span&gt;
&lt;span style="color:#800080;"&gt;%3&lt;/span&gt;
&lt;span style="color:#000000;"&gt;d&lt;/span&gt;
&lt;span style="color:#800080;"&gt;%3&lt;/span&gt;
&lt;span style="color:#000000;"&gt;d Response: HTTP&lt;/span&gt;
&lt;span style="color:#000000;"&gt;/&lt;/span&gt;
&lt;span style="color:#000000;"&gt;1.1&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;100&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;Continue Server: ASP&lt;/span&gt;
&lt;span style="color:#000000;"&gt;.&lt;/span&gt;
&lt;span style="color:#0000FF;"&gt;NET&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;Development Server&lt;/span&gt;
&lt;span style="color:#000000;"&gt;/&lt;/span&gt;
&lt;span style="color:#000000;"&gt;8.0&lt;/span&gt;
&lt;span style="color:#000000;"&gt;.&lt;/span&gt;
&lt;span style="color:#000000;"&gt;0.0&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;Date&lt;/span&gt;
&lt;span style="color:#000000;"&gt;: Mon&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;11&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;Sep&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;2006&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;15&lt;/span&gt;
&lt;span style="color:#000000;"&gt;:&lt;/span&gt;
&lt;span style="color:#000000;"&gt;04&lt;/span&gt;
&lt;span style="color:#000000;"&gt;:&lt;/span&gt;
&lt;span style="color:#000000;"&gt;13&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;GMT Content-Length:&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;0&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;After getting this clearance from the server, the actual body is
sent. This is done in order to prevent long posts which are not
going to succeed anyway if the server cannot accept it. But it
comes at the cost of network latency.&lt;/p&gt;
&lt;p&gt;So, Http Get should be at least twice faster than Http Post.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s how you make Http GET calls in Atlas:&lt;/p&gt;
&lt;p&gt;Step 1: Decorate web method with attribute&lt;/p&gt;
&lt;p&gt;First you need to put a special attribute on the web method:&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="F2210F5F-69EB-4d4c-AFF7-B8A050E9CC72:30628f04-16af-49fe-afa5-725fdb3738f3" style="padding-right:0px;display:inline;padding-left:0px;float:none;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;

&lt;div&gt;

&lt;span style="color:#000000;"&gt;[WebMethod] [WebOperation(&lt;/span&gt;
&lt;span style="color:#0000FF;"&gt;true&lt;/span&gt;
&lt;span style="color:#000000;"&gt;)]&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;public&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;string&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;HelloWorld() {&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;return&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;&amp;quot;&lt;/span&gt;
&lt;span style="color:#000000;"&gt;Hello World&lt;/span&gt;
&lt;span style="color:#000000;"&gt;&amp;quot;&lt;/span&gt;
&lt;span style="color:#000000;"&gt;; }&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Step 2: Set useGetMethod=true while making the call&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s how you call the web method using Http Get:&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="F2210F5F-69EB-4d4c-AFF7-B8A050E9CC72:47e751a4-470f-4a45-bdbb-b2a65c81cbec" style="padding-right:0px;display:inline;padding-left:0px;float:none;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;

&lt;div&gt;

&lt;span style="color:#000000;"&gt;WebService.HelloWorld( {
useGetMethod:&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;true&lt;/span&gt;
&lt;span style="color:#000000;"&gt;, onMethodComplete:&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;function&lt;/span&gt;
&lt;span style="color:#000000;"&gt;(result) { debug.dump(result); } }
);&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Note: It needs to be a web service (.asmx). It will not work if
you use it on page methods.&lt;/p&gt;
&lt;p&gt;Please see this 
&lt;a href="http://atlas.asp.net/docs/atlas/doc/services/consuming.aspx"&gt;
page in Atlas Quickstart&lt;/a&gt; for further info.&lt;/p&gt;
&lt;img src="http://msmvps.com/aggbug.aspx?PostID=136469" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net+ajax/default.aspx">asp.net ajax</category></item><item><title>Atlas 1: Try not to use page methods</title><link>http://msmvps.com/blogs/omar/archive/2006/09/22/Atlas-1_3A00_-Try-not-to-use-page-methods.aspx</link><pubDate>Fri, 22 Sep 2006 18:08:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:136467</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=136467</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2006/09/22/Atlas-1_3A00_-Try-not-to-use-page-methods.aspx#comments</comments><description>&lt;p&gt;One of the easiest thing in Atlas is to use the 
&lt;a href="http://atlas.asp.net/docs/atlas/doc/services/exposing.aspx#webpage"&gt;
Page Method&lt;/a&gt; feature. If you use Atlas on your web page say
Default.aspx, you can directly call public methods on Default.aspx
from javascript. Just put a [WebMethod] attribute on a public
method in Default.aspx and then you can them from Javascript using
PageMethods.MethodName().&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="F2210F5F-69EB-4d4c-AFF7-B8A050E9CC72:2a79672c-070c-46f0-af3f-7c5dd3c08df1" style="padding-right:0px;display:inline;padding-left:0px;float:none;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;

&lt;div&gt;

&lt;span style="color:#0000FF;"&gt;public&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;partial&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;class&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;_Default : System.Web.UI.Page
{&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;protected&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;void&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;Page_Load(&lt;/span&gt;
&lt;span style="color:#0000FF;"&gt;object&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;sender, EventArgs e) { }
[WebMethod]&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;public&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;string&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;DoSomething(&lt;/span&gt;
&lt;span style="color:#0000FF;"&gt;string&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;param) {&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;return&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;param; } }&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;On the client side you can call this method like this:&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="F2210F5F-69EB-4d4c-AFF7-B8A050E9CC72:c9e2b7e3-eb7c-4b1d-847e-b4a750a07354" style="padding-right:0px;display:inline;padding-left:0px;float:none;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;

&lt;div&gt;

&lt;span style="color:#000000;"&gt;PageMethods.DoSomething(&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;&amp;#39;&lt;/span&gt;
&lt;span style="color:#000000;"&gt;Hi&lt;/span&gt;
&lt;span style="color:#000000;"&gt;&amp;#39;&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;function&lt;/span&gt;
&lt;span style="color:#000000;"&gt;(result) { alert(result); }
);&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here&amp;#39;s the catch, Page method calls are always HTTP POST calls.
You can never make HTTP GET call to the Page methods but you can
make HTTP GET calls to Web service method. So, on later stage of
your project when you will need Http response caching in order to
save roundtrips, you will have to refactor all page methods to web
service methods and for this you will have to move all public
methods and related code from default.aspx to some web service. So,
try not to use Page methods from Day 1.&lt;/p&gt;
&lt;img src="http://msmvps.com/aggbug.aspx?PostID=136467" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net+ajax/default.aspx">asp.net ajax</category></item><item><title>Beginning Atlas series: Why Atlas?</title><link>http://msmvps.com/blogs/omar/archive/2006/09/18/Beginning-Atlas-series_3A00_-Why-Atlas_3F00_.aspx</link><pubDate>Mon, 18 Sep 2006 05:51:06 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:131049</guid><dc:creator>omar</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=131049</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2006/09/18/Beginning-Atlas-series_3A00_-Why-Atlas_3F00_.aspx#comments</comments><description>&lt;p&gt;&lt;/p&gt; &lt;p&gt;This is the first question everyone asks me when they see &lt;a href="http://www.pageflakes.com/"&gt;Pageflakes&lt;/a&gt;. Why not Protopage or Dojo library? Microsoft Atlas is a very promising AJAX library. They are putting a lot of effort on Atlas, making lots of reusable components that can really save you a lot of time and give your web application a complete face lift at reasonably low effort on changes. It integrated with ASP.NET v very well and it is compatible with ASP.NET Membership and Profile provider.&amp;nbsp;  &lt;p&gt;When we first started developing Pageflakes, Atlas was&amp;nbsp;in infant stage. We were only able to use the Page Method and Webservice Method call feature of Atlas. We had to make our own drag &amp;amp; drop, component architecture, popups, collapse/expand features etc. But now you can have all these from Atlas and thus save a lot of development time. The web service proxy feature of Atlas is a marvel. You can point a &amp;lt;script&amp;gt; tag to a .asmx file and you get a javascript class generated right out of the web service definition. The Javascript class contains the exact methods that you have on the web service class. This makes it really easy to add/remove new webservices, add/remove methods in webservices which does not require any changes on the client side. It also offers a lot of control over the AJAX calls and&amp;nbsp;provides rich exception trapping feature on the javascript. Server side exceptions are nicely thrown to client side javascript code and you can trap it and show nicely formatted error messages to the user. Atlas works really well with ASP.NET 2.0 eliminating the integration problem completely. You need not worry about authentication and authorization on page methods and web service methods. So, you save a lot of code on the client side (of course Atlas Runtime is huge for this reason) and you can concentrate more on your own code then building up all these framework related codes.  &lt;p&gt;Recent version of Atlas works nicely with ASP.NET Membership and Profile services giving you login/logout features from Javascript without requiring page postbacks and you can read/write Profile object directly from Javascript. This comes very handy when you heavily use ASP.NET membership and profile providers in your web application which we do at Pageflakes.  &lt;p&gt;On earlier versions of Atlas, there was no way to make HTTP GET calls. All calls were HTTP POST and thus quite expensive calls. Now you can say which calls should be HTTP GET. Once you have HTTP GET, you can utilize Http response caching features which I will explain soon.  &lt;p&gt;I will be writing about lots of Atlas tips and tricks. I am assuming you are familiar with Atlas and you have already tried some quick start tutorials and you know the concepts of Page Method, Web service Proxy, Script Manager etc.&lt;/p&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=131049" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net+ajax/default.aspx">asp.net ajax</category></item><item><title>String and Array extensions in Atlas Runtime - a StringBuilder too!</title><link>http://msmvps.com/blogs/omar/archive/2006/08/02/string-and-array-extensions-in-atlas-runtime-a-stringbuilder-too.aspx</link><pubDate>Wed, 02 Aug 2006 12:40:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:106484</guid><dc:creator>omar</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=106484</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2006/08/02/string-and-array-extensions-in-atlas-runtime-a-stringbuilder-too.aspx#comments</comments><description>&lt;p&gt;Atlas runtime extends the String class of Javascript with the
following handy extensions:&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New" size="2"&gt;String.prototype.endsWith=function(suffix){
&lt;br /&gt;String.prototype.startsWith=function(prefix){
&lt;br /&gt;String.prototype.lTrim=String.prototype.trimLeft=function(){
&lt;br /&gt;String.prototype.rTrim=String.prototype.trimRight=function(){
&lt;br /&gt;String.prototype.trim=function(){
&lt;br /&gt;String.format=function(format){&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;Format one is pretty powerful. You can build complex strings
very efficiently:&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New" size="2"&gt;var result = String.format(&amp;quot;Hello
{0} My name {1} {2}&amp;quot;, param1, param2, param3);&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;It also has a StringBuilder just like .NET. If you are building
a string of HTML anywhere which has more than 10 concatenation, use
StringBuilder. Concatenations are like:&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New" size="2"&gt;Html = &amp;quot;....&amp;quot; + &amp;quot;....&amp;quot; + &amp;quot;....&amp;quot; +
&amp;quot;....&amp;quot;;&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New" size="2"&gt;Or&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New" size="2"&gt;Html += &amp;quot;.....&amp;quot;;&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;If you are doing things like this in loops, you must use
StringBuilder. Javascript string concatenation is very very
slow.&lt;/p&gt;
&lt;p&gt;StringBuilder is defined as:
&lt;br /&gt;
&lt;br /&gt;
&lt;font face="Courier New" size="2"&gt;Sys.StringBuilder=function(initialText){
&lt;br /&gt;&amp;nbsp;this.append=function(text){
&lt;br /&gt;&amp;nbsp;this.appendLine=function(text){
&lt;br /&gt;&amp;nbsp;this.clear=function(){
&lt;br /&gt;&amp;nbsp;this.toString=function(delimiter){&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s how you use it:&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New" size="2"&gt;var builder = new
Sys.StringBuilder(&amp;quot;Initial text, or leave blank&amp;quot;);
&lt;br /&gt;builder.append(&amp;quot;more text&amp;quot;);
&lt;br /&gt;var result = builder.toString();&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;The Array class is pretty rich. It has the following public
methods:&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New" size="2"&gt;Array.prototype.add=function(item)
&lt;br /&gt;Array.prototype.addRange=function(items)
&lt;br /&gt;Array.prototype.clear=function()
&lt;br /&gt;Array.prototype.clone=function()
&lt;br /&gt;Array.prototype.contains=Array.prototype.exists=function(item)
&lt;br /&gt;Array.prototype.dequeue=function()
&lt;br /&gt;Array.prototype.indexOf=function(item,startIndex)
&lt;br /&gt;Array.prototype.insert=function(index,item)
&lt;br /&gt;Array.prototype.remove=function(item)
&lt;br /&gt;Array.prototype.removeAt=function(index)
&lt;br /&gt;Array.parse=function(value)&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;All these functions are equivalent to .NET Array and String
class. So, I am not explaining in details what they do.
&lt;br /&gt;&lt;/p&gt;
&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=106484" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net+ajax/default.aspx">asp.net ajax</category></item></channel></rss>