<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7923925041222581283</id><updated>2011-07-31T03:19:55.865-07:00</updated><category term='Global Village For Knowledge Sharing'/><title type='text'>YOGENDRA</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://helloyogendra.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7923925041222581283/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://helloyogendra.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>yogendra</name><uri>http://www.blogger.com/profile/17352040371528808178</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://3.bp.blogspot.com/_HAPjfdF1UaM/STe2FmgLKsI/AAAAAAAAAD0/2We-ihnll1A/S220/11.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>1</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7923925041222581283.post-603537851565690585</id><published>2008-12-04T21:22:00.001-08:00</published><updated>2009-11-12T08:41:31.281-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Global Village For Knowledge Sharing'/><title type='text'>Technology in our Hands : So let us raise your hands to make a team effort.</title><content type='html'>&lt;span style="font-size:180%;"&gt;&lt;span style="color:#3333ff;"&gt;&lt;strong&gt;&lt;a href="http://1.bp.blogspot.com/_HAPjfdF1UaM/STjCiDVK9zI/AAAAAAAAAF0/3dzSX1NplFg/s1600-h/gg.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5276180853729982258" style="WIDTH: 121px; CURSOR: hand; HEIGHT: 109px" alt="" src="http://1.bp.blogspot.com/_HAPjfdF1UaM/STjCiDVK9zI/AAAAAAAAAF0/3dzSX1NplFg/s320/gg.jpg" border="0" /&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:130%;color:#000066;"&gt;&lt;strong&gt;&lt;u&gt;Blog for all guys who are working with Microsoft.Net Technologies or interested to make their career as a Microsoft.Net Developer. &lt;/u&gt;&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;u&gt;&lt;span style="color:#006600;"&gt;Microsoft.Net Framework = (Ver. - 2.0/3.0/3.5) &lt;/span&gt;&lt;/u&gt;&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;u&gt;&lt;span style="color:#006600;"&gt;(CLR, CLS, CTS, CLI, MSIL, JIT, GC)&lt;br /&gt;C#.Net, VB.Net, ASP.Net, ADO.Net, AJAX.Net, SilverLight, WCF, WPF, WWF, Winforms, LINQ, SharePoint.&lt;/span&gt;&lt;/u&gt;&lt;br /&gt;&lt;/strong&gt;&lt;u&gt;&lt;span style="color:#006600;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/u&gt;.&lt;strong&gt;&lt;u&gt;&lt;span style="color:#cc0000;"&gt;NET Application performance Tips and Tricks:&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/u&gt;&lt;span style="color:#ff6600;"&gt;Changes have to be Done in Web.Config and Mechine.config File:&lt;/span&gt; &lt;/u&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;1.Set debug=false under compilation as follows:- When you create the application, by default this attribute is set to "true" which is very useful while developing. However,when you are deploying your application, always set it to "false" Setting it to "true" requires the pdb information to be inserted into the file and this results in a comparatively larger file and hence processing will be slow.&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt; 2. Turn off Tracing unless until required. Tracing is one of the wonderful features which enable us to track the application's trace and the sequences. However, again it is useful only for developers and you can set this to "false" unless you require to monitor the trace logging. Before you deploy your application, disable tracing and debugging. Tracing and debugging may cause performance issues. Tracing and debugging are not recommended while your application is running in production. You can disable tracing and debugging in the Machine.config and Web.config using the syntax below. You can turn off tracing as follows:-&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt; 3. Turn off Session State, if not required. ASP.NET Manages session state automatically. However, in case you dont require Sessions, disabling it will help in improving the performance. You may not require seesion state when ur pages r static or whn u dont need to store infor captured in the page. You can turn off session state as follows:- For doing it in Page wise Changes have to be Done when building .NET Application-&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt; 4. Select the Release mode before making the final Build for your application. This option is available in the Top Frame just under the Window Menu option. By default, the Mode is Debug There are several things happening when you Build/Re-Build applications in the Debug Mode. First of all, it creates an additional PDB File under your BIN directory. This holds all the Debug information. Secondly, the Timeout is very high since you require higher time out frequency while debugging such that your process hangs on until you get to the exact break point where error is there. So, selecting Release Mode will greatly improve the performance of the application when u deploy. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;&lt;u&gt;&lt;span style="color:#000066;"&gt;General Methods to improve the Performance of Web Application&lt;/span&gt;&lt;/u&gt;&lt;/strong&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;strong&gt;&lt;u&gt;&lt;/u&gt;&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt; 5. Disable ViewState when not required. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;6. Avoid Frequent round trips to the Database. Calls made to Database can be quite expensive in terms of response time as well as resources and it can be avoided by using Batch Processing. Make calls to Database as mininal as possible and make them last even lesser time. Use of DataAdapter wherever applicable is very useful since, it automatically opens and closes Connection whenever required and doesnt require user to explicitly open the connection. A number of connections opened and not closed adequately can directly influence in performance slow down. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;7. Avoid Throwing Exceptions. It is very expensive. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;8. Use Caching to improve the performance of your application. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;9. Use appropriate Authentication Mechanism. The Authentication Mechanism you choose determines the cost associated with it and hence select the appropriate mechanism. An informal but useful order is as follows:- &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;Authentication Modes &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;1. None &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;2. Windows &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;3. Forms &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;4. Passport &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;10. Validate all Input received from the Users. Use Client Side Validations as much as possible. However, do a check at the Server side too to avoid the infamous Javascript disabled scenarios. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;11. Use Finally Method to kill resources. In your Try..Catch.. Block, always use the Finally method to close Open connections, Open DataReaders, Files and other resources such that they get executed independent of whether the code worked in Try or went to Catch. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;12. The String and Stringbuilder Usage. If you are initially creating a string say s = "Hello". Then you are appending to it as s = s + " World"; You are actually creating two instances of string in memory. Both the original as well as the new string will be stored in the memory. For that matter, all the activities you do to the string are stored in the memory as separate references and it must be avoided as much as possible. Use StringBuilder which is very useful in these kind of scenarios. For the example above, using a StringBuilder as s.Append(" World"); &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;which only stores the value in the original string and no additional reference is created. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;Eg: &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;String Action -------------- string str=""; DateTime startTime = DateTime.Now; Response.Write((" Start time:" + startTime.ToString())); int i; for(i=0;i&lt;20000;i++)&gt;"; } DateTime EndTime= DateTime.Now; Response.Write((" End time:" + EndTime.ToString())); Out Put: &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;Start time:3/22/2006 10:23:44 AM End time:3/22/2006 10:25:08 AM &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;The above code took 1 minutes and 24 Seconds to complete its operation String Builder Action:&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;StringBuilder strbuilder = new StringBuilder(); DateTime startTime1 = DateTime.Now; Response.Write((" Start time:" + startTime1.ToString())); int i1; for (i1 = 0; i1 &lt;&gt;"); } DateTime EndTime1 = DateTime.Now; Response.Write((" End time:" + EndTime1.ToString())); &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;Out Put: &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;Start time:3/22/2006 10:25:08 AM End time:3/22/2006 10:25:09 AM &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;The above code took 1 Seconds to complete its operation &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;13. Avoid Recursive Functions / Nested Loops &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;14. Enable Option Strict and Option Explicit for your pages. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;15. Use early binding in Visual Basic or JScript code. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;16. Use Response.Write for String concatenation: Use the HttpResponse.Write method in your pages or user controls for string concatenation. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;This method offers buffering and concatenation services that are very efficient. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;If you are performing extensive concatenation, however, the technique in the following example, using multiple calls to Response.Write, is faster than concatenating a string with a single call to the Response.Write method. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;Response.Write("a"); &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;Response.Write(myString); &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;Response.Write("b"); &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;Response.Write(myObj.ToString()); &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;Response.Write("c"); &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;Response.Write(myString2); &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;Response.Write("d"); &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;17. Avoid unnecessary round trips to the server: &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;Use Page.IsPostback to avoid extra work on a round trip. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;� Implement Ajax UI whenever possible. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;The idea is to avoid full page refresh and only update the portion of the page that needs to be changed. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;I think Scott's article gave great information on how to implement Ajax Atlas and control. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;� Use Client Side Scripts. Client site validation can help reduce round trips that are required to process user&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;�Isrequest. In ASP.NET you can also use client side controls to validate user input.&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;� Use Page.ISPostBack property to ensure that you only perform page initialization logic when a page first time loaded and not in response to client postbacks. If Not IsPostBack Then LoadJScripts() End If &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;� In some situations performing postback event handling are unnecessary. You can use client callbacks to read data from the server instead of performing a full round trip. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;18. Keep IO Buffer Size Between 4KB and 8KB For nearly every application, a buffer between 4KB and 8KB will give you the maximum performance. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;For very specific instances, you may be able to get an improvement from a larger buffer (loading large images of a predictable size, for example), but in 99.99% of cases it will only waste memory. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;All buffers derived from BufferedStream allow you to set the size to anything you want, but in most cases 4 and 8 will give you the best performance &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;19. Minimize the Use of Format() When you can, use toString() instead of format(). &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;In most cases, it will provide you with the functionality you need, with much less overhead. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;20. Optimize Assignments Use exp += val instead of exp = exp + val. Since exp can be arbitrarily complex, this can result in lots of unnecessary work. This forces the JIT to evaluate both copies of exp, and many times this is not needed. The first statement can be optimized far better than the second, since the JIT can avoid evaluating the exp twice. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;21. Include Return Statements with in the Function&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;22. Use For Loops for String Iteration &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;23. Explicitly Dispose or Close all the resources: Try _con.Open() Catch ex As Exception Throw ex Finally If Not _con Is Nothing Then _con.Close() End If End Try &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;24. Precompiling pages and disabling AutoEventWireup: &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;By precompiled pages, users do not have to experience the batch compile of your ASP.NET files; it will increase the performance that your users will experience. Also setting the AutoEventWireup attribute to false in the Machine.config file means that the page will not match method names to events and hook them up (for example, Page_Load). &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;If page developers want to use these events, they will need to override the methods in the base class (for example, they will need to override Page.OnLoad for the page load event instead of using a Page_Load method). &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;If you disable AutoEventWireup, your pages will get a slight performance boost by leaving the event wiring to the page author instead of performing it automatically. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;Database--------&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;1.Use the Optimal Managed Provider &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;2.Use Stored Procedures Whenever Possible &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;3.Use SqlDataReader Instead of Dataset wherevr it is possible &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;4.Turn Off Features You Don't Use Turn off automatic transaction enlistment if it's not needed. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;For the SQL Managed Provider, &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;it's done via the connection string: SqlConnection conn = new SqlConnection("Server=mysrv01;Integrated Security=true;Enlist=false"); When filling a dataset with the data adapter, don't get primary key information if you don't have to (e.g. don't set MissingSchemaAction.Add with key): public DataSet SelectSqlSrvRows(DataSet dataset,string connection,string query){ SqlConnection conn = new SqlConnection(connection); SqlDataAdapter adapter = new SqlDataAdapter(); adapter.SelectCommand = new SqlCommand(query, conn); adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey; adapter.Fill(dataset); return dataset; }&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;4.Keep Your Datasets Lean Only put the records you need into the dataset. Remember that the dataset stores all of its data in memory, and that the more data you request, the longer it will take to transmit across the wire. 5.Use Connection Pooling and Object Pooling&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#663300;"&gt;&lt;strong&gt;&lt;u&gt;&lt;/u&gt;&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:130%;color:#663300;"&gt;&lt;strong&gt;&lt;u&gt;Ten ASP.NET Performance and Scalability Secrets:&lt;/u&gt;&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;span style="font-size:130%;"&gt;&lt;strong&gt;&lt;u&gt;Introduction:&lt;/u&gt;&lt;/strong&gt;&lt;/span&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;ASP.NET 2.0 has many secrets, which when revealed can give you big performance and scalability boost.&lt;br /&gt;For instance, there are secret bottlenecks in Membership and Profile provider which can be solved easily to make authentication and authorization faster.&lt;br /&gt;Furthermore, ASP.NET HTTP pipeline can be tweaked to avoid executing unnecessary code that gets hit on each and every request.&lt;br /&gt;Not only that, ASP.NET Worker Process can be pushed to its limit to squeeze out every drop of performance out of it.&lt;br /&gt;Page fragment output caching on the browser (not on the server) can save significant amount of download time on repeated visits.&lt;br /&gt;On demand UI loading can give your site a fast and smooth feeling. Finally, Content Delivery Networks (CDN) and proper use of HTTP Cache headers can make your website screaming fast when implemented properly. In this article, you will learn these techniques that can give your ASP.NET application a big performance and scalability boost and prepare it to perform well under 10 times to 100 times more traffic.&lt;br /&gt;&lt;br /&gt;In this article we will discuss the following techniques:&lt;br /&gt;&lt;br /&gt;ASP.NET pipeline optimization:&lt;br /&gt;&lt;br /&gt;ASP.NET process configuration optimization&lt;br /&gt;&lt;br /&gt;Things you must do for ASP.NET before going live&lt;br /&gt;&lt;br /&gt;Content Delivery Network&lt;br /&gt;&lt;br /&gt;Caching AJAX calls on browser&lt;br /&gt;&lt;br /&gt;Making best use of Browser Cache&lt;br /&gt;&lt;br /&gt;On demand progressive UI loading for fast smooth experience&lt;br /&gt;&lt;br /&gt;Optimize ASP.NET 2.0 Profile provider&lt;br /&gt;&lt;br /&gt;How to query ASP.NET 2.0 Membership tables without bringing down the site&lt;br /&gt;&lt;br /&gt;Prevent Denial of Service (DOS) attack&lt;br /&gt;&lt;br /&gt;The above techniques can be implemented on any ASP.NET website, especially those who use&lt;br /&gt;ASP.NET 2.0's Membership and Profile provider.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;strong&gt;&lt;span style="color:#660000;"&gt;&lt;u&gt;ASP.NET Pipeline Optimization:&lt;/u&gt;&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;There are several ASP.NET default HttpModules which sit in the request pipeline and intercept each and every request. &lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;For example, SessionStateModule intercepts each request, parses the session cookie and then loads the proper session in the HttpContext. Not all of these modules are always necessary. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;For example, if you aren't using Membership and Profile provider, you don't need FormsAuthentication module. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;If you aren't using Windows Authentication for your users, you don't need WindowsAuthentication. These modules are just sitting in the pipeline, executing some unnecessary code for each and every request. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;The default modules are defined in machine.config file (located in the $WINDOWS$\Microsoft.NET\Framework\$VERSION$\CONFIG directory).&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;httpmodules&gt;&lt;add type="System.Web.Caching.OutputCacheModule" name="OutputCache"&gt;&lt;add type="System.Web.SessionState.SessionStateModule" name="Session"&gt;&lt;add type="System.Web.Security.WindowsAuthenticationModule" name="WindowsAuthentication"&gt;&lt;add type="System.Web.Security.FormsAuthenticationModule" name="FormsAuthentication"&gt;&lt;add type="System.Web.Security.PassportAuthenticationModule" name="PassportAuthentication"&gt;&lt;add type="System.Web.Security.UrlAuthorizationModule" name="UrlAuthorization"&gt;&lt;add type="System.Web.Security.FileAuthorizationModule" name="FileAuthorization"&gt;&lt;add type="System.Web.Mobile.ErrorHandlerModule, System.Web.Mobile, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" name="ErrorHandlerModule"&gt;&lt;/httpmodules&gt;&lt;br /&gt;You can remove these default modules from your Web application by adding &lt;remove&gt;nodes in your site's web.config. For example:&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;httpmodules&gt;&lt;!-- Remove unnecessary Http Modules for faster pipeline --&gt;&lt;remove name="Session"&gt;&lt;remove name="WindowsAuthentication"&gt;&lt;remove name="PassportAuthentication"&gt;&lt;remove name="AnonymousIdentification"&gt;&lt;remove name="UrlAuthorization"&gt;&lt;remove name="FileAuthorization"&gt;&lt;/httpmodules&gt;&lt;br /&gt;The above configuration is suitable for websites that use database based Forms Authentication and do not need any Session support. So, all these modules can safely be removed. &lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;&lt;strong&gt;&lt;u&gt;&lt;span style="color:#000066;"&gt;ASP.NET Process Configuration Optimization :&lt;/span&gt;&lt;br /&gt;&lt;/u&gt;&lt;/strong&gt;ASP.NET Process Model configuration defines some process level properties like how many number of threads ASP.NET uses, how long it blocks a thread before timing out, how many requests to keep waiting for IO works to complete and so on.&lt;br /&gt;&lt;br /&gt;The default is in many cases too limiting. Nowadays hardware has become quite cheap and dual core with gigabyte RAM servers have become a very common choice. So, the process model configuration can be tweaked to make ASP.NET process consume more system resources and provide better scalability from each server.&lt;br /&gt;&lt;br /&gt;A regular ASP.NET installation will create machine.config with the following configuration:&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;system.web&gt;&lt;processmodel autoconfig="true"&gt;&lt;br /&gt;You need to tweak this auto configuration and use some specific values for different attributes in order to customize the way ASP.NET worker process works. &lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;Here all the values are default values except for the following ones:&lt;br /&gt;&lt;br /&gt;maxWorkerThreads - This is default to 20 per process. On a dual core computer, there'll be 40 threads allocated for ASP.NET. This means at a time ASP.NET can process 40 requests in parallel on a dual core server.&lt;br /&gt;&lt;br /&gt;I have increased it to 100 in order to give ASP.NET more threads per process. If you have an application which is not that CPU intensive and can easily take in more requests per second, then you can increase this value. Especially if your Web application uses a lot of Web service calls or downloads/uploads a lot of data which does not put pressure on the CPU.&lt;br /&gt;&lt;br /&gt;When ASP.NET runs out of worker threads, it stops processing more requests that come in. Requests get into a queue and keeps waiting until a worker thread is freed. This generally happens when site starts receiving much more hits than you originally planned. In that case, if you have CPU to spare, increase the worker threads count per process.&lt;br /&gt;&lt;br /&gt;maxIOThreads - This is default to 20 per process. On a dual core computer, there'll be 40 threads allocated for ASP.NET for I/O operations. This means at a time ASP.NET can process 40 I/O requests in parallel on a dual core server. I/O requests can be file read/write, database operations, web service calls, HTTP requests generated from within the Web application and so on. So, you can set this to 100 if your server has enough system resource to do more of these I/O requests. Especially when your Web application downloads/uploads data, calls many external webservices in parallel.&lt;br /&gt;&lt;br /&gt;minWorkerThreads - When a number of free ASP.NET worker threads fall below this number, ASP.NET starts putting incoming requests into a queue. So, you can set this value to a low number in order to increase the number of concurrent requests. However, do not set this to a very low number because Web application code might need to do some background processing and parallel processing for which it will need some free worker threads.&lt;br /&gt;&lt;br /&gt;minIOThreads - Same as minWorkerThreads but this is for the I/O threads. However, you can set this to a lower value than minWorkerThreads because there's no issue of parallel processing in case of I/O threads.&lt;br /&gt;&lt;br /&gt;memoryLimit - Specifies the maximum allowed memory size, as a percentage of total system memory, that the worker process can consume before ASP.NET launches a new process and reassigns existing requests.&lt;br /&gt;&lt;br /&gt;If you have only your Web application running in a dedicated box and there's no other process that needs RAM, you can set a high value like 80. However, if you have a leaky application that continuously leaks memory, then it's better to set it to a lower value so that the leaky process is recycled pretty soon before it becomes a memory hog and thus keep your site healthy.&lt;br /&gt;&lt;br /&gt;Especially when you are using COM components and leaking memory. However, this is a temporary solution, you of course need to fix the leak.&lt;br /&gt;Besides the processModel, there's another very important section with the system.net where you can specify the maximum number of outbound requests that can be made to a single IP.&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;system.net&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;Default is 2, which is just too low. This means you cannot make more than 2 simultaneous connections to an IP from your Web application. Sites that fetch external content a lot suffer from congestion due to the default setting. Here I have set it to 100. If your Web applications make a lot of calls to a specific server, you can consider setting an even higher value.&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;&lt;strong&gt;&lt;u&gt;&lt;span style="color:#003333;"&gt;Things You Must Do for ASP.NET Before Going Live&lt;/span&gt;&lt;/u&gt;&lt;/strong&gt;&lt;br /&gt;You should do some tweaking on your web.config if you are using ASP.NET 2.0 Membership Provider before you go live on your production server: &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;Add applicationname attribute in Profile Provider. If you do not add a specific name here, Profile provider will use a GUID. So, on your local machine you will have one GUID and on the production server you will have another GUID.&lt;br /&gt;If you copy your local DB to the production server, you won't be able to reuse the records available in your local DB and ASP.NET will create a new application on production. Here's where you need to add it.&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;&lt;providers&gt;&lt;clear&gt;&lt;add description="..." type="System.Web.Profile.SqlProfileProvider" name="..." connectionstringname="..." applicationname="YourApplicationName"&gt;&lt;/providers&gt;&lt;br /&gt;Profile provider will automatically save the profile whenever a page request completes. So, this might result in an unnecessary UPDATE on your DB which has significant performance penalty. So, turn off automatic save and do it explicitly from your code using Profile.Save(); &lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;Role Manager always queries the database in order to get the user roles. This has significant performance penalty. You can avoid this by letting the Role Manager cache role information on a cookie. But this will work for users who do not have a lot of roles assigned to them which exceeds the 2 KB limit of Cookie. But it's not a common scenario. So, you can safely store role info on a cookie and save one DB roundtrip on every request to *.aspx and *.asmx.&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;rolemanager enabled="true" cacherolesincookie="true"&gt;&lt;br /&gt;&lt;strong&gt;&lt;u&gt;&lt;span style="color:#000066;"&gt;The above three settings are must haves for high volume websites.&lt;br /&gt;Content Delivery Network&lt;/span&gt;&lt;/u&gt;&lt;/strong&gt;&lt;br /&gt;Every request from a browser goes to your server traveling through the Internet backbones that span the world. The number of countries, continents, oceans a request has to go through to reach your server, the slower it is. For example, if you have your servers in USA and someone from Australia is browsing your site, each request is literary crossing the planet from one end to the other in order to reach your server and then come back again to the browser. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;If your site has large number of static files like images, CSS, JavaScript; sending request for each of them and downloading them across the world takes a significant amount of time. If you could setup a server in Australia and redirect users to your Australian server, then each request would take fraction of the time it takes to reach USA. Not only the network latency will be lower but also the data transfer rate will be faster and thus static content will download a lot faster. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;This will give significant performance improvement on the users end if your website is rich in static content. Moreover, ISPs provide far greater speed for country wide network compared to the Internet because each country generally has handful of connectivity to the Internet backbone that is shared by all ISPs within the country. As a result, users having 4 MBPS broadband connection will get the full 4 MBPS speed from servers that are within the same country. But they will get as low as 512 KBPS from servers which are outside the country. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;Thus having a server in the same country significantly improves site download speed and responsiveness. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;Besides improving site load speed, CDN also offloads traffic from your Web servers. As it deals with static cacheable content, your webservers rarely get hits for those content. Thus hits going to your webservers drop significantly and webservers free up more resource to process dynamic requests. Your webservers also save a lot of IIS log space because IIS need not log requests for the static contents. If you have a lot of graphics, CSS and JavaScript on your website, you can save gigabytes of IIS logs every day.&lt;br /&gt;&lt;br /&gt;Above figure shows average response time for &lt;/span&gt;&lt;a href="http://www.pageflakes.com/" mce_href="http://www.pageflakes.com/"&gt;&lt;span style="color:#ff6600;"&gt;www.pageflakes.com&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt; from Washington, DC, where the servers are in Dallas, Texas. The average response time is around 0.4 seconds. This response includes server side execution time as well. Generally it takes around 0.3 to 0.35 seconds to execute the page on the server. So, time spent on the network is around 0.05 seconds or 50ms. This is a really fast connectivity as there are only 4 to 6 hops to reach Dallas from Washington DC. &lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;This&lt;/a&gt; figure shows average response time from Sydney, Australia. The average response time is 1.5 seconds which is significantly higher than that of Washington DC. It�s almost 4 times compared to USA. There's almost 1.2 seconds overhead on network only. Moreover, there are around 17 to 23 hops from Sydney to Dallas. So, the site downloads at least 4 times slower in Australia than it is from anywhere in USA.&lt;br /&gt;&lt;br /&gt;A content delivery network (CDN) is a system of computers networked together across the Internet. The computers cooperate transparently to deliver content (especially large media content) to end users. CDN nodes (cluster of servers in a specific location) are deployed in multiple locations, often over multiple backbones. These nodes cooperate with each other to serve requests for content by end users. They also transparently move content behind the scenes to optimize the delivery process. CDN serves requests by intelligently choosing the nearest server. It looks for the fastest connectivity between your computer to a nearest node that has the content you are looking for.&lt;br /&gt;&lt;br /&gt;The number of nodes in different countries and the number of redundant backbone connectivity a CDN has measures its strength. Some of the most popular CDNs are Akamai, Limelight, EdgeCast. Akamai is used by large companies like Microsoft, Yahoo, AOL. It�s a comparatively expensive solution. However, Akamai has the best performance throughout the world because they have servers in almost every prominent city in the world. However, Akamai is very expensive and they only accept a customer who can spend a minimum of 5K on CDN per month. For smaller companies, Edgecast is a more affordable solution.&lt;br /&gt;&lt;br /&gt;This figure shows CDN Nodes that are closest to the browser intercepts traffic and serves response. If it does not have the response in cache, it fetches it from origin server using a faster route and much more optimized connectivity than the browser�s ISP can provide. If the content is already cached, then it�s served directly from the node and no request goes to the origin server.&lt;br /&gt;&lt;br /&gt;There are generally two types of CDNs. One is where you upload content to CDN's servers via FTP and you get a subdomain in their domain like dropthings.somecdn.net. You change all the URL of static content throughout your site to download content from the CDN domain instead of the relative URL to your own domain. So, a URL like /logo.gif will be renamed to http://dropthings.somecdn.net/logo.gif. This is easy to configure but has maintenance problems.&lt;br /&gt;&lt;br /&gt;You will have to keep CDN�s store synchronized with the files all the time. Deployment becomes complicated because you need to update both your website and the CDN store at the same time. Example of such a CDN (which is very cheap) is &lt;/span&gt;&lt;a href="http://www.cachefly.com/" mce_href="http://www.cachefly.com"&gt;&lt;span style="color:#ff6600;"&gt;Cachefly&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt;.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;A more convenient approach is to store static content on your own site but use domain aliasing. You can store your content in a subdomain that points to your own domain like static.dropthings.com. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;Then you use CNAME to map that subdomain to a CDN�s nameserver like cache.somecdn.net&lt;/a&gt;. When a browser tries to resolve static.dropthigns.com, the DNS lookup request goes to the CDN nameserver. The nameserver then returns IP of a CDN node which is closest to you and can give you the best download performance. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;The browser then sends requests for files to that CDN node. When CDN node sees the request, it checks whether it has the content already cached. If it is cached, it delivers the content directly from its local store. If not, it makes a request to your server and then looks at the cache header generated in response. Based on the cache header it decides how long to cache the response in its own cache. In the meantime, the browser does not wait for CDN node to get content and return to it. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;CDN does an interesting trick on the Internet backbone to actually route requests to the origin server so that the browser gets the response directly served from origin server while CDN is updating its cache&lt;/a&gt;. Sometimes CDN act as a proxy, intercepting each request and then fetching uncached content from the origin using a faster route and optimized connectivity to the origin server. Example of such CDN is &lt;/span&gt;&lt;a href="http://edgecast.com/" mce_href="http://edgecast.com/"&gt;&lt;span style="color:#ff6600;"&gt;Edgecast&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt;.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;strong&gt;&lt;u&gt;&lt;span style="color:#006600;"&gt;Caching AJAX Calls on Browser:&lt;/span&gt;&lt;br /&gt;&lt;/u&gt;&lt;/strong&gt;Browsers can cache images, JavaScript, CSS files on a user's hard drive, and it can also cache XML HTTP calls if the call is a HTTP GET. The cache is based on the URL. If it's the same URL, and it's cached on the computer, then the response is loaded from the cache, not from the server when it is requested again. Basically, the browser can cache any HTTP GET call and return cached data based on the URL. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;If you make an XML HTTP call as HTTP GET and the 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 saves the delay of network roundtrip and download time.&lt;br /&gt;At Pageflakes, we cache the user's state so that when the user visits again the following day, the user gets a cached page which loads instantly from the browser cache, not from the server. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;Thus the second time load becomes very fast. We also cache several small parts of the page which appears on user's actions. When the user performs the same action again, a cached result is loaded immediately from the local cache and thus saves the network roundtrip time. The user gets a fast loading site and a very responsive site. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;The perceived speed increases dramatically.&lt;br /&gt;The idea is to make HTTP GET calls while making Atlas Web service calls and return some specific HTTP Response headers that tell the browser to cache the response for some specific duration. If you return the Expires header during the response, the browser will cache the XML HTTP response. There are two headers that you need to return with the response that instruct the browser to cache the response:&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#000066;"&gt;&lt;strong&gt;&lt;u&gt;Cache-Control: public :&lt;/u&gt;&lt;/strong&gt;&lt;br /&gt;&lt;/span&gt;This instructs the 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 origin server. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;There are more advanced ways to get further control over response caching. For example, here is a header that instructs the browser to cache for 60 seconds but contact the server and get a fresh response after 60 seconds. It will also prevent proxies from returning cached response when the browser local cache expires after 60 seconds. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;Cache-Control: private, must-revalidate, proxy-revalidate, max-age=60&lt;br /&gt;Let's try to produce such response headers from an ASP.NET Web service call:&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;[WebMethod][ScriptMethod(UseHttpGet=true)]&lt;br /&gt;public string CachedGet()&lt;br /&gt;{&lt;br /&gt;TimeSpan cacheDuration = TimeSpan.FromMinutes(1);&lt;br /&gt;Context.Response.Cache.SetCacheability(HttpCacheability.Public);&lt;br /&gt;Context.Response.Cache.SetExpires(DateTime.Now.Add(cacheDuration));&lt;br /&gt;Context.Response.Cache.SetMaxAge(cacheDuration);&lt;br /&gt;Context.Response.Cache.AppendCacheExtension(&lt;br /&gt;"must-revalidate, proxy-revalidate");&lt;br /&gt;return DateTime.Now.ToString();&lt;br /&gt;} &lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;This will result in the following response headers:&lt;br /&gt;The Expires header is set properly. But the problem is with the Cache-control. It is showing that max-age is set to 0 which will prevent the browser from doing any kind of caching. If you seriously want to prevent caching, you should emit such a cache-control header. Looks like exactly the opposite thing happened.&lt;br /&gt;&lt;br /&gt;The output is as usual incorrect, and not cached:&lt;br /&gt;&lt;br /&gt;There's a bug in ASP.NET 2.0 that you cannot change the max-age header. As max-age is set to 0, ASP.NET 2.0 sets the Cache-control to private because max-age = 0 means no cache is needed. So, there's no way you can make ASP.NET 2.0 return proper headers which cache the response. This is due to the ASP.NET AJAX Framework that intercepts calls to Webservices and incorrectly sets the max-age to 0 by default before executing a request.&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#006600;"&gt;&lt;strong&gt;Time for a hack. After decompiling the code of the HttpCachePolicy class:&lt;/strong&gt;&lt;/span&gt; (Context.Response.Cache object's class), I found the following code:&lt;br /&gt;Somehow, this._maxAge is getting set to 0 and the check: "if (!this._isMaxAgeSet (delta &lt; this._maxAge))" is preventing it from getting set to a bigger value.&lt;br /&gt;&lt;br /&gt;Due to this problem, we need to bypass the SetMaxAge function and set the value of the _maxAge field directly, using Reflection. Collapse&lt;/span&gt;&lt;a href="http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx#" preid="11"&gt;&lt;span style="color:#ff6600;"&gt; Copy Code&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt;[WebMethod][ScriptMethod(UseHttpGet=true)]&lt;br /&gt;public string CachedGet2()&lt;br /&gt;{&lt;br /&gt;TimeSpan cacheDuration = TimeSpan.FromMinutes(1);&lt;br /&gt;FieldInfo maxAge = Context.Response.Cache.GetType().GetField("_maxAge",&lt;br /&gt;BindingFlags.InstanceBindingFlags.NonPublic);&lt;br /&gt;maxAge.SetValue(Context.Response.Cache, cacheDuration);&lt;br /&gt;Context.Response.Cache.SetCacheability(HttpCacheability.Public);&lt;br /&gt;Context.Response.Cache.SetExpires(DateTime.Now.Add(cacheDuration));&lt;br /&gt;Context.Response.Cache.AppendCacheExtension(&lt;br /&gt;"must-revalidate, proxy-revalidate");&lt;br /&gt;return DateTime.Now.ToString();&lt;br /&gt;} &lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;This will return the following headers:&lt;br /&gt;&lt;br /&gt;Now max-age is set to 60 and thus the 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's a test output which shows the date time returned from the server:&lt;br /&gt;After 1 minute, the cache expires and the browser makes a call to the server again. The client side code is like this:&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;function testCache()&lt;br /&gt;{&lt;br /&gt;TestService.CachedGet(function(result)&lt;br /&gt;{&lt;br /&gt;debug.trace(result);&lt;br /&gt;});&lt;br /&gt;}&lt;br /&gt;There's another problem to solve. In web.config, you will see ASP.NET Ajax will add:&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;system.web&gt;&lt;trust level="Medium"&gt;&lt;br /&gt;This prevents us from setting _maxAge field of Response object because it requires Reflection. So, you will have to remove this trust level or put Full.&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;system.web&gt;&lt;trust level="Full"&gt;&lt;br /&gt;&lt;strong&gt;&lt;u&gt;&lt;span style="color:#000066;"&gt;Making Best Use of Browser Cache&lt;br /&gt;Use URLs Consistently&lt;/span&gt;&lt;/u&gt;&lt;/strong&gt;&lt;br /&gt;Browsers cache content based on the URL. When the URL changes, the browser fetches a new version from origin server. URL can be changed by changing the query string parameters. For example, /default.aspx is cached on the browser. If you request /default.aspx?123 it will fetch new content from the server. Response from the new URL can also be cached in the browser if you return proper caching headers. In that case, changing the query parameter to something else like /default.aspx?456 will return new content from the server. So, you need to make sure you use URL consistently everywhere when you want to get cached response. From homepage, if you have requested a file with URL /welcome.gif, make sure from another page you request the same file using the same URL. One common mistake is to sometimes omit the �www� subdomain from the URL. &lt;/span&gt;&lt;a href="http://www.pageflakes.com/default.aspx" mce_href="http://www.pageflakes.com/default.aspx"&gt;&lt;span style="color:#ff6600;"&gt;www.pageflakes.com/default.aspx&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt; is not same as &lt;/span&gt;&lt;a href="http://www.pageflakes.com/default.aspx" mce_href="http://www.pageflakes.com/default.aspx"&gt;&lt;span style="color:#ff6600;"&gt;pageflakes.com/default.aspx&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt;. Both will be cached separately.&lt;br /&gt;&lt;strong&gt;&lt;u&gt;&lt;span style="color:#000066;"&gt;&lt;/span&gt;&lt;/u&gt;&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;strong&gt;&lt;u&gt;&lt;span style="color:#000066;"&gt;Cache Static Content for Longer Period:&lt;/span&gt;&lt;/u&gt;&lt;/strong&gt;&lt;br /&gt;Static files can be cached for longer periods like one month. If you are thinking that you should cache for couple of days so that when you change the file, users will pick it up sooner, you're mistaken. If you update a file which was cached by Expires header, new users will immediately get the new file while old users will see the old content until it expires on their browser. So, as long as you are using Expires header to cache static files, you should use as high a value as possible.&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;For example, if you have set Expires header to cache a file for three days, one user will get the file today and store it in cache for next three days. Another user will get the file tomorrow and cache it for three days after tomorrow. If you change the file on the day after tomorrow, the first user will see it on fourth day and the second user will see it on fifth day. So, different users will see different versions of the file. As a result, it does not help setting a lower value assuming all users will pick up the latest file soon. You will have to change the URL of the file in order to ensure everyone gets the exact same file immediately.&lt;br /&gt;You can setup Expires header from static files from IIS Manager. You'll learn how to do it in a later section. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;&lt;strong&gt;&lt;u&gt;&lt;span style="color:#000066;"&gt;Use Cache Friendly Folder Structure:&lt;/span&gt;&lt;/u&gt;&lt;/strong&gt;&lt;br /&gt;Store cached content under a common folder. For example, store all images of your site under the /static folder instead of storing images separately under different subfolders. This will help you use consistent URL throughout the site because from anywhere you can use /static/images/somefile.gif. Later on, we will learn it�s easier to move to a Content Delivery Network when you have static cacheable files under a common root folder.&lt;br /&gt;Reuse Common Graphics Files&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;Sometimes we put common graphics files under several virtual directories so that we can write smaller paths. For example, say you have indicator.gif in root folder, some subfolders and under CSS folder. You did it because you need not worry about paths from different places and you could just use the file name as relative URL. This does not help in caching. Each copy of the file is cached in the browser separately. So, you should collect all graphics files in the whole solution and put them under the same root static folder after eliminating duplicates and use the same URL from all the pages and CSS files. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;&lt;strong&gt;&lt;u&gt;&lt;span style="color:#000066;"&gt;Change File Name When You Want to Expire Cache:&lt;/span&gt;&lt;/u&gt;&lt;/strong&gt;&lt;br /&gt;When you want a static file to be changed, don't just update the file because it�s already cached in the user�s browser. You need to change the file name and update all references everywhere so that browser downloads the new file. You can also store the file names in database or configuration files and use data binding to generate the URL dynamically. This way you can change the URL from one place and have the whole site receive the change immediately.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;u&gt;&lt;strong&gt;&lt;span style="color:#000066;"&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/u&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;u&gt;&lt;strong&gt;&lt;span style="color:#000066;"&gt;Use a Version Number While Accessing Static Files:&lt;/span&gt;&lt;/strong&gt;&lt;/u&gt;&lt;br /&gt;If you do not want to clutter your static folder with multiple copies of the same file, you can use query string to differentiate versions of same file. For example, a GIF can be accessed with a dummy query string like /static/images/indicator.gif?v=1. When you change the indicator.gif, you can overwrite the same file and then update all references to the file to /static/images/indicator.gif?v=2. This way you can keep changing the same file again and again and just update the references to access the graphics using the new version number. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;&lt;strong&gt;&lt;u&gt;&lt;span style="color:#000066;"&gt;Store Cacheable Files in a Different Domain:&lt;/span&gt;&lt;/u&gt;&lt;/strong&gt;&lt;br /&gt;It is always a good idea to put static contents in a different domain. First of all, the browser can open other two concurrent connections to download the static files. Another benefit is that you don't need to send the cookies to the static files. When you put the static files on the same domain as your Web application, browser sends all the ASP.NET cookies and all other cookies that your Web application is producing. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;This makes the request headers unnecessarily large and waste bandwidth. You don't need to send these cookies to access the static files. So, if you put the static files in a different domain, those cookies will not be sent. For example, put your static files in &lt;/span&gt;&lt;a href="http://www.staticcontent.com/" mce_href="http://www.staticcontent.com/"&gt;&lt;span style="color:#ff6600;"&gt;www.staticcontent.com&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt; domain while your website is running on &lt;/span&gt;&lt;a href="http://www.dropthings.com/" mce_href="http://www.dropthings.com/"&gt;&lt;span style="color:#ff6600;"&gt;www.dropthings.com&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt;. The other domain does not need to be a completely different Web site. It can just be an alias and share the same Web application path.&lt;br /&gt;SSL is Not Cached, so Minimize SSL Use &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;Any content that is served over SSL is not cached. So, you need to put static content outside SSL. Moreover, you should try limiting SSL to only secure pages like Login page or Payment page. Rest of the site should be outside SSL over regular HTTP. SSL encrypts request and response and thus puts extra load on the server. Encrypted content is also larger than the original content and thus takes more bandwidth.&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;HTTP POST Requests are Never Cached&lt;br /&gt;Cache only happens for HTTP GET requests. HTTP POST requests are never cached. So, any kind of AJAX call you want to make cacheable needs to be HTTP GET enabled. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;&lt;strong&gt;&lt;u&gt;&lt;span style="color:#000066;"&gt;Generate Content-Length Response Header:&lt;/span&gt;&lt;/u&gt;&lt;/strong&gt;&lt;br /&gt;When you are dynamically serving content via Web service calls or HTTP handlers, make sure you emit Content-Length header. Browsers have several optimizations for downloading contents faster when it knows how many bytes to download from the response by looking at the Content-Length header. Browsers can use persisted connections more effectively when this header is present. This saves the browser from opening a new connection for each request. When there is no Content-Length header, browser doesn't know how many bytes it�s going to receive from the server and thus keeps the connection open as long as it gets bytes delivered from the server until the connection closes. So, you miss the benefit of Persisted Connections that can greatly reduce download time of several small files like CS, JavaScripts, and images. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#000066;"&gt;&lt;strong&gt;&lt;u&gt;How to Configure Static Content Caching in IIS :&lt;/u&gt;&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;In IIS Manager, Web site properties dialog box has �HTTP Headers� tab where you can define Expires header for all requests that IIS handles. There you can define whether to expire content immediately or expire after certain number of days or on a specific date. The second option (Expire after) uses sliding expiration, not absolute expiration. This is very useful because it works per request. Whenever someone requests a static file, IIS will calculate the expiration date based on the number of days/months from the Expire after.&lt;br /&gt;&lt;/span&gt;&lt;a href="http://omar.mvps.org/images/Makingbestuseofcacheforbestsiteperforman_15143/clip_image001.gif" mce_href="http://omar.mvps.org/images/Makingbestuseofcacheforbestsiteperforman_15143/clip_image001.gif"&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;For dynamic pages that are served by ASP.NET, a handler can modify the Expires header and override IIS default setting. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;On Demand Progressive UI Loading for Fast Smooth Experience&lt;br /&gt;AJAX websites are all about loading as many features as possible into the browser without having any postback. If you look at the Start Pages like &lt;/span&gt;&lt;a href="http://www.pageflakes.com/" mce_href="http://www.pageflakes.com"&gt;&lt;span style="color:#ff6600;"&gt;Pageflakes&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt;, it's only one single page that gives you all the features of the whole application with zero postback. A quick and dirty approach for doing this is to deliver every possible HTML snippet inside hidden divs during page load and then make those divs visible when needed. But this makes first time loading way too slow and browser gives sluggish performance as too much stuff is there to process on the DOM. So, a better approach is to load the HTML snippet and necessary JavaScript on-demand. In my &lt;/span&gt;&lt;a href="http://www.dropthings.com/" mce_href="http://www.dropthings.com"&gt;&lt;span style="color:#ff6600;"&gt;dropthings&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt; project, &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;I have shown an example how this is done.&lt;br /&gt;When you click on the "help" link, it loads the content of the help dynamically. This HTML is not delivered as part of the default.aspx that renders the first page. Thus the giant HTML and graphics related to the help section has no effect on site load performance. It is only loaded when user clicks the "help" link. Moreover, it gets cached on the browser and thus loads only once. When user clicks the "help" link again, it's served directly from the browser cache, instead of fetching from the origin server again.&lt;br /&gt;The principle is making an XMLHTTP call to an *.aspx page, get the response HTML, put that response HTML inside a container DIV, make that DIV visible. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;AJAX Framework has a Sys.Net.WebRequest class which you can use to make regular HTTP calls. You can define HTTP method, URI, headers and the body of the call. It�s kind of a low level function for making direct calls via XMLHTTP. Once you construct a Web request, you can execute it using Sys.Net.XMLHttpExecutor.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;function showHelp()&lt;br /&gt;{&lt;br /&gt;var request = new Sys.Net.WebRequest();&lt;br /&gt;request.set_httpVerb("GET");&lt;br /&gt;request.set_url('help.aspx');&lt;br /&gt;request.add_completed( function( executor )&lt;br /&gt;{&lt;br /&gt;if (executor.get_responseAvailable())&lt;br /&gt;{&lt;br /&gt;var helpDiv = $get('HelpDiv');&lt;br /&gt;var helpLink = $get('HelpLink');&lt;br /&gt;var helpLinkBounds = Sys.UI.DomElement.getBounds(helpLink);&lt;br /&gt;helpDiv.style.top = (helpLinkBounds.y + helpLinkBounds.height) + "px";&lt;br /&gt;var content = executor.get_responseData();&lt;br /&gt;helpDiv.innerHTML = content;&lt;br /&gt;helpDiv.style.display = "block";&lt;br /&gt;}&lt;br /&gt;});&lt;br /&gt;var executor = new Sys.Net.XMLHttpExecutor();&lt;br /&gt;request.set_executor(executor);&lt;br /&gt;executor.executeRequest();&lt;br /&gt;}&lt;br /&gt;The example shows how the help section is loaded by hitting help.aspx and injecting its response inside the HelpDiv. The response can be cached by the output cache directive &lt;/a&gt;set on help.aspx. So, next time when the user clicks on the link, the UI pops up immediately. The help.aspx file has no block, only the content that is set inside the DIV&lt;/a&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;Using this approach, you can break the UI into smaller *.aspx files. Although these *.aspx files cannot have JavaScript or stylesheet blocks, they can contain large amount of HTML that you need to show on the UI on-demand. Thus you can keep initial download to absolute minimum just for loading the basic stuff. When the user explores new features on the site, load those areas incrementally.&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;div class="helpContent"&gt;&lt;div id="lipsum"&gt;&lt;p&gt;&lt;br /&gt;&lt;u&gt;&lt;strong&gt;&lt;span style="color:#000066;"&gt;Optimize ASP.NET 2.0 Profile Provider:&lt;/span&gt;&lt;/strong&gt;&lt;/u&gt;&lt;br /&gt;Do you know there are two important stored procedures in ASP.NET 2.0 Profile Provider that you can optimize significantly? If you use them without doing the necessary optimization, your servers will sink taking your business down with you during heavy load. Here's a story:&lt;br /&gt;During March, &lt;/span&gt;&lt;a href="http://www.pageflakes.com/" mce_href="http://www.pageflakes.com"&gt;&lt;span style="color:#ff6600;"&gt;Pageflakes&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt; was shown on MIX 2006. We were having a glamorous time back then. We were right on &lt;/span&gt;&lt;a href="http://atlas.asp.net/default.aspx?tabid=47&amp;amp;subtabid=472" mce_href="http://atlas.asp.net/default.aspx?tabid=47&amp;amp;subtabid=472"&gt;&lt;span style="color:#ff6600;"&gt;Showcase of Atlas Web site&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt; as the first company. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;Number of visits per day were rising sky high. One day we noticed, the database server was no more. We restarted the server, brought it back, again it died within an hour. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;After doing a lot of postmortem analysis on the remains of the server's body parts, we found that it was having 100% CPU and super high IO usage. The hard drives were over heated and turned themselves off in order to save themselves. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;This was quite surprising to us because we thought we were very intelligent back then and we used to profile every single Web service function. So, we went through hundreds of megabytes of logs hoping to find which webservice function was taking the time. We suspected one. It was the first function that loads a user's page setup. We broke it up into smaller parts in order to see which part is taking most of the time. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;private GetPageflake(string source, string pageID, string userUniqueName)&lt;br /&gt;{&lt;br /&gt;if( Profile.IsAnonymous )&lt;br /&gt;{&lt;br /&gt;using (new TimedLog(Profile.UserName,"GetPageflake"))&lt;br /&gt;{&lt;br /&gt;You see, the entire function body is timed. If you want to learn how this timing works, I will explain it in a new article. We also timed smaller parts which we suspected were taking the most resource. But we could find not a single place in our code which was taking any significant time. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;Our codebase is always super optimized (after all, you know who is reviewing it, me).&lt;br /&gt;Meanwhile, users were shouting, management was screaming, support staff was complaining on the phone. Developers were furiously sweating and blood vessels on their forehead were coming out. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;Nothing special, just a typical situation we have couple of times every month.&lt;br /&gt;Now you must be shouting, "You could have used SQL Profiler, you idiot!" We were using SQL Server workgroup edition. It does not have SQL Profiler. So, we had to hack our way through to get it running on a server somehow. Don't ask how. After running the SQL Profiler, boy, were we surprised! The name of the honorable SP which was giving us so much pain was the great stored procedure dbo.aspnet_Profile_GetProfiles!&lt;br /&gt;We used (and still use) Profile provider extensively. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;Here's the SP:&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;CREATE PROCEDURE [dbo].[aspnet_Profile_GetProfiles]&lt;br /&gt;@ApplicationName nvarchar(256),&lt;br /&gt;@ProfileAuthOptions int,&lt;br /&gt;@PageIndex int,&lt;br /&gt;@PageSize int,&lt;br /&gt;@UserNameToMatch nvarchar(256) = NULL,&lt;br /&gt;@InactiveSinceDate datetime = NULL&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;DECLARE @ApplicationId uniqueidentifier&lt;br /&gt;SELECT @ApplicationId = NULL&lt;br /&gt;SELECT @ApplicationId = ApplicationId&lt;br /&gt;FROM aspnet_Applications&lt;br /&gt;WHERE LOWER(@ApplicationName)&lt;br /&gt;= LoweredApplicationName&lt;br /&gt;&lt;br /&gt;IF (@ApplicationId IS NULL)&lt;br /&gt;RETURN&lt;br /&gt;&lt;br /&gt;-- Set the page bounds&lt;br /&gt;DECLARE @PageLowerBound int&lt;br /&gt;DECLARE @PageUpperBound int&lt;br /&gt;DECLARE @TotalRecords int&lt;br /&gt;SET @PageLowerBound = @PageSize * @PageIndex&lt;br /&gt;SET @PageUpperBound = @PageSize - 1 + @PageLowerBound&lt;br /&gt;&lt;br /&gt;-- Create a temp table TO store the select results&lt;br /&gt;CREATE TABLE #PageIndexForUsers&lt;br /&gt;(&lt;br /&gt;IndexId int IDENTITY (0, 1) NOT NULL,&lt;br /&gt;UserId uniqueidentifier&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;-- Insert into our temp table&lt;br /&gt;INSERT INTO #PageIndexForUsers (UserId)&lt;br /&gt;&lt;br /&gt;SELECT u.UserId&lt;br /&gt;FROM dbo.aspnet_Users&lt;br /&gt;u, dbo.aspnet_Profile p&lt;br /&gt;WHERE ApplicationId = @ApplicationId&lt;br /&gt;AND u.UserId = p.UserId&lt;br /&gt;AND (@InactiveSinceDate&lt;br /&gt;IS NULL OR LastActivityDate&lt;br /&gt;&lt;= @InactiveSinceDate) AND ( (@ProfileAuthOptions = 2) OR (@ProfileAuthOptions = 0 AND IsAnonymous = 1) OR (@ProfileAuthOptions = 1 AND IsAnonymous = 0) ) AND (@UserNameToMatch IS NULL OR LoweredUserName LIKE LOWER(@UserNameToMatch)) ORDER BY UserName SELECT u.UserName, u.IsAnonymous, u.LastActivityDate, p.LastUpdatedDate, DATALENGTH(p.PropertyNames) + DATALENGTH(p.PropertyValuesString) + DATALENGTH(p.PropertyValuesBinary) FROM dbo.aspnet_Users u, dbo.aspnet_Profile p, #PageIndexForUsers i WHERE u.UserId = p.UserId AND p.UserId = i.UserId AND i.IndexId &gt;= @PageLowerBound&lt;br /&gt;AND i.IndexId &lt;= @PageUpperBound DROP TABLE #PageIndexForUsers END END First it looks up for ApplicationID. Collapse&lt;/span&gt;&lt;a href="http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx#" preid="19"&gt;&lt;span style="color:#ff6600;"&gt; Copy Code&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt; DECLARE @ApplicationId uniqueidentifier&lt;br /&gt;SELECT @ApplicationId = NULL&lt;br /&gt;SELECT @ApplicationId = ApplicationId FROM aspnet_Applications&lt;br /&gt;WHERE LOWER(@ApplicationName) = LoweredApplicationName&lt;br /&gt;IF (@ApplicationId IS NULL)&lt;br /&gt;RETURN&lt;br /&gt;Then it creates a temporary table (it should use table data type) in order to store profiles of users.&lt;br /&gt;&lt;/p&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;Create a temp table TO store the select results&lt;br /&gt;CREATE TABLE #PageIndexForUsers&lt;br /&gt;(&lt;br /&gt;IndexId int IDENTITY (0, 1) NOT NULL,&lt;br /&gt;UserId uniqueidentifier&lt;br /&gt;)&lt;br /&gt;-- Insert into our temp table&lt;br /&gt;INSERT INTO #PageIndexForUsers (UserId) &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;If it gets called very frequently, there will be too high IO due to the temporary table creation. It also runs through two very big tables - aspnet_Users and aspnet_Profile. The SP is written in such a way that if one user has multiple profiles, it will return all profiles of the user. But normally we store one profile per user. So, there's no need for creating a temporary table. Moreover, there's no need for doing LIKE LOWER(@UserNameToMatch). We always called with a full user name which we can match directly using the equal operator.&lt;br /&gt;So, we opened up the stored proc and did a open heart bypass surgery like this:&lt;br /&gt;&lt;/p&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;IF @UserNameToMatch IS NOT NULL&lt;br /&gt;BEGIN&lt;br /&gt;SELECT u.UserName, u.IsAnonymous, u.LastActivityDate, p.LastUpdatedDate,&lt;br /&gt;DATALENGTH(p.PropertyNames)&lt;br /&gt;+ DATALENGTH(p.PropertyValuesString) + DATALENGTH(p.PropertyValuesBinary)&lt;br /&gt;FROM dbo.aspnet_Users u&lt;br /&gt;INNER JOIN dbo.aspnet_Profile p ON u.UserId = p.UserId&lt;br /&gt;WHERE u.LoweredUserName = LOWER(@UserNameToMatch)&lt;br /&gt;&lt;br /&gt;SELECT @@ROWCOUNT&lt;br /&gt;END&lt;br /&gt;ELSE&lt;br /&gt;BEGIN -- Do the original bad things &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;It ran fine locally. Now it was time to run it on the server. This is an important SP which is used by the ASP.NET 2.0 Profile Provider, heart of ASP.NET Framework. If we do something wrong here, we might not be able to see the problem immediately, but may be after one month we will realize users profile is mixed up and there's no way to get it back. So, it was a pretty hard decision to run this on a live production server directly without doing enough testing. We did not have time to do enough testing anyway. We are already down. So, we all gathered, said our prayers and hit the "Execute" button on SQL Server Management Studio.&lt;br /&gt;The SP ran fine. On the server we noticed from 100% CPU usage it came down to 30% CPU usage. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;IO usage also came down to 40%.&lt;br /&gt;We went live again!&lt;br /&gt;Here's another SP that gets called on every page load and webservice call on our site because we use Profile provider extensively.&lt;br /&gt;&lt;/p&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;&lt;/span&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;CREATE PROCEDURE [dbo].[aspnet_Profile_GetProperties]&lt;br /&gt;@ApplicationName nvarchar(256),&lt;br /&gt;@UserName nvarchar(256),&lt;br /&gt;@CurrentTimeUtc datetime&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;DECLARE @ApplicationId uniqueidentifier&lt;br /&gt;SELECT @ApplicationId = NULL&lt;br /&gt;SELECT @ApplicationId = ApplicationId&lt;br /&gt;FROM dbo.aspnet_Applications&lt;br /&gt;WHERE LOWER(@ApplicationName) = LoweredApplicationName&lt;br /&gt;IF (@ApplicationId IS NULL)&lt;br /&gt;RETURN&lt;br /&gt;DECLARE @UserId uniqueidentifier&lt;br /&gt;SELECT @UserId = NULL&lt;br /&gt;SELECT @UserId = UserId&lt;br /&gt;FROM dbo.aspnet_Users&lt;br /&gt;WHERE ApplicationId = @ApplicationId&lt;br /&gt;AND LoweredUserName =&lt;br /&gt;LOWER(@UserName)&lt;br /&gt;IF (@UserId IS NULL)&lt;br /&gt;RETURN&lt;br /&gt;SELECT TOP 1 PropertyNames, PropertyValuesString, PropertyValuesBinary&lt;br /&gt;FROM dbo.aspnet_Profile&lt;br /&gt;WHERE UserId = @UserId&lt;br /&gt;IF (@@ROWCOUNT &gt; 0)&lt;br /&gt;BEGIN&lt;br /&gt;UPDATE dbo.aspnet_Users&lt;br /&gt;SET LastActivityDate=@CurrentTimeUtc&lt;br /&gt;WHERE UserId = @UserId&lt;br /&gt;END&lt;br /&gt;END &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;When you run the SP, see the statistics:&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;Table 'aspnet_Applications'. Scan count 1, logical reads 2, physical reads 0,&lt;br /&gt;read-ahead reads 0, lob logical reads 0, lob physical&lt;br /&gt;reads 0, lob read-ahead reads 0.&lt;br /&gt;(1 row(s) affected)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;Table 'aspnet_Users'. Scan count 1, logical reads 4, physical reads 0,&lt;br /&gt;read-ahead reads 0, lob logical reads 0, lob physical&lt;br /&gt;reads 0, lob read-ahead reads 0.&lt;br /&gt;(1 row(s) affected)&lt;br /&gt;(1 row(s) affected)&lt;br /&gt;Table 'aspnet_Profile'. Scan count 0, logical reads 3, physical reads 0,&lt;br /&gt;read-ahead reads 0, lob logical reads 0, lob physical&lt;br /&gt;reads 0, lob read-ahead reads 0.&lt;br /&gt;(1 row(s) affected)&lt;br /&gt;Table 'aspnet_Users'. Scan count 0, logical reads 27, physical reads 0,&lt;br /&gt;read-ahead reads 0, lob logical reads 0, lob physical&lt;br /&gt;reads 0, lob read-ahead reads 0.&lt;br /&gt;(1 row(s) affected)&lt;br /&gt;(1 row(s) affected) &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;This stored proc populates the Profile object with all the custom properties whenever Profile object is accessed for the first time within a request.&lt;br /&gt;First it does a SELECT on aspnet_application to find out the application ID from application name. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;You can easily replace this with a hard coded application ID inside the SP and save some effort. Normally we run only one application on our production server. So, there's no need to lookup application ID on every single call. This is one quick optimization to do. However, from client statistics, you can see where's the real performance bottleneck:&lt;br /&gt;Then look at the last block where aspnet_users table is updated with LastActivityDate. This is the most expensive one. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;This is done in order to ensure Profile provider remembers when was the last time a user's profile was accessed. We do not need to do this on every single page load and Web service call where Profile object is accessed. Maybe we can do it when user first logs in and logs out. In our case, a lot of Web service is called while user is on the page. There's only one page anyway. So, we can easily remove this in order to save a costly update on the giant aspnet_users table on every single Web service call. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;How to Query ASP.NET 2.0 Membership Tables Without Bringing Down the Site&lt;br /&gt;Such queries will happily run on your development environment:&lt;br /&gt;Collapse&lt;/span&gt;&lt;a href="http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx#" preid="24"&gt;&lt;span style="color:#ff6600;"&gt; Copy Code&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt;Select * from aspnet_users where UserName = 'blabla'&lt;br /&gt;Or you can get some user's profile without any problem using:&lt;br /&gt;Collapse&lt;/span&gt;&lt;a href="http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx#" preid="25"&gt;&lt;span style="color:#ff6600;"&gt; Copy Code&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt;Select * from aspnet_profile where userID = '�...'&lt;br /&gt;Even you can nicely update a user's email in aspnet_membership table like this:&lt;br /&gt;Collapse&lt;/span&gt;&lt;a href="http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx#" preid="26"&gt;&lt;span style="color:#ff6600;"&gt; Copy Code&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt;Update aspnet_membership&lt;br /&gt;SET Email = 'newemailaddress@somewhere.com'&lt;br /&gt;Where Email = '�' &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;But when you have a giant database on your production server, running any of these will bring your server down. The reason is, although these queries look like very obvious ones that you will be using frequently, none of these are part of any index. So, all of the above results in "Table Scan" (worst case for any query) on millions of rows on respective tables. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;Here's what happened to us. We used such fields like UserName, Email, UserID, IsAnonymous etc. on lots of marketing reports at &lt;/span&gt;&lt;a href="http://www.pageflakes.com/" mce_href="http://www.pageflakes.com"&gt;&lt;span style="color:#ff6600;"&gt;Pageflakes&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt;. These are some reports which only marketing team use, no one else. Now, the site runs fine but several times a day marketing team and users used to call us and scream "Site is slow!", "Users are reporting extreme slow performance!", "Some pages are getting timed out!" etc. Usually when they call us, we tell them "Hold on, checking right now" and we check the site thoroughly. We use SQL profiler to see what's going wrong. But we cannot find any problem anywhere. Profiler shows queries running file. CPU load is within parameters. Site runs nice and smooth. We tell them on the phone, "We can't see any problem, what's wrong?"&lt;br /&gt;So, why can't we see any slowness when we try to investigate the problem but the site becomes really slow several times throughout the day when we are not investigating?&lt;br /&gt;Marketing team sometimes run analysis reports that use queries like the above several times per day. Whenever they run any of those queries, as the fields are not part of any index, it makes server IO go super high and CPU also goes super high - something like this:&lt;br /&gt;We have SCSI drives which have 15000 RPM, very expensive, very fast. CPU is Dual core Dual Xeon 64bit. Both are very powerful hardware of their kind. Still these queries bring us down due to huge database size.&lt;br /&gt;But this never happens when marketing team calls us and we keep them on the phone and try to find out what's wrong. Because when they are calling us and talking to us, they are not running any of the reports which bring the servers down. They are working somewhere else on the site, mostly trying to do the same things complaining users are doing.&lt;br /&gt;&lt;/p&gt;&lt;/span&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;Let's look at the indexes:&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;Table: aspnet_users&lt;br /&gt;Clustered Index = ApplicationID, LoweredUserName&lt;br /&gt;NonClustered Index = ApplicationID, LastActivityDate&lt;br /&gt;Primary Key = UserID&lt;br /&gt;Table: aspnet_membership&lt;br /&gt;Clustered Index = ApplicationID, LoweredEmail&lt;br /&gt;NonClustered = UserID&lt;br /&gt;Table: aspnet_Profile&lt;br /&gt;Clustered Index = UserID&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;Most of the indexes have ApplicationID in it. Unless you put ApplicationID='�' in the WHERE clause, it's not going to use any of the indexes. As a result, all the queries will suffer from Table Scan. Just put ApplicationID in the where clause (Find your ApplicationID from aspnet_Application table) and all the queries will become blazingly fast.&lt;br /&gt;DO NOT use Email or UserName fields in WHERE clause. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;They are not part of the index instead LoweredUserName and LoweredEmail fields are in conjunction with ApplicationID field. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;All queries must have ApplicationID in the WHERE clause.&lt;br /&gt;Our Admin site which contains several of such reports and each contains lots of such queries on aspnet_users, aspnet_membership and aspnet_Profile tables. As a result, whenever marketing team tried to generated reports, they took all the power of the CPU and HDD and the rest of the site became very slow and sometimes non-responsive.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;Make sure you always cross check all your queries WHERE and JOIN clauses with index configurations. Otherwise you are doomed for sure when you go live.&lt;br /&gt;Prevent Denial of Service (DOS) Attack&lt;br /&gt;&lt;/p&gt;&lt;/span&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;Web services are the most attractive target for hackers because even a pre-school hacker can bring down a server by repeatedly calling a Web service which does expensive work. Ajax Start Pages like &lt;/span&gt;&lt;a href="http://www.pageflakes.com/" mce_href="http://www.pageflakes.com/"&gt;&lt;span style="color:#ff6600;"&gt;Pageflakes&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt; are the best target for such DOS attack because if you just visit the homepage repeatedly without preserving cookie, every hit is producing a brand new user, new page setup, new widgets and what not. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;The first visit experience is the most expensive one. Nonetheless, it is the easiest one to exploit and bring down the site. You can try this yourself. Just write a simple code like this:&lt;br /&gt;Collapse&lt;/span&gt;&lt;a href="http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx#" preid="27"&gt;&lt;span style="color:#ff6600;"&gt; Copy Code&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt;for( int i = 0; i &lt; client =" new"&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;DownloadString("http://www.pageflakes.com/default.aspx"); } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;To your great surprise, you will notice that, after a couple of calls, you don't get a valid response. It is not that you have succeeded in bringing down the server. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;It is that your requests are being rejected. You are happy that you no longer get any service, thus you achieve Denial of Service (for yourself). We are happy to Deny You of Service (DYOS). The trick I have in my sleeve is an inexpensive way to remember how many requests are coming from a particular IP. When the number of request exceeds the threshold, deny further request for some duration. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;The idea is to remember caller�s IP in ASP.NET Cache and maintain a count of request per IP. When the count exceeds a predefined limit, reject further request for some specific duration like 10 mins. After 10 mins, again allow requests from that IP. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;I have a class named ActionValidator which maintains a count of specific actions like First Visit, Revisit, Asynchronous postbacks, Add New widget, Add New Page etc. It checks whether the count for such specific action for a specific IP exceeds the threshold value or not. Collapse&lt;/span&gt;&lt;a href="http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx#" preid="28"&gt;&lt;span style="color:#ff6600;"&gt; Copy Code&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt;public static class ActionValidator&lt;br /&gt;{&lt;br /&gt;private const int DURATION = 10; // 10 min period&lt;br /&gt;&lt;br /&gt;public enum ActionTypeEnum&lt;br /&gt;{&lt;br /&gt;FirstVisit = 100, // The most expensive one, choose the value wisely.&lt;br /&gt;ReVisit = 1000, // Welcome to revisit as many times as user likes&lt;br /&gt;Postback = 5000, // Not must of a problem for us&lt;br /&gt;AddNewWidget = 100,&lt;br /&gt;AddNewPage = 100,&lt;br /&gt;}&lt;br /&gt;The enumeration contains the type of actions to check for and their threshold value for a specific duration � 10 mins.&lt;br /&gt;A static method named IsValid does the check. It returns true if the request limit is not passed, false if the request needs to be denied. Once you get false, you can call Request.End() and prevent ASP.NET from proceeding further. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;You can also switch to a page which shows �Congratulations! You have succeeded in Denial of Service Attack.�&lt;br /&gt;Collapse&lt;/span&gt;&lt;a href="http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx#" preid="29"&gt;&lt;span style="color:#ff6600;"&gt; Copy Code&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#ff6600;"&gt;public static bool IsValid( ActionTypeEnum actionType )&lt;br /&gt;{&lt;br /&gt;HttpContext context = HttpContext.Current;&lt;br /&gt;if( context.Request.Browser.Crawler ) return false;&lt;br /&gt;&lt;br /&gt;string key = actionType.ToString() + context.Request.UserHostAddress;&lt;br /&gt;var hit = (HitInfo)(context.Cache[key] ?? new HitInfo());&lt;br /&gt;&lt;br /&gt;if( hit.Hits &gt; (int)actionType ) return false;&lt;br /&gt;else hit.Hits ++;&lt;br /&gt;&lt;br /&gt;if( hit.Hits == 1 )&lt;br /&gt;context.Cache.Add(key, hit, null, DateTime.Now.AddMinutes(DURATION),&lt;br /&gt;System.Web.Caching.Cache.NoSlidingExpiration,&lt;br /&gt;System.Web.Caching.CacheItemPriority.Normal, null);&lt;br /&gt;return true;&lt;br /&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;The cache key is built with a combination of action type and client IP address. First it checks if there�s any entry for the action and the client IP in cache or not. If not, start the count and remember the count for the IP in cache for the specific duration. The absolute expiration on cache item ensures that after the duration the cache item will be cleared and the count will restart. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;When there is already an entry in the cache, get the last hit count, and check if the limit is exceeded or not. If not exceeded, increase the counter. There is no need to store the updated value in the cache again by doing: Cache[url]=hit; because the hit object is by reference and changing it means it gets changed in the cache as well. In fact, if you do put it again in the cache, the cache expiration counter will restart and fail the logic of restarting count after specific duration. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;The usage is very simple, on the default.aspx: &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#ff6600;"&gt;protected override void OnInit(EventArgs e)&lt;br /&gt;{&lt;br /&gt;base.OnInit(e);&lt;br /&gt;// Check if revisit is valid or not&lt;br /&gt;if( !base.IsPostBack )&lt;br /&gt;{&lt;br /&gt;// Block cookie less visit attempts&lt;br /&gt;if( Profile.IsFirstVisit )&lt;br /&gt;{&lt;br /&gt;if( !ActionValidator.IsValid(ActionValidator.ActionTypeEnum.FirstVisit))&lt;br /&gt;Response.End();&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;if( !ActionValidator.IsValid(ActionValidator.ActionTypeEnum.ReVisit) )&lt;br /&gt;Response.End();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;// Limit number of postbacks&lt;br /&gt;if( !ActionValidator.IsValid(ActionValidator.ActionTypeEnum.Postback) )&lt;br /&gt;Response.End();&lt;br /&gt;}&lt;br /&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;&lt;br /&gt;Here I am checking specific scenario like first Visit, re-visit, postbacks etc.&lt;br /&gt;Of course you can put in some Cisco firewall and prevent DOS attack. You will get a guarantee from your hosting provider that their entire network is immune to DOS and DDOS (Distributed DOS) attacks. What they guarantee is network level attack like TCP SYN attacks or malformed packet floods etc. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;There is no way they can analyze the packet and find out a particular IP is trying to load the site too many times without supporting cookie or trying to add too many widgets. These are called application level DOS attack which hardware cannot prevent. It must be implemented in your own code.&lt;br /&gt;&lt;/p&gt;&lt;/span&gt;&lt;p&gt;&lt;span style="color:#ff6600;"&gt;There are very few websites out there which take such precaution for application level DOS attacks. Thus it�s quite easy to make servers go mad by writing a simple loop and hitting expensive pages or Web services continuously from your home broadband connection. I hope this small but effective class will help you prevent DOS attack in your own Web applications. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#006600;"&gt;====================================================================&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#006600;"&gt;Name : Yogendra Pratap Singh&lt;br /&gt;Education : M.SC. in Computer Science in 2006&lt;br /&gt;Specialization: Microsoft.Net Technologies&lt;br /&gt;Occuption: Software Programmer&lt;br /&gt;Location : PUNE (MH)&lt;br /&gt;Native : MAIHAR (MP)&lt;br /&gt;E-Mail : &lt;/span&gt;&lt;a href="mailto:helloyogendra@gmail.com"&gt;&lt;span style="color:#006600;"&gt;helloyogendra@gmail.com&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7923925041222581283-603537851565690585?l=helloyogendra.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://helloyogendra.blogspot.com/feeds/603537851565690585/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7923925041222581283&amp;postID=603537851565690585' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7923925041222581283/posts/default/603537851565690585'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7923925041222581283/posts/default/603537851565690585'/><link rel='alternate' type='text/html' href='http://helloyogendra.blogspot.com/2008/12/friends-world.html' title='Technology in our Hands : So let us raise your hands to make a team effort.'/><author><name>yogendra</name><uri>http://www.blogger.com/profile/17352040371528808178</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://3.bp.blogspot.com/_HAPjfdF1UaM/STe2FmgLKsI/AAAAAAAAAD0/2We-ihnll1A/S220/11.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_HAPjfdF1UaM/STjCiDVK9zI/AAAAAAAAAF0/3dzSX1NplFg/s72-c/gg.jpg' height='72' width='72'/><thr:total>0</thr:total></entry></feed>
