I know what you downloaded last summer
Published on Friday, November 5, 2010 7:31:00 AM UTC in Programming & Tools
This is a post about a particular behavior of the built-in ASP.NET development server that can turn your debugging experience as a Silverlight developer into an unpleasant experience.
It all started when I wanted to do some tests around bindings. I had created a small Silverlight project, and basically switched back and forth between the browser and Visual Studio to check what effects my code changes would produce.
Quickly I ran into a problem where a binding expression I was trying to use didn't work as intended. I spent some minutes double-checking that it was syntactically correct and then started to "google that with Bing" (thanks Scott, I'll never get this out of my head). After 20 minutes, when I had already started to doubt my mind, I finally realized that it was simply the browser that had not picked up the latest version of my Xap file. I had used hundreds of those small sample projects and never run into something similar. WTF?
What had happened
When I looked at the network traffic in Fiddler, I realized that the following happened. On the first request, Fiddler would log something like that as response for my Xap file:
No problem here. However, the second response for my Xap file looked like this:
As you can see, the ASP.NET development server returned code 304 ("not modified"), which is ok in this case. However, it also added an "Expires" header set to 24 hours in the future, which apparently is the default for static content.
All modern browsers obey this header and do not request that content again until the expiration date has passed. The problem is that you can't force the browser to ignore that. Even when you force a refresh of the page (Shift + F5 etc.), it won't request your Xap file. Because the server told it that this content does not change for the next 24 hours, it thinks it doesn't have to ask for it again. The only way to have it fetched before the expiration date is when you delete the browser cache.
The surprising thing was that I never had this problem before with any of my throw-away sample projects, and when I created a second one, I could hit the refresh button in the browser a dozen times, and the Xap file was downloaded every time. For that second project, the responses all looked like this:
As you can see, no "Expires" header is sent, and also some other minor details are different. "Cache-Control" is set to private, and there's also no ETag sent across the wire.
I really took me a while to figure out what was going on. When I realized the second sample project I had created worked perfectly fine, I thought about what I had made differently with the first one. This first sample I created as a stand-alone Silverlight project first, without a hosting web site. Shortly after, I decided that I wanted a hosting web application project after all and used the "Add new project" command to add a new ASP.NET Web Application project to my solution.
The difference is that if you create the web application separately from the Silverlight project, then the ASP.NET Membership is configured for you (this doesn't happen when you create the web project together with the Silverlight project). Further investigation unveiled that it's a single configuration setting in the Web.config which triggers this undesired behavior:
<?xml version="1.0"?> <configuration> <system.web> <compilation debug="true" targetFramework="4.0" /> <authentication mode="Forms" /> </system.web> </configuration>
As soon as you configure the authentication in your Web.config, the ASP.NET development server will switch to the above mentioned behavior. Remove that line and it's back to normal again.
This never occurred to me before, because for any type of project other than throw-away tests I host my web applications in IIS, and IIS doesn't show any of this behavior. It also returns 304 when content hasn't changed, but it does not add an "Expires" value by default. This causes the browser to ask whether a new version of your Xap file is available the next time the page loads.
What do we learn? I personally will try to avoid the built-in ASP.NET Development Server now whenever possible (can't wait for IIS Express integration into VS), even for small test projects. And should there be any unexpected behavior in my Silverlight applications, from now on I'll go with "it's the browser's fault" until proven otherwise :-).