Scripts and images downloaded from the WebResources.axd
handler (in ASP.NET 2.0 only) are not cached by the browser when debug=true.
We have seen quite a few issues lately where the customers
complain that the pages are running too slowly. They look at Fiddler
traces/Netmon and figure out that WebResources.axd is the culprit and is getting
called multiple times, thus reducing the performance of the webpage. The
explanation to this behavior is pretty simple. While developing, you keep
debug=true and there are chances that you will be modifying the scripts,
validators, treeview images and other client resources handled by webresources.axd.
You would really not appreciate it if the script and images downloaded from
webresources.axd get cached in the browser’s memory because you will have to
clear the browser cache every time to check your application. Thus, what is a
perfectly reasonable thing to do in development scenario could turn out to be a
very big bottleneck on production websites.
When you set debug=false, the cache duration for the items
handled by webresource.axd is set to such a value that it is cached at the
client (and intermediate proxy servers) as well. Look at the details below. I
have modified one.aspx page of this project (see Listing 1) and it contains the
following in the page’s <form> tag.
Listing 5
<div>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:RangeValidator ID="RangeValidator1" runat="server"
ErrorMessage="RangeValidator" ControlToValidate="TextBox1" MaximumValue="100"
MinimumValue="10"></asp:RangeValidator>
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />
</div>
I am using a simple RangeValidator which is checking a
Textbox for values between 10 and 100. This is done to ensure that
webresource.axd comes into play. Another thing which you need to do is install Fiddler. This is a free
HTTP Debugger tool and I have used this tool to copy the headers of the
requests and responses as you can see below.
Let us have a look at the header when debug=true.
Listing 6
GET /DebugTrue/WebResource.axd?d=QmP4A6B4y3bRHKeLCMYC2A2&t=633176900891406250
HTTP/1.1
Accept: */*
Referer: <a href="http://rahulsoni/debugtrue/one.aspx">http://rahulsoni/debugtrue/one.aspx</a>
Accept-Language: en-us
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)
Proxy-Connection: Keep-Alive
Host: rahulsoni
Cookie: ASP.NET_SessionId=nytwqw450gtuax55sqzmz3mh
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.1
Date: Sun, 24 Jun 2007 16:12:25 GMT
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: private
Content-Type: application/x-javascript
Content-Length: 20931
Now, look at the header when debug=false.
Listing 7
GET /DebugTrue/WebResource.axd?d=QmP4A6B4y3bRHKeLCMYC2A2&t=633176900891406250
HTTP/1.1
Accept: */*
Referer: <a href="http://rahulsoni/debugtrue/one.aspx">http://rahulsoni/debugtrue/one.aspx</a>
Accept-Language: en-us
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)
Proxy-Connection: Keep-Alive
Host: rahulsoni
Cookie: ASP.NET_SessionId=nytwqw450gtuax55sqzmz3mh
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.1
Date: Sun, 24 Jun 2007 16:13:31 GMT
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: public
Expires: Mon, 23 Jun 2008 16:13:31 GMT
Content-Type: application/x-javascript
Content-Length: 20931
Notice how Expires header is set to an year ahead and how
Cache-Control header is changed to Public when you have debug=false.
Figure 10 – Fiddler snapshot with
debug=<true/false> showing WebResource.axd
Have a look at the image above and see how webresource.axd
is getting called multiple times when debug=true (RED Box). The request number
55 and 62 are two different requests from the same browser session and you will
see 57, 58, 64, and 65 making calls to webresource.axd with cache type as private
(7th Column).
I changed the debug=false (output after that is in GREEN box
above). Notice how the call to webresource.axd is made in 70 and 72 with cache
type as public and the expiring date is set to a year ahead! The subsequent
click on the button or new requests to one.aspx does not lead to webresoure.axd
requests any more. This is a real big performance gain since we are not talking
about just the get requests but each and every postback of the pages which
deals with webresouce.axd.