Sunday, November 07, 2004

Relationship between Page and Page Directives

Another adventure into .net... The other day I had a problem where I wanted to create a property for a page, and have it configurable within the designer. To me, this seemed like it should be fairly easy to do, after all I can create a public property for a user control, and then set it in the designer like an attribute:

 < ... runat="server" property="value"/> 
But you can't simply add a custom value in the page directives:
<%@ Page Language="C#" MyPageProperty="value" %>
... you'll end up with an error. So it got me thinking, what is the relationship between Page and Page Directives, and why do I get this error? Enter Reflector. I've grown quite fond of this utility, and I've found it indispensible for inspecting code. Reflector allows you to crack open the internals of the core .net framework, and examine how Microsoft put the framework together. The best place to start is at the machine.config. It tells us that all requests for aspx pages are piped through the PageHandlerFactory. Using Reflector, we quickly see that the factory's main job is to create the handler and pass it off for execution (though we don't really need Reflector to tell us that, if you're familiar with design patterns -- that is what a Factory does). The actual creation of the handler is performed by the PageParser class, specifically the GetCompiledPageInstance method Looking at the PageParser through Reflector is like a good mystery novel, as it's quite complex, and uses a quite a variety of other classes to perform it's job. Most .net developers understand that the first time a page is requested, the worker process compiles the page and caches it so that future requests will take less time -- this is accomplished through the PageParser. As it turns out, the directives for the Page are used as settings for the PageParser, they get converted using Regular Expressions into a Dictionary object, then processed through the PageParser's ProcessMainDirective method. As the items in the directive are parsed, they are popped off the Dictionary. Afterwards, the CheckUnknownDirectiveAttributes method inspects the size of the Dictionary, and if it contains values it throws the error. If you're still reading, very good, or if you got excited and tried to create a derived class of the PageParser you've already discovered that all of these methods I've described are marked as internal and cannot be overridden. Few things this inspires me to do: 1) Hunt down and find all dependencies to the PageParser, decompile and create a custom PageHandlerFactory. 2) Take a peek at the ASP.NET 2.0 model and see how this has changed.

submit to reddit