image Tonight we fixed a severe compatibility issue that I feel you should all be aware of.

Executive summary: ASP.NET AJAX breaks down completely in some circumstances when using WebKit-based browsers. Reference the JavaScript provided below to solve these problems.

As you know, we develop web applications using ASP.NET AJAX and tonight we were notified that one of our users was not able to proceed to the payment page on one of our e-commerce websites. (As you can imagine, preventing payment is the worst thing that can happen in an e-commerce site!). After some investigation, we discovered the user was using Safari 3 on an Intel-based MacBook Pro just like the one I recently purchased. I picked up my MBP and re-tested the site, going through exactly the same steps this user did (thanks to the auditing capabilities we've built into the e-commerce engine). The site works fine in general, except at one particular page deep within the bowels of the website, when clicking on a button, the ASP.NET UpdateProgress control would show and never go away during the asynchronous postback.

I first thought this was an SSL issue such as the evil IE White Screen Bug, but I managed to replicate on my local machine without using SSL. This button is contained inside a dozen layers of user controls. Fortunately, I use this user control in another location. I tested one of these locations (where it isn't as nested) and this one worked. I then proceeded to hide my user controls, layer by layer and narrowed the issue to ASP.NET validators on one of my pages.

<asp:RequiredFieldValidator ID="rfvName" runat="server" ErrorMessage="Required"
    Display="Dynamic" ControlToValidate="txtName"="true" />


Adding Visible="false" to this (and the other validators) on my user control unfroze the UpdateProgress. My first thought was that I must have reached a limit in identifier name lengths because my validator was nested very deeply. I proceeded to rename a few layers to make the name shorter. This changed nothing. I then discovered how to enable a FireBug-like tool in Safari called Web Inspector. This helped me discover an obscure JavaScript error.

Sys.ScriptLoadFailedException: The script 'http://localhost:2241/ScriptResource.axd?[...]' failed to load.


After changing from ScriptMode="Release" to ScriptMode="Debug", I got additional details.

Check for:
Inaccessible path.
Script errors. (IE) Enable 'Display a notification about every script error' under advanced settings.
Missing call to Sys.Application.notifyScriptLoaded().


This finally lead me to an old post on the ASP.NET forums. It appears that Safari 2 needed a few hacks in the ASP.NET AJAX JavaScript code to work properly. These hacks are no longer needed in Safari 3 (or Google Chrome) because WebKit works out of the box. However, these hacks sometimes broke WebKit-based browsers as I discovered today. The first solution in the forums is to change the JavaScript files used by the framework but we didn't like that solution very much. The second comment provided a solution which we found reasonable. 

Workaround

The workaround simply tells ASP.NET AJAX that Safari 3 and Google Chrome are a new type of browser instead of the old Safari for which workarounds had to be programmed.

1) Create a new file called webkit.js

Sys.Browser.WebKit = {}; //Safari 3 is considered WebKit
if( navigator.userAgent.indexOf( 'WebKit/' ) > -1 )
{
  Sys.Browser.agent = Sys.Browser.WebKit;
  Sys.Browser.version = parseFloat( navigator.userAgent.match(/WebKit\/(\d+(\.\d+)?)/)[1]);
  Sys.Browser.name = 'WebKit';
}


2) Reference this webkit.js from your ScriptManager

<ajax:ToolkitScriptManager ID="scripts" runat="server" ScriptMode="Release" EnableHistory="true" 
EnableSecureHistoryState="false" EnablePageMethods="True" CombineScripts="true" 
OnAsyncPostBackError="Page_OnAsyncError" OnNavigate="OnHistoryNavigate">
    <Scripts>
        <asp:ScriptReference Path="~/js/webkit.js" />
    </Scripts>
</ajax:ToolkitScriptManager>


We hope this will help some of you!

kick it on DotNetKicks.com