Click here to Skip to main content
15,867,453 members
Articles / Web Development / ASP.NET
Article

ASP.NET 1.1 Web Application Compilation and Pre-compilation - Enhanced

Rate me:
Please Sign up or sign in to vote.
4.17/5 (4 votes)
5 Sep 20059 min read 80.4K   780   36   15
Enhancements to how to pre-compile or compile .aspx and .ascx files of C# or VB ASP.NET 1.1 web application; includes full source code, compilation library, runtime library and demo project.

Please see the original article first: ASP.NET 1.1 Web Application Compilation and Pre-compilation.

Introduction

The idea given by Peter Tewkesbury:

The requirement to change the IIS configuration for embedded resources troubles me. I look after a number of websites, which are hosted for me and I do not have access to the IIS settings. On my websites, I have a handler that creates thumbnail images from the full image. The code for this is not important.

This is the idea that I have had:

  1. Add a new handler called XYZ.
  2. The XYZ handler when it is called with a parameter, name of resource, would get and return this file.
  3. When you pre-compile the source, you could scan the code for objects which access these files (Image object, HTML code with src tag etc.) and then patch the code so that:
    1. the resource is included in the assembly,
    2. and the compiled code is patched so that the XYZ handler is called with the correct parameter so the correct resource file is returned.

Then you don't need to change any IIS settings - A big plus for everyone who has hosted websites.

This article is concerned with the implementation of this idea and its usage in your application. The source code is also rewritten and has a better design so that you can use this instead of the one in the old article.

Idea

As the previous article describes it is possible to embed any external file that your application requires (e.g. .gif, .css, etc.) in an assembly and requests to such files are to be served by your application instead of IIS. In order that IIS forwards requests to such files (e.g. "/MyApp/Css/Global.css") to ASP.NET runtime (and your application) the file name extensions should be mapped at IIS to aspnet_isapi.dll. Additionally, the extensions should be mapped to System.Web.IHttpHander implementator (e.g. WebApp.Web.Compilation.Runtime.ResourceFileHandler ) that will load the file content from the assembly and return it as a response to the requests. This mapping is done through web.config. If, for example, you want your application to serve requests to .css and .gif files you need to manually (or by using script) map these extensions at IIS to aspnet_isapi.dll and add the following lines in your web.config:

XML
<system.web>
  <httpHandlers>
    <add verb="*" path="*.css" 
      type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                              WebApp.Web.Compilation.Runtime" />
    <add verb="*" path="*.gif" 
      type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                              WebApp.Web.Compilation.Runtime" />
  </httpHandlers>
</system.web>

However, changing the IIS settings make the deployment of your application more difficult and it may not be always possible to do that. The solution is to make requests to such files to appear, as they are requests to files whose extensions are already registered at IIS: for example .aspx or .asmx. This may be done by substituting links to such files (e.g. "/MyApp/Css/Global.css") by links of type "handler?p=file_id" (e.g. "FH.aspx?p=Css/Global.css"). "handler" should have a path whose extension is already mapped at IIS to aspnet_isapi.dll (.aspx, .asmx, etc.) and file_id should be string by which the Win32 resource that corresponds to the file can be loaded from the assembly. As a result, no IIS settings need be changed but the following lines should be presented in your web.config:

XML
<system.web>
  <httpHandlers>
    <add verb="*" path="FH.aspx" 
      type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                              WebApp.Web.Compilation.Runtime" />
  </httpHandlers>
</system.web>

Implementation

A solution should target the following issues:

  • Embedding files
  • Links substitution
  • Serving requests to embedded files.

Embedding files

Embedding files to assembly is done by the WebApp.Web.Compilation.ResourceBuilder type. It enables building of Win32 Resource (.res) file which is to be included in compilation. The type provides two kinds of methods:

  • Adding an unnamed data or file by specifying Win32 resource type and name (unsigned short).
  • Adding a named data or file by specifying Win32 resource type and name (unsigned short).

If a resource is named then later on it can be accessed only by its name by the WebApp.Web.Compilation.Runtime.ResourceManager type. The name of a resource is of System.String type and differs from the Win32 resource name, which is of type System.UInt16. To enable support of string names of resources a common index is built and saved as an additional resource. Note: Although a Win32 resource name and/or type can be a string this is not implemented.

The main issue is how to choose the name for the resource of a file being added:

  • If all links to the file are to be substituted by links of type "handler?p=file_id" the name can be any string that is unique among all named resources. Subsequently, the value of "file_id" should be that name so the resource can be loaded on request at runtime. The only issue is that the name should denote the extension of the file in some way so an appropriate content-type can be returned with the HTTP response.
  • If the links to the file are to remain untouched, the name of the resource should be derived from the virtual path to the file so that the resource can be located at runtime.

This solution provides two WebApp.Web.Compilation.Runtime.IResourceNameProvider implementations that are responsible to provide names for files being added as resources:

  • WebApp.Web.Compilation.Runtime.RelativePathNameProvider
  • WebApp.Web.Compilation.Runtime.EncodedNameProvider

The RelativePathNameProvider derives the name of the resource from the relative path to the file based on the application's root directory. That is, if the application is located in C:\MyApp and the file is C:\MyApp\Css\Global.css the name would be Css/Global.css.

EncodedNameProvider does the same as the RelativePathNameProvider but applies base64 encoding on the relative path.

Links substitution

The following files that may contain links to other embedded files should be the target:

  • Pages and user controls: .aspx and .acsx.
  • Resource files: .htm, .html, .js, .css etc.

The following strategy is used:

  • Only links to embedded files should be substituted: that is links to files whose extensions are specified to be embedded as resources and that are within the scope of the application (i.e. the file physically resides within the subdirectory tree of the application's base directory). Note: to determine if a file is within the scope of the application the physical path is obtained by the System.Web.HttpRequest.MapPath(string,string,bool) method.
  • A link is any string that begins and ends with '"', ''', '(', ')' and contains the path that ends with one of the target file name extensions (exactly the regular expression used is @"('|""|\()(?<1>(\w|[.% \/~])*?\.(htm|html|js|...))('|""|\))"). This allows links to be located regardless of the name of the tag and attribute as they are specified in JavaScript/CSS code. For more information, see the WebApp.Web.Compilation.FileReferencesFixer type.

Pages and user controls

Links in such files are substituted prior to the files to be parsed by the System.Web.UI.TemplateParser descendants (i.e. a file's content is read, altered and then passed to the parser). Because of the way links are searched links specified within tags that has runat="server" attribute specified are also handled (e.g. <asp:image ImageUrl="~/Images/Logo.gif" runat="server"> will become <asp:image ImageUrl="FH.aspx?p=Images/Logo.gif" runat="server">).

Note: Only links that reside within .aspx and .asxc files will be substituted. Any links in code-behind should be handled manually by redesigning the code.

Resource files

Links in such files are substituted prior to adding their content to Win32 resource file (i.e. a file is read, altered and then appended to the resource file). That means only the files that are embedded itself will be processed. Links in files that are not specified to be embedded will not be fixed.

Choosing handler name

Generally, there are two types of handler names to choose from: relative to the current virtual path (e.g. "FH.aspx") and relative to the web site root (e.g. "/FH.aspx", "/MyApp/FH.aspx"). The differences are:

  • The way a browser will see the links: if you specify "FH.aspx" as a handler name all links will appear as "FH.aspx?p= ..." which is relative to the virtual path where the file containing the link is located. That means if you have /Default.aspx that contains <link href="/KB/aspnet/FH.aspx"?p=Css/Global.css" rel="stylesheet"> and /SubDir/WebForm1.aspx that contains <link href="/KB/aspnet/FH.aspx"?p=Css/Global.css" rel="stylesheet"> a browser will see links to two different files: "/FH.aspx?p= Css/Global.css" and "/SubDir/FH.aspx?p= Css/Global.css" and will request "Css/Global.css" twice (note that "Css/Global.css" is not the relative path to a file but the name of a resource). Because of that links in files that reside in subdirectories are adjusted by adding number of "../" strings in front of the handler's name: e.g. the link in /SubDir/WebForm1.aspx would become "../FH.aspx?p=Css/Global.css". That will cause a browser to request "Css/Global.css" only once. Otherwise if you specify "/FH.aspx?p=..." or "/MyApp/FH.aspx?p=..." as a handler name all links to the same file will be the same (e.g. "/MyApp/FH.aspx?p=Css/Global.css").
  • Deployment: if you choose a handler name relative to the virtual path (e.g. "FH.aspx") the application can be deployed in any virtual directory, as the links does not include any path dependent information. If you choose a name relative to the web site root the application should be deployed in a specific virtual directory.

If you need to generate links in your code-behind you can use the System.Web.UI.Control.ResolveUrl method (e.g. ResolveUrl( "~/FH.aspx?p=..." )).

Serving requests to embedded files

At runtime, requests are served by the WebApp.Web.Compilation.Runtime.ResourceFileHandler type. All you need to do is to map the name of the handler to this type in your web.config:

XML
<system.web>
  <httpHandlers>
    <add verb="*" path="FH.aspx" 
      type="WebApp.Web.Compilation.Runtime.ResourceFileHandler,
                              WebApp.Web.Compilation.Runtime" />
  </httpHandlers>
</system.web>

Note that the value of the path attribute does not include directory information (e.g. "/FH.aspx", "/MyApp/FH.aspx"). That will cause ASP.NET runtime to forward all requests made to "FH.aspx" anywhere within the application (e.g. "/FH.aspx", "/MyApp/FH.aspx", "/MyApp/SubDir/FH.aspx") to the WebApp.Web.Compilation.Runtime.ResourceFileHandler type.

Additionally, you will need to specify the type of the resource name provider (WebApp.Web.Compilation.Runtime.IResourceNameProvider descendant) in the WebApp.Web.Compilation.Runtime.ResourceFileManager configuration section:

XML
<WebApp.Web.Compilation.Runtime.ResourceFileManager>
  <add key="ResourceNameProvider" 
    value="WebApp.Web.Compilation.Runtime.RelativePathNameProvider"/>
</WebApp.Web.Compilation.Runtime.ResourceFileManager>

or

XML
<WebApp.Web.Compilation.Runtime.ResourceFileManager>
  <add key="ResourceNameProvider" 
    value="WebApp.Web.Compilation.Runtime.EncodedNameProvider" />
</WebApp.Web.Compilation.Runtime.ResourceFileManager>

Final notes

  • There are changes in the configuration sections compared to the previous version of the library. Please see the source code and demo.
  • Applications complied with the previous version may not be compatible with this one.

Bugs

  • Please report bugs, if any.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior)
Bulgaria Bulgaria
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionhow to use with asp.net 2.0 Pin
boy_yao17-Apr-07 0:35
boy_yao17-Apr-07 0:35 
AnswerRe: how to use with asp.net 2.0 Pin
Jecho Jekov17-Apr-07 22:43
Jecho Jekov17-Apr-07 22:43 
GeneralRe: how to use with asp.net 2.0 Pin
stefanbarlow23-Apr-08 8:46
stefanbarlow23-Apr-08 8:46 
GeneralGeneral question about httpHandlers Pin
icestatue8-May-06 4:26
icestatue8-May-06 4:26 
QuestionHow to call a aspx from different dir? Pin
WilsonTeo14-Sep-05 23:31
WilsonTeo14-Sep-05 23:31 
AnswerRe: How to call a aspx from different dir? Pin
Jecho Jekov15-Sep-05 22:12
Jecho Jekov15-Sep-05 22:12 
GeneralRe: How to call a aspx from different dir? Pin
WilsonTeo20-Sep-05 18:35
WilsonTeo20-Sep-05 18:35 
Hi Jecho, thanks for your advice.

I managed to this trial work after follow your instruction. However, I noticed that I need to put WebApp.Web.Compilation.Runtime and WebApp.Web.Compilation in every "bin" of each subdirectory.

For example, both WebApp.Web.Compilation.Runtime and WebApp.Web.Compilation have to copy into these folder,
C:\Projects\MainMenu\Bin
C:\Projects\MainMenu\Country\Bin

In I my real system, I will have more than 50 of these and that would have many DLL duplication.

Besides, in my web.config I have added some key value for my application, such as,
<appSettings>
<add key="DataConn" value="packet size=4096;integrated security=SSPI;data
source=MySQLServer;persist
security "info=False;initialcatalog=MyDataBase"/>
<add key="PanelBgrdColor" value="#f5f5f5"/>
</appSettings>

And as far as I understood from your previous reply, each subdirectory in fact is a sub program of MainMenu and it will need to include web.config, global and css file.

It will be not practical to have the same web.config to be duplicate into 50 or more subdirectory. Because, that will take long time time to change "key value" in each of the web.config if needed. Pardon me if I was wrong.

Can you see what I am trying to say? I am sure there is a way to avoid these duplication but I just have no clue of it. Can you please advise?

Thank you very much!

GeneralRe: How to call a aspx from different dir? Pin
Jecho Jekov21-Sep-05 3:11
Jecho Jekov21-Sep-05 3:11 
GeneralExcellent article!!! Pin
WilsonTeo13-Sep-05 17:29
WilsonTeo13-Sep-05 17:29 
GeneralI guess i didn't understand but... Pin
JabraJabra12-Sep-05 22:03
JabraJabra12-Sep-05 22:03 
GeneralRe: I guess i didn't understand but... Pin
Jecho Jekov13-Sep-05 2:58
Jecho Jekov13-Sep-05 2:58 
GeneralRe: I guess i didn't understand but... Pin
JabraJabra13-Sep-05 9:36
JabraJabra13-Sep-05 9:36 
GeneralHttpHandler Pin
ChrisAdams8-Sep-05 3:35
ChrisAdams8-Sep-05 3:35 
GeneralRe: HttpHandler Pin
Jecho Jekov8-Sep-05 6:42
Jecho Jekov8-Sep-05 6:42 
NewsThanks Pin
Peter Tewkesbury5-Sep-05 21:59
professionalPeter Tewkesbury5-Sep-05 21:59 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.