Ajax Under the covers: What exactly is the .AXD
One of the most furstrating issues with programming languages and new developer must learn technology is understanding the hows and why's something actually works. Sure, it is easy enough to cut and paste code examples but almost impossible (unless from blind luck) to troubleshoot. In these series of posts I will attempt to dymstify the logic behind Ajax (Microsoft's) and try to shed some light on how it works for you - and for myself.
What exactly is the role of *.AXD files?
While I couldn't find a definition for the .AXD extension - I'll theorize that the extension's acronymn means Auxiliary Resource(X) Data. The two most notable filenames that you are probably aware of with .AXD extensions are Trace.Axd and WebResource.AXD.
Trace.AXD:
This is a diagnostic utility mode file and actually is a great tool to use when debugging or simply trying to follow programming logic flow without attaching to a debugger. In fact, because my web UI project is totally seperate from the code projects (meaning that I have a web project totally unaware of the C# code in the dll's and are two totally seperate Visual Studio solutions), I rely on the ability to insert Trace.Warns and Trace.Writes so that when viewing the trace.axd file - I can have informational and actual CLR warnings and exceptions displayed.
What you need to know about Trace.AXD in terms of AJAX.
The Trace function actually intercepts the output page before it is sent to the client's browser. As a result it parses and sometimes - re-organizes the html output to properly add the trace output to the end of page when the web.config is configured as such:
<system.web>
<trace enabled="true" pageOutput="true" />
If you are using Microsoft's Ajax what you want to do is configure the Web.Config with this instead:
<system.web>
<trace writeToDiagnosticsTrace="true" enabled="true" pageOutput="false" />
The difference between the two is that in the first example - it appends the trace output to the end of the resulting client's HTML page. The latter requires you to open a seperate browser instance pointing to http:// {some address} /Trace.axd.
The latter since it creates a new page doesn't change the client's browser's DOM. Therefore the mode you run Trace in is what has to be carefully considered in ANY AJAX enviroment as it is the ability to code against the client's browser's DOM that makes AJAX so powerful. Why is this so important? If the DOM structure is different than what the server expects (Specifically the ScriptManager which handles all the AJAX interactions from a parent or top level) - you will get a multitude of untraceable errors. In other words what may work one time will not the next and all kinds of unpredicablity will occur trying to track down issues if trace is not properly configured. I make this statement matter of factly as I already have gone through this chasing my tail in spite of not having one when Trace is improperly configured. Luckily for me in the instance I ran into this (upgrading to RC! from ATLAS - I was able to get hands on demonstration and explanation from Matt Gibbs - but we all are not so lucky). So, even though Microsoft Ajax is RTM with Version 1 - this rule applies and part of the logic of writing this article is to explain the workings...
.AXDs when using custom IHTTP Handlers.
Unfortunately, 99% (and I am yet to find the remaining 1%) of all the examples with Ajax (from Microsoft) are centered around Asp.Net 2.0's Master Pages. In other words - everything goes through default handlers for Asp.Net and no consideration is given to those that run websites not using Master Pages. If you use Master Pages this segment will be merely informational but of no practical use to you.
When using custom IHHTP handlers (such as what the original Community Starter Kit uses ((CSK) not to be confused with the Commerce Starter Kit which is all Master Page oriented)), special consideration must be given to how requests are being handled. Why? .AXD files will still be processed by your IHTTP handler unless they are explicitly designed to only handle .aspx requests. Most are not designed with indivudal handlers because they handle web services, aspx, html, text etc.requests. and in most instances it is easier to provide a global codebase versus individual ...From a performance perspective you can handle requests and just let go what doesn't get handled by your IHTTP module, but there is a time expiration for requests and at high loads you may run into an artificially induced brick wall. Additionally, the more code a request goes through only never to be handled - is a incremental negative load handling capacity for your system. Why? Common sense applies here - if your IHTTP handler is processing a request and it goes throughs a dozen checks to find out whether or not you have methods to handle the request - that is much more unneccessary load than returning the request to ASP.Net's CLR / IIS processing pipeline and having it handled properly elsewhere as promptly as possible (but preferably before it is set to your IHTTP handler if not configured to handle it).
So what do the configuration documents not include if you run with custom IHTTP handlers?
This is where it gets confusing. What gets handled first in terms of how things are laid out in the Web.Config versus how it is actually processed. Nothing I can determine from documentation and what I have seen in real enviroments actually give any actual insight in the process. That is the issue with Ajax as well - for most programmers the web.config is a leave it alone after it is first configured and then comes Ajax that requires all kinds of additional additions and deletions. For myself at least I kinda loathe changes to the Web.Config for two reasons:
1. There is absolutely no actual documentation on what it actually is and how to lay it out. Instead you get change this or that but never a reason having the entries that one does.
2. No intellisense. Even when you start changing it - there is nothing of the Web.Config that has intellisense to tell you what the options are resulting in having to scour the web to figure it all out - 9 times out of 10 - we just accept what we find in blogs or instructions = we go with the flow without truly understanding it.
Here is where speculation and my own experience comes in.
My web.config is configured as such:
<httpHandlers>
<remove verb="*" path="*.asmx"/>
<remove verb ="*" path="*.axd"/>
<add path="trace.axd" verb="*" type="System.Web.Handlers.TraceHandler" validate="true" />
<!-- <add path="*source.axd" verb="*" type="System.Web.Handlers.AssemblyResourceLoader" validate="true" /> -->
<add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="false"/>
<add path="*.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="true" />
</httpHandlers>
<httpModules>
<add name="CommunitiesModule" type="Cavalia.CommunitiesModule"/>
<add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</httpModules>
Notice that in the HttpHandlers section has the CommunitiesModule listed first - the AXD request will get processed first through it. Fortunately - I track the file requests coming through this handler and merely do a string search on the rawurl and if it matches a *.axd I merely do a return and pass it on. The reason I do hav it listed first is tht the ASMX (WebService) I do handle in my IHTTP handler. So, for my purposes I add logic to intercept the AXD requests and flush them back out while allowing my webservice stuff independent of AJAX to be handled properly. ForAJAX performance - I should move the ScriptModule above the CommunitiesModule listing. So for beginning programmer's here is code that would suffice as an example for passing the request:
protected void Page_Init(Object s, EventArgs e)
{
// Get abbreviated reference to current context
HttpContext Context = HttpContext.Current;
//check for the type of conternt (ie Admin, Section, User etc...)
string requestPath = CommunityGlobals.RemovePathInfo(Context.Request.Path.ToLower());
if (requestPath.EndsWith(".axd") )
{
return;
}
What if an AXD request goes through and is never handled?
The following line is what is used to handle non-handled .AXD requests:
<add path="*.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="true" />
However, the caveat here is that it is unknown what this does. There are never Event Log entries if a AXD is never found and quite honestly - no idea what this is used for. I will kinda half-heartedly go on record that not including this line - your code will not explode with tons of exceptions...but sometimes maybe will result in some absurb ScriptManager issues - but I am not positive about it and honestly no idea what the purpose of this configuration line is as there is no way to track whether or not a AXD request is full-filled or not. I have never seen a HTTP Not found with any axd file requested, which means either I am better programmer than I think I am or that since I do not create *.AXD files - would never see it anyways. So, do you need it? I would say yes and no...Unfortunately - there is no apparent coding strategy in place to determine if not found what to do or not do.
So, mainly the subject has been on the Trace.AXD but there are others and each is tied to a specfic handler by FILE NAME.
For instance - the Trace.AXD maps directly to this:
<add path="trace.axd" verb="*" type="System.Web.Handlers.TraceHandler" validate="true" /> (found in machine.config so technically you do not need to add it to the web.config)
The ScriptResource.AXD :
<add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="false"/>
As for the WebResource.AXD is handled by:
<
add path="WebResource.axd" verb="GET" type="System.Web.Handlers.AssemblyResourceLoader" validate="True" />(found in machine.config so techhnically you do not need to add it to the web.config)
There is one additional .AXD you shoud be aware of and that is the WebAdmin.AXD. This is the web utility Microsoft provides to manage default web site configuration settings. Since I do not use this as the admin features for .Net kinda lack anything remotedly useful in terms of web site administration I will defer to this introductory article.
So what is the ScriptResource.AXD and its difference from the WebResource.AXD?
Simply put the ScriptResource.AXD contains all of the clientside javascript routines for Ajax. Just because you include a scriptmanager that loads a script file it will never appear as a ScriptResource.AXD - instead it will be merely passed as the .js file you send if you reference a external script file. If you embed it in code then it may merely appear as part of the html as a <script> tag and code but depending if you code according to how the ToolKit handles it - may or may not appear as as a ScriptResource.axd. ScriptResource.axd is only introduced with AJAX and you will never see it elsewhere.
WebResources however, have been around for awhile. The AjaxToolKit uses WebResources to send data to the client (it always uses the GET action of HTTP) as well as what happens when you embed resources into an assembly. Embedded resources appear as WebResource.Axds and never peform a post it is always a get as they merely provide localization, images, client code - the client. Most third party component developers rely heavily on WebResource.Axds as it provides a way to embed stuff into a dll that is not easliy hacked.
And that is a short summary of the AXD.