Managing ASP.NET Precompiled Output for Deployment Using the aspnet_merge.exe Command


Microsoft Corporation

November 2005


In ASP.NET 2.0, you can precompile a Web site using the aspnet_compiler.exe command-line tool and create a version of a Web site that can be deployed to a server. The tool compiles source files—pages, user controls, resources, utility classes, and other files—into assemblies.

By default, the compiler works in "batch mode," in which the output of multiple source files is compiled into single assemblies according to the type of file, file dependencies, and other criteria. The result is a target site containing a set of assemblies with the executable code for the original source files.

In some instances, the assemblies created with batch compilation may not be ideal for deploying a Web site to a production server. The assembly names are generated automatically by the compiler and it is therefore not obvious which assemblies map to which source files. The compiler also creates new names each time it runs, so that the names of assemblies might not be the same after each compilation. In addition, if source files have changed, the compiler might batch up source files differently, meaning that the resulting assemblies do not necessarily represent the same source files. If you are maintaining a deployed Web site and want to update only the assemblies for recent changes, the output from batch compilation can make that job more complicated.

To help you in this situation, aspnet_compiler.exe supports an option specifically designed for packaging and release management: the -fixednames option. This option enables you to create compiler output that has two benefits. The first is that the assemblies produced by the compiler have the same names each time you compile. The second is that the assemblies are based on the same input files each time.

Even when you use the -fixednames option, however, the resulting assembly names can still be somewhat cryptic. More importantly, when you use the fixednames option, the compiler can produce numerous assemblies—one for each compiled source file.

When creating deployable Web applications, developers who work with large Web sites require the following features:

  • The ability to manage output assemblies and files. In Visual Studio .NET 2003, the build operation creates a single assembly, which makes deployment of the assembly relatively simple. However, Web UI content files (ASP.NET pages and user controls) are still dynamically compiled on the server and also require deployment. (Using the term "single assembly" to refer to the output of building in Visual Studio .NET 2003 is not completely correct; code-behind files are compiled into a single assembly, but page assemblies are still dynamically generated and either batch compiled or compiled individually.)
  • The ability to explicitly name the resulting output assembly or assemblies rather than relying on the auto-generated assembly names.
  • The ability to more easily compare ("diff") builds so that release management and deployment processes can be streamlined.

The ASP.NET 2.0 compiler provides some of these abilities when you use the -fixednames option, but it does not enable you to name the resulting assemblies, or to be able to produce just one or a few assemblies.

To address these issues, a new merge utility named aspnet_merge.exe has been created, which enables you to combine and manage the assemblies created by the compiler. The merge tool and its use are described in this article.

A Web Site Example

To illustrate how the compiler and merge tool work together, imagine that you have created a Web site using the Personal Web Starter Kit in Visual Studio 2005. The site's file structure is shown in Figure 1.


Figure 1. An example Personal Web Site created using Visual Studio 2005

Note the following about the site content and layout:

  • Web UI content files (.aspx files, .master files, and .ascx controls) appear in several folders in the application.
  • The site contains static content such as .jpg and .css files.
  • Utility classes are defined in the App_Code folder.

A typical development cycle for a Web site like this one go through these stages:

  • Design and development   Designers and developers create the Web site using Visual Studio 2005, testing and modifying in an iterative manner. For this stage, dynamic compilation used in Visual Studio 2005 and ASP.NET 2.0 improves the rapid development process in comparison with Visual Studio 2003 and ASP.NET 1.1.
  • Build   The application can be checked into source control and synchronized through a build server. A developer might create a custom build script to run aspnet_compiler.exe and aspnet_merge.exe and other tools. (The developer responsible for deployment could also use a new Web Deployment Projects to create an MSBuild project, as described in the "Visual Studio 2005 Web Deployment Projects" section later in this article.). The build scripts might be responsible for creating the deployable targets or the packaged targets.
  • Deployment   The scripts or MSBuild project might also create the deployable Web site, which is moved to staging or production/release server.
  • Test   The team tests the application using the staging server.
  • Production/Release   The staged build is moved to a production/release server.
  • Maintenance   The team runs a process to propagate changes to the staging or production/release server.
  • There are obviously many possible variations in this idealized process, such as creating setup files (an .msi file) or creating processes to manage incremental updates, store daily builds, implement release management processes, and so on. In all of these scenarios, the aspnet_compiler.exe and aspnet_merge.exe tools can play an integral part in your Web site development processes. Using Visual Studio 2005 Web Deployment projects can further enhance many aspects of build, merge, and deployment processes.

This article does not investigate these processes but concentrates on the aspnet_compiler.exe and, more importantly, the aspnet_merge.exe tools that you can use on a build server or through Visual Studio 2005 Web Deployment Projects.

A Note about the Examples in this Article

The examples in this article show using aspnet_compiler.exe with the -v option, because the site is assumed to be configured as an application in IIS. However, the compiler can work with a physical path specified using the -p option. If you use the -p option, aspnet_compiler.exe treats any subfolders under the root as folders belonging to the root Web site. This can lead to compilation errors if those folders are Web sites in their own right. If you use the -v option without the -p option, aspnet_compiler.exe can determine which subfolders are part of the root application.

If you use the -p option, the -v option is used for a number of purposes such as resolving the location of the ~ operator and providing a folder in the Temporary ASP.NET Files folder under the installation directory.

All example commands are assumed to be executed in the example Web site's root folder.

Precompilation Overview

Before you examine the new merge tool, it is useful to review the functionality of the ASP.NET 2.0 compiler (aspnet_compiler.exe). The compiler is shipped with the .NET Framework version 2.0. You can run the compiler from the .NET Framework installation folder (typically %windir%\Microsoft.NET\Framwork\version) or from within Visual Studio 2005 Professional Edition or Visual Studio 2005 Enterprise Edition.

Using the ASP.NET compiler, you can precompile the Web application into several deployment forms, each of which removes source code from the Web application. The compiler can also optionally remove Web UI content pages (.aspx, .master, and .ascx files).

The descriptions of the aspnet_compiler.exe and aspnet_merge.exe tools refer to two assembly groups:

  • Web UI content assemblies   These assemblies are generated for the Web UI content itself (.aspx, .master, and .ascx files, and any associated code files).
  • Top-level assemblies   These assemblies are generated by the compiler from special-purpose folders such as App_Code, App_GlobalResources, and App_WebReferences, and for special files such as Global.asax.

The aspnet_compiler.exe command generates output consisting of a layout structure that mirrors the source site, with the compiled object code placed in the target application's Bin folder.

The compiler supports precompilation with two types of outputs: output for deployment and output in place.

Precompilation for Deployment

Precompilation for deployment creates a set of files that you can deploy to a server as a working Web application. Precompilation for deployment enables you to produce two types of output:

  • Non-updatable precompilation for deployment removes all markup as well as source code from the target. In this option, all source for top-level assemblies and Web UI content files is removed from the production environment. (Contrast this with ASP.NET 1.1, where Web UI content files are always dynamically compiled.)
  • Updatable precompilation for deployment retains the markup in Web UI content pages and results in a target site that is similar to that created by Visual Studio .NET 2003.

The compiler's -fixednames option affects both forms of precompilation for deployment. It performs compilation that creates assemblies with specific (fixed) names and generates a single assembly per Web UI content file.

Precompilation in Place

Precompilation in place performs batch compilation that creates assemblies directly in the source site and does not produce a new target layout. To precompile in place, you run the compiler with the -v option referencing the Web site virtual directory (if IIS is installed on the computer) or with the -p option referencing the physical source path.

Precompilation in place is mentioned here for completeness, but does not produce output that would be combined with aspnet_merge.exe in a build system. Precompilation in place can produce a production Web site that retains all source code, but that does not experience the "compilation penalty" that the first request to the Web site can incur.

Precompilation — Removing Code and Markup

Returning to the example Web site, imagine that you create non-updatable output by precompiling the Web site for deployment using the command shown in Figure 2, which uses the virtual path to the Web site (named psw), and specifies an output folder named pswcompile.


Figure 2. Running aspnet_compiler.exe with the -v option

The compiler generates the target site (pswcompile) shown in Figures 3 and 4. In Figure 3 you can see that the source Web site structure is retained. For example, the Admin folder remains and other static Web UI content such as Welcome.html is copied as is to the pswcompile folder. Although it appears that the .aspx files have been copied, closer inspection reveals that these are really dummy markup files and that their content is simply a string value. In this case, all markup (HTML and Web server controls) has been removed.

The target Web site contains no source files at all and the Web UI content assemblies have been created in the Bin folder, as shown in Figure 4. The aspnet_compiler.exe command generates .compiled files in the Bin folder; these indicate to ASP.NET the class to instantiate for a request to a specific page or to a specific virtual path.

If you open a .compiled file in a text editor like Notepad, you will see that the file has references to the compiled page. This enables ASP.NET to determine the page's original location in the file structure. You can also see the assembly name that contains the compiled output resulting from the page. The assembly name is automatically generated by the compiler and is created in a way that guarantees uniqueness.

Note   Precompiling for deployment performs a new build every time and aspnet_compiler.exe creates different assembly names each time. In addition, the files used as the source of the assembly might change from build to build. This means that it would be difficult to consistently know for release management what assemblies were created as a result of changes. These are the primary reasons for the –fixednames option.


Figure 3. Precompiled output in the pswcompile folder


Figure 4. Precompiled output in the pswcompile\Bin Folder

Precompiling with Fixed Names

Imagine that you compile the Web site with the -fixednames option as in Figure 5.


Figure 5. Compiling with the -fixednames option

Using the -fixednames option results in more assemblies in the pswcompile\Bin folder, as shown in Figure 6. Each assembly represents one page, user control, or master page. As the option name suggests, the assembly names are the same from build to build. The assemblies are named using the format App_Web_filetype.nnnn.dll where nnnn is a hash value.


Figure 6. Precompiled output in the pswcompile\Bin Folder after compiling with the -fixednames option

Precompiling — Removing Only Code

You can precompile a Web site so that the deployable target directory (pswcompile in the example) retains the markup in Web UI content pages. Figure 7 shows an example aspnet_compiler.exe command to generate a precompiled Web site for deployment. The site then allows limited modifications to the site's pages. These can be layout changes, but not control ID changes or new controls that require code such as event handlers.


Figure 7. Running aspnet_compiler.exe to retain markup in ASP.NET pages and user controls

Figures 8 and 9 show the results in the pswcompile folder and the Bin folder.


Figure 8. Precompiled output in the pswcompile folder


Figure 9. Precompiled output in the pswcompile\Bin folder

Figure 8 shows that as with the earlier compilation, the Web site structure has been retained and that the static Web UI content such as Welcome.html has been copied to the pswcompile folder. Figure 9 shows that the Web UI content assemblies and the top-level assemblies such as App_Code.dll have been generated in the pswcompile\Bin folder.

You can see the difference in this form of precompilation when you look at the Web UI content pages themselves. Notice in Figure 9 that the pswcompile\Bin folder no longer contains the .compiled files, because the Web UI content pages themselves are retained. Instead of acting as dummy files as in the earlier compilation, the .aspx pages are modified to inherit from a different assembly, as shown in Figure 10. After precompilation, the page inherits from an assembly that resides in the Bin folder, and any previous codeFile reference is removed.


Figure 10. Modified inherits attribute in precompiled .aspx file

Precompiling with Fixed Names

It is possible to precompile the site to retain markup and to use fixed names using the using the syntax shown in Figure 11. As before, using the -fixednames option results in more assemblies in the Bin directory.


Figure 11. Running aspnet_compiler.exe to retain Web UI content markup and to use fixed assembly names

Merging Assemblies Using aspnet_merge.exe

As you have seen, the aspnet_compiler.exe ordinarily produces output assemblies either in batch mode or by creating an assembly with a fixed name for each compiled file. In these cases, there are benefits to you as an enterprise developer depending on your Web site characteristics and your plans for deployment and release management.

However, in other cases, the outputs are too numerous or not named conveniently for your purposes. The aspnet_merge.exe command is designed to make these cases much easier.

The aspnet_merge.exe tool combines assemblies that are created by the compiler. The merge tool enables you to combine:

  • All assemblies generated by ASP.NET (not custom assemblies) in a precompiled Web site into a single named assembly.
  • All Web UI content assemblies into a single named assembly.
  • Web UI content assemblies into an assembly for each folder in the Web site.
Note   In Visual Studio .NET 2003, when you build a project, you build the code-behind files and other class files into an assembly for the Web site. This assembly can be deployed to a production server without the need to deploy the source code. You must also deploy all markup pages to the production server. To make an incremental update to the site, you redeploy the code-behind assembly and relevant markup pages. However, the single assembly has its own drawbacks. Building the assembly can take a long time, which can result in a dramatic delay when you press F5 or CTRL-F5 during development. Furthermore, any change to any code-behind class file requires you to rebuild the entire assembly. From a test perspective, creating a new assembly technically invalidates all pages in the Web site and might require retesting all pages.

With ASP.NET 2.0, you can now use a combination of dynamic compilation, precompilation using the aspnet_compiler.exe, and merging using aspnet_merge.exe to best suit your development and deployment needs. The following table lists patterns for when to use each type of compilation and when to use the merge utility.

During development: Use dynamic compilation.Use Visual Studio 2005 and dynamic compilation with ASP.NET 2.0.

This offers rapid development because you can configure projects not to perform a full build when you press F5 or CTRL+F5. In fact, you can disable building altogether. In that case, the page you are working on (and its dependencies) is compiled dynamically by ASP.NET 2.0 when you run the page inside Visual Studio 2005. In that case, you can develop and debug a particular page even if other pages contain errors.

Because Visual Studio 2005 uses ASP.NET compilation, you get full fidelity between Visual Studio and ASP.NET compilation, including all code and parse time errors in the IDE. (On-the-fly ASP.NET 2.0 dynamic compilation also provides custom IntelliSense in the editors.)
For deployment: Create a single assembly for each Web UI content file.Precompile using the -fixednames option to generate a target with Web UI content assemblies for each file.

This scenario offers very granular release management because you can make incremental updates (down to the Web page level) with little effect on other pages. You can generate both updatable and non-updatable precompiled Web sites with this option.

For large sites, many assemblies are created and scalability may be a concern.

The assemblies are cryptically named, but using a combination of the page and the .compiled files, it is possible to determine which file generates which assembly.

Static Web content and custom assemblies are unaffected.
For deployment: Create an assembly for each Web UI content folder.Precompile and then use aspnet_merge.exe to create separate assemblies for each folder containing Web UI content.

Creating an assembly per Web UI content folder results in a number of assemblies. If you omit the –u option when compiling, you can create a Web site that deploys assemblies and just the dummy pages, so that the markup is also removed from the deployed Web site.

Making a change to any file in a folder requires you to redeploy the folder assembly and the modified pages. If you can limit test processes to work only against that folder, you can assume that other folders are still valid. In practice, however, if the markup pages are retained in this Web site, then adding any new assemblies to the Bin folder will cause all pages to be re-compiled.

By default, the assembly names are based on the folder name, but you can prefix the assemblies with a custom name. Top-level assemblies are unaffected when you use this option. Static Web UI content and custom assemblies are also unaffected.

For deployment: Create a single assembly for all Web UI content files.Precompile the site and then use the aspnet_merge.exe to generate a single Web UI content assembly for the entire Web site.

With a single assembly for Web UI content, you create a deployable Web site that is similar to the output created in Visual Studio .NET 2003. If you omit the –u option when compiling, you can deploy assemblies and just the dummy pages so that the markup is also removed from the deployed Web site.

To update a deployed Web site, you can deploy the recompiled assembly and any modified Web UI content files.

If you change any Web UI content files, you must redeploy the entire assembly with the relevant .compiled and .aspx pages. On the production server, the markup pages are retained, but these be dynamically recompiled also, which might invalidate the results of any test processes for those pages.

You can assign a custom name to the assembly as part of the merging process. Top-level assemblies are unaffected when you use this option. Static Web UI content and custom assemblies are also unaffected.
For deployment: Create an assembly for the entire Web site.Precompile and then use aspnet_merge.exe to generate a single assembly that combines Web UI content assemblies and top-level assemblies.

By creating a single assembly for the entire Web site, you can easily manage the release process. You will be able to deploy the single assembly and any updated Web UI content files. If you omit the -u option when compiling, you can create a Web site containing only the assembly and the dummy pages, with the markup also removed from the deployed Web site.

If you make any change to any file in the Web site, you must redeploy the assembly and potentially the dummy pages. This might invalidate the results of any test processes for the entire Web site.

You can assign a custom name to the assembly. Static Web UI content and custom assemblies are unaffected.

Aspnet_merge.exe merges assemblies only in a precompiled Web site; it will work only with known precompiled assemblies. It will not modify custom assemblies or the App_licenses.dll assembly in the Bin folder.

Note    Aspnet_merge.exe performs its operations in place. The precompiled Web site will be modified and assemblies that are combined are removed. Be sure to back up your precompiled site before merging unless you are comfortable rerunning aspnet_compiler.exe against the source files.

Merging Content Assemblies for Each Folder

When you run aspnet_merge.exe without any options except the target folder name, it creates output assemblies for each Web UI content folder. The syntax for this type of merge is shown in Figure 12.


Figure 12. Running aspnet_merge.exe with no options

This default merge operation results in fewer assemblies than the number of assemblies generated by the compiler -fixednames option. This form of merging might be useful if you plan to deploy incremental updates to a production server.

Merging in Non-updatable Precompiled Web Sites

Figure 13 shows the result of running aspnet_merge.exe without any options on a non-updatable precompiled site. (The illustration shows the results of merging the precompiled output illustrated in Figure 2.) The assemblies have been renamed to include the folder name (App_Web_filetype.nnnn.dll). In addition, there are two assemblies named Root.dll and Admin.dll (circled in red), which result from merging folders in the Web site—the Web UI content in the root folder and in the psw\Admin subfolder, respectively. The Bin folder still contains the top-level assemblies such as App_Code.dll. Themes have also been compiled and merged into a single Themes.dll assembly (circled in blue).

Aspnet_merge.exe can work with assemblies generated either with or without the aspnet_compiler.exe command's -fixednames option. It automatically handles merging the assemblies for any particular folder.


Figure 13. Results from merging Web UI content folders in a non-updatable precompiled Web site

For non-updatable precompiled Web sites, the compiler creates .compiled files for .aspx files. ASP.NET uses the .compiled files to instantiate the correct type for a Web request. The merge tool updates these files so that the new merged assemblies are referenced instead. Figure 14 shows the effect in a .compiled file of a merge operation.


Figure 14. A modified .compiled file after a merge operation

Because the folder name is used to identify the merged assembly, it is relatively simple to determine the assembly for a set of Web UI content files in the Web site. However, you might want to use your own naming conventions, so aspnet_merge.exe enables you to specify a prefix for these assemblies by using the -prefix option, as shown in Figure 15.


Figure 15. Running aspnet_merge.exe with the -prefix option

Figure 16 shows the assembly created as the result of merging with the -prefix option. You can see that the Root.dll is now named Contoso.dll and the Admin.dll is now named Contoso.Admin.dll.


Figure 16. Results from merging a non-updatable precompiled Web site using the -prefix option

Note   In Web sites with local resources, local resources are ordinarily treated as Web UI content. However, the merge tool does not process the local resources because local resources by their nature are already folder specific.

Merging in Updatable Precompiled Web Sites

Merging assemblies in an updatable precompiled Web site results in the same merged output as merging in a non-updatable Web site. The difference is that aspnet_merge.exe modifies the markup pages, such as .aspx pages, to point to a merged assembly. As with a non-updatable site, assemblies are produced for each folder and the merge tool applies the same naming conventions. Figure 17 shows the Bin folder of the example site after merging. Notice that there are now two assemblies for Web UI content, Root.dll (resulting from Web UI content in the root psw folder) and Admin.dll (resulting from Web UI content in the psw\Admin subfolder).


Figure 17. Results from merging Web UI content folders in an updatable precompiled Web site

However, there are some subtle differences when it comes to updatable precompiled Web sites. Themes remain untouched because in an updatable precompiled Web site, themes are not compiled. Similarly, local resources remain untouched because these are also regarded as Web UI content and can be modified. The compiler does not create .compiled files for .aspx, .master and .ascx files; these remain in the application. However, during the merge process, these are modified to point to the new merged assembly, as shown in Figure 18.


Figure 18. A modified .aspx file after a merge operation

Combining Precompiled Web UI Content into a Single Assembly

Rather than deploy assemblies individually for each Web UI content folder, you can use aspnet_merge.exe to generate a single assembly for all Web UI content. This enables you to manage the assembly for the Web UI content as a unit. It also enables you to assign a name to the merged assembly. Figure 19 shows the syntax for creating a single assembly for all Web UI content.


Figure 19. Running aspnet_merge.exe to create a single assembly for all Web UI content

The command in Figure 19 generates a single assembly named Contoso.dll for all Web UI content and puts the assembly in the Bin folder. Top-level assemblies are not touched. All .compiled files, or alternatively all .aspx, .master, and .ascx files, are modified to reference this single assembly.

Figure 20 shows the results in the pswcompile\Bin folder of merging the Web UI content into a single assembly in a non-updatable precompiled Web site.


Figure 20. Results in the pswcompile\Bin folder from merging Web UI content folders in a non-updatable precompiled Web site

Combining Precompiled Web UI Content and Top-level Assemblies

So far you have seen the results from merging Web UI content assemblies. But aspnet_compiler.exe generates many other assemblies as part of a Web site. Among these are the top-level assemblies that result from compiling the contents of the App_Code folder and other specialized folders.

In precompiled Web sites, these assemblies are named after their source folder. This means that the assemblies are already compiled to the folder level. Changes to files that affect these assemblies mean that the Web UI content files must be recompiled, even if they have not changed. This must be factored into any release management process.

Aspnet_merge.exe enables you to merge top-level assemblies into a single assembly that combines the top-level assemblies and the Web UI content assemblies. To create a single, merged assembly for the Web site, add the -o option to the merge command and specify an assembly name. Figure 21 shows an example of the syntax.


Figure 21. Running aspnet_merge.exe to create a single assembly from top-level and Web UI content assemblies

Figure 22 shows the result of merging with the -o option when working against the files illustrated in Figure 2. For this type of merge, aspnet_merge.exe requires an output assembly name, which is used to name the single file (Contoso.dll). No other assemblies result from this merge operation.


Figure 22. Results from merging all assemblies using the -o option

If the original site contains local resources, the local resources are not touched by the merge process, because it is not possible to merge local resources into a large resource assembly. Similarly, global resources are not merged.

Assembly Attributes in Merged Assemblies

When aspnet_merge.exe combines assemblies, by default it carries forward the assembly attributes from an initial source assembly in the merged set to the final merged assembly. Because the source assemblies can be marked with different attributes, it cannot be determined easily what attributes are applied to the merged assembly.

To avoid ambiguity of attributes in the merged assembly, you can instruct aspnet_merge.exe to use the assembly attributes defined for the App_Code assembly as the source attribute set, or to use a specified assembly as the assembly defining the attributes.

For example, Figure 23 shows an Assemblyinfo.cs file that might be added to the App_Code directory in the Web site shown in Figure 1.


Figure 23. Assemblyinfo.cs file added to the App_Code folder

If you do not merge assemblies, only the App_Code assembly will be marked with these attributes. (You could see this by inspecting the assembly with a tool such as Ildasm.exe.) To mark the merged assembly with the attributes defined for the App_Code assembly), use the -copyattrs option, as shown in Figure 24.


Figure 24. Running aspnet_merge.exe to use the attributes defined for the App_Code assembly for the final merged assembly

The -copyattrs option causes the attributes for the App_Code assembly to be used even if App_Code.dll, a top-level assembly, is not included in the merge. This might be the case if you are merging only Web UI content assemblies. The following listing shows a snippet from the manifest in the IL for the Contoso.dll assembly generated by the command illustrated in Figure 23.

.assembly Contoso
  .... AssemblyFileVersionAttribute:.. =   // ...1.0.4567.0..
  .... AssemblyDescriptionAttribute:.. =   // ...Contoso's Web Site..
  .... AssemblyProductAttribute:.. =       // ...Contoso.Web..
  .... AssemblyCompanyAttribute:.. =       // ...Contoso..
  .ver 1:4000:0:0

To specify the attributes from a different assembly, and not from the App_Code assembly, provide an assembly name with the –copyattrs option. One way to use this option is to create an assembly from an AssemblyInfo.cs or AssemblyInfo.vb file, and then use that assembly only for marking attributes in the merged assemblies.

Signing Merged Assemblies

A development team might want to sign precompiled applications for the following reasons:

  • To ensure that the assemblies are verifiable as originating with the specified development team. The signature or key can be used only by that organization and provides some degree of confidence that the assemblies originate from the given company.
  • To lock a production computer to allow trust for assemblies that are signed with known keys, and to allow no execute privileges for assemblies with unrecognized keys or with no key.

Merged and signed Web site assemblies can be added to the GAC to be shared between applications. However, this can introduce problems with resource URL basing (such as for images), among other issues. In general, adding precompiled or merged assemblies to the GAC is not recommended. In some limited situations, such as an assembly created from just user controls that do not reference external resources, adding a merged and signed assembly to the GAC might be an option.

You can sign assemblies in the precompiled site using aspnet_compiler.exe. However, if you merge assemblies, you must sign the assemblies using the merge tool.

When merging precompiled Web sites, it is possible that the assemblies have already been delay signed or signed using aspnet_compiler.exe. During the merge, you can sign the merged assemblies from either pre-signed or unsigned bits. To sign the resulting merged assemblies, you can use the following options with aspnet_merge.exe: -keyfile, -keyContainer, or -delaysign. If you run aspnet_merge.exe to merge pre-signed assemblies and do not provide any signing options, the resulting assemblies will be unsigned.

The following commands show how to merge the precompiled assemblies into the single assembly named Contoso.dll and sign the assembly using Aspnet_merge.exe.

  1. Create a key file with public and private keys:
    sn –k contoso.snk 
  2. Precompile the Web site without signing:
    aspnet_compiler -v psw pswcompile
  3. Merge the Web application and sign it:
    aspnet_merge pswcompile -keyfile contoso.snk -o Contoso

Delay Signing Merged Assemblies

The steps for delay signing using Aspnet_merge.exe are as follows:

  1. Create a key file with public and private keys. In general, you keep the public and private keyfiles in a secure location that is accessible only to a limited set of users. The syntax is:
    sn –k contoso.snk 
  2. Extract the public key from that file to another key file:
    sn –p contoso.snk contosopublicKey.snk
  3. Precompile the Web site without signing:
    aspnet_compiler -v psw pswcompile
  4. Merge and delay sign the assemblies, specifying the -delaysign and -keyfile options:
    aspnet_merge pswcompile -delaysign -keyfile contosopublicKey.snk -o Contoso

Applying APTCA to Merged Assemblies

If your precompiled Web site will operate in a security level other than full trust, you must ensure that the assemblies are precompiled using the -aptca option (Allow Partially Trusted Callers Attribute) with aspnet_compile.exe. This means that the appropriate assembly-level attribute will be added to the compiled assemblies. The attribute will be maintained in the merged assemblies resulting from aspnet_merge.exe.

Note   If some source assemblies, but not all, are marked with the AllowPartiallyTrustedCallersAttribute (APTCA), aspnet_merge.exe does not carry forward the source assembly attributes. Instead, it raises an exception. This ensures that the merged assembly does not provide a different level of trust to some code than was originally intended. You can change this behavior by ensuring that all assemblies are marked with APTCA before merging or by merging with the -a option. However, be aware that using the –a option when merging means that assemblies not previously marked with APTCA might now be marked with that attribute. As a result, you might be allowing partially trusted code to call on the assembly, which it previously could not.

The steps for applying APTCA are as follows:

  1. Precompile the site with the -aptca option:
    aspnet_compiler -v psw pswcompile –aptca
  2. Merge the assemblies:
    aspnet_merge pswcompile –o Contoso

Versioning Merged Assemblies

If you want to add versioning information to the assemblies generated for a precompiled Web site, you can do the following:

  • Add an AssemblyInfo.cs or AssemblyInfo.vb file to the App_Code folder. The assembly generated for the App_Code folder will then be versioned. You can also add version attributes to the code-behind files for pages and user controls. However, adding version attributes to individual files is tedious and applies only to code-behind files in an updatable precompilation layout.
  • Add references to an AssemblyInfo.cs or AssemblyInfo.vb file to the compilerOptions attribute of the <compiler> element in the Web.config file. This enables you to add versioning for all assemblies generated for the Web site. In that case, you must include both C# and Visual Basic compilers because ASP.NET might select a compiler for non-code type files, such as WSDL, when compiling the proxies.

Aspnet_merge.exe can version the assemblies it creates by either copying the attributes from the App_Code assembly or copying them from a specific assembly specified using the –copyattrs option. This is therefore treated like any other assembly attribute. These options for specifying an attribute for the merged assembly or assemblies ensures that you can define all version attributes, including the file version, the assembly version, and any other assembly attributes you require.

Figure 25 shows the merge command used to apply attributes from the App_Code assembly, using the Web site shown in Figure 1. The AssemblyInfo.cs file shown in Figure 22 has been added to the Web site's App_Code folder.


Figure 25. Running aspnet_merge.exe to use the attributes defined for the App_Code assembly in the final merged assembly

The following listing shows a snippet of the full metadata that is applied to Contoso.dll when running the preceding command:

.assembly Contoso
  .... AssemblyFileVersionAttribute:.. =  // ...1.0.4567..
  .... AssemblyDescriptionAttribute:.. =  // ..!Contoso Personal Web
// Site Starter Kit..
  .... AssemblyProductAttribute:.. =      // ...Contoso.Web..
  .... AssemblyCompanyAttribute:.. =      // ...Contoso..
  .ver 1:0:4000:0

If you look at the properties for the .dll file, you can see the attribute reflected there:


Figure 26. Contoso.dll assembly attributes and properties

Creating Debug Output for Merged Assemblies

You can create debug output files (.pdb files) during compilation. By default, aspnet_compiler.exe creates retail output and ignores any debug options in the Web.config file or in .aspx pages, master-pages, or user controls. To create debug output, use the -d option when compiling, as shown in Figure 27.


Figure 27. Running aspnet_compiler.exe with the -d option to create debug output

To merge debug output files, use the -debug option with aspnet_merge.exe. Without the -debug option, the merge process removes any debug output in the Web site. If you merge a site that includes debug output and create a single assembly using the –o option, you will find that the pswcompile\Bin folder contains a single merged .pdb file. Figure 28 shows the aspnet_merge.exe command for creating debug output, and Figure 29 shows the resulting output in the Bin folder.


Figure 28. Running aspnet_merge.exe to merge debug output for the entire site


Figure 29. Results from merging debug output for the entire Web site

Using aspnet_compiler.exe and aspnet_merge.exe in a Build Environment

Visual Studio 2005 Professional Edition and Visual Studio 2005 Enterprise Edition include menu commands to perform precompilation (Build > Publish Web). Although Visual Studio 2005 enables you to precompile for deployment, by default it does not enable you to add pre-build or post-build actions directly in a Web site project. As a consequence, you cannot easily add merge commands to the build within Visual Studio 2005.

To address this requirement, you can use the new Web Deployment Projects feature, which you can download and install separately. The installation for Visual Studio 2005 Web Deployment Projects includes the aspnet_merge.exe tool. Web Deployment Projects give you functionality inside Visual Studio 2005 that is otherwise available only by running command-line tools and manually editing build-related files.

A development team therefore has the following options for building:

  • Using aspnet_compiler.exe and aspnet_merge.exe sequentially in a custom build operation. Typically enterprise development teams construct custom build scripts to suit their own build server scenarios.
  • Using aspnet_compiler.exe and aspnet_merge.exe in a manually created MSBuild file. It is possible to manually add custom tasks within an MSBuild file that can then run on a build server.
  • Using the aspnet_compiler.exe and aspnet_merge.exe tools through a Web Deployment project associated with a Web site in Visual Studio 2005. This provides a UI for many features, and can also be executed through MSBuild.

Visual Studio 2005 Web Deployment Projects

Web Deployment projects enable you to control the assemblies for a build and to manage further actions required to create a deployable Web site. You can associate a Web Deployment project with your Web site by adding a new Web Deployment project to the solution that contains the Web project. Figure 30 shows the Web Deployment project psw_deploy associated with the Web site C:\work\psw.


Figure 30. Visual Studio 2005 Web Deployment project node in Solution Explorer

Once you open Visual Studio 2005 and create a Web site, you can add a Web Deployment project to the solution by right-clicking the Web site node in Solution Explorer and choosing Add Web Deployment Project. By right-clicking the Web Deployment project in Solution Explorer, you can then display property pages that enable you to configure many deployment settings. Visual Studio 2005 Web Deployment projects enable you to do the following:

  • Configure multiple build operations such as Debug, Release, or Staging builds using aspnet_compiler.exe options.
  • Configure the merge operation in those configurations.
  • Handle versioning and signing.
  • Manipulate assembly names during merge.
  • Define further actions such as modifying the Web.config file as part of the deployment process.
  • Modify the project file directly, which enables a wealth of custom scenarios.
  • Disable building the project at development time, or disable building the Web site itself when creating the deployment target.

You can also manually edit the project file and add custom tasks or actions as pre-build and post-build operations. For more information, see the article Using Web Deployment Projects with Visual Studio 2005 on the MSDN Web site.

Figure 31 shows the property page for setting options for output assemblies.

Click here for larger image

Figure 31: The Output Assemblies property page for a Visual Studio 2005 Web Deployment project.

You can see that there are several options here that correspond to the options available for the aspnet_merge.exe tool.

Aspnet_merge.exe Help

There are many options described in this article for aspnet_merge.exe. You can get additional help for these and others not described here by running aspnet_merge.exe with the -? option.


Aspnet_merge.exe is a new utility that helps you manage your Web site production environment. The merge tool combines the potentially numerous assemblies generated by the ASP.NET compiler, aspnet_compiler.exe, when precompiling a Web site. This enables you to more easily manage a publishing process or a release management process that uses the outputs created by the ASP.NET compiler.

This article describes various options that you can use with the merge tool, and describes how to use the merge tool in conjunction with precompiling a Web site. The examples in the article show the commands that you can incorporate into a custom build model.

Aspnet_merge.exe is installed with the new Web Deployment Projects add-in for Visual Studio 2005. This add-in provides a comprehensive UI for managing options for the aspnet_compiler.exe and aspnet_merge.exe tools, and enables you to manage creation of a deployable Web site from within Visual Studio. Web Deployment projects also include facilities for adding pre-build and post-build steps necessary for managing Web site deployment.

This is a preliminary document and may be changed substantially prior to final commercial release of the software described herein.

The information contained in this document represents the current view of Microsoft Corporation on the issues discussed as of the date of publication. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information presented after the date of publication.


Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation.

Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property.

Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places, and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place, or event is intended or should be inferred.

© 2005 Microsoft Corporation. All rights reserved.