Patching Atlas bugs
One of the downsides to working with early beta software is that it has bugs. Atlas is no exception. So what happens when you encounter one of those bugs? Well, the Atlas team has been good enough to provide us with the source to the Javascript library, so if the bug is there we can in theory patch in a fix ourselves. I found myself in this situation when I encountered a bug in the way client-side Actions handle data binding. Fixing the bug in the source was relatively simple.
Things get a little more complicated, however, when using the Atlas server controls like ScriptManager and UpdatePanel. The ScriptManager control loads the Atlas Javascript from embedded resources in the Atlas assembly, and doesn't provide a way to override the script source. There's a thread on the ASP.NET forums on this topic, and one of the ASP.NET team members offers one solution - a bit of code to add to the Page_Load event handler that preemptively loads the script from a different location.
Here's another option - one that doesn't require adding code to each of the site's pages. We can simply use the URL rewriting feature built-in to ASP.NET to redirect the WebResource requests to our customized versions of the scripts. To use this trick, copy the ScriptLibrary directory from "C:\Program Files\Microsoft ASP.NET\Atlas\v2.0.50727\Atlas" into your web site. Your site should then contain directories ScriptLibrary\Debug and ScriptLibrary\Release, which hold the script sources. Make any changes to the scripts you like. Finally, add the following code to the code-behind of one of your pages and wire it up to a button click or some other trigger:
private const string ResourceNameBaseDebug = "Microsoft.Web.Resources.ScriptLibrary.Debug."; |
private const string ResourceNameBaseRelease = "Microsoft.Web.Resources.ScriptLibrary.Release."; |
private const string ScriptLibraryBaseDebug = "~/ScriptLibrary/Debug/"; |
private const string ScriptLibraryBaseRelease = "~/ScriptLibrary/Release/"; |
private void WriteAtlasWebResourceMappings() |
{ |
Configuration config = WebConfigurationManager.OpenWebConfiguration("~/"); |
UrlMappingsSection urlMappingSection = (UrlMappingsSection)config.GetSection("system.web/urlMappings"); |
UrlMappingCollection urlMappings = urlMappingSection.UrlMappings; |
WebResourceAttribute[] attributes = (WebResourceAttribute[])typeof(ScriptManager).Assembly.GetCustomAttributes(typeof(WebResourceAttribute), false); |
foreach (WebResourceAttribute attribute in attributes) |
{ |
urlMappings.Add(new UrlMapping(GetResourceUrl(attribute), GetMappedUrl(attribute.WebResource))); |
} |
config.Save(); |
} |
public string GetMappedUrl(string webResource) |
{ |
string scriptLibraryPath = String.Empty; |
if (webResource.StartsWith(ResourceNameBaseDebug)) |
{ |
scriptLibraryPath = webResource.Replace(ResourceNameBaseDebug, ScriptLibraryBaseDebug); |
} |
else if (webResource.StartsWith(ResourceNameBaseRelease)) |
{ |
scriptLibraryPath = webResource.Replace(ResourceNameBaseRelease, ScriptLibraryBaseRelease); |
} |
return scriptLibraryPath; |
} |
This will write out the machine-specific URL rewrite directives into your app's web.config. Now all requests will be redirected to the script source in the ScriptLibrary folder.
This solves one problem with the embedded-as-resources scripts. However, another hassle remains. More on that later...