Using MSBuild and ILMerge to Package User Controls For Reuse

One of the advantages to ASP.NET server controls is the ability to package them into an assembly and reference them from other web applications. Server controls are relatively difficult to write but easy to reuse. User controls (ascx files), on the other hand, are relatively easy to develop, but don't like to swing with other projects. A common solution in 1.x involves setting up virtual directories. Yuck.

The ASP.NET 2.0 environment is different. We have MSBuild. We have an ASP.NET compiler. Perhaps you've also noticed we have a tool by the name of ILMerge.

Here is a proof of concept.

Step 1: I created a new solution in Visual Studio 2005 and added a plain class library project. I then added two user controls to the project, which Visual Studio doesn’t like initially, but it does all work, even the intellisense. The first user control is all inline code:

<%@ Control Language="C#" ClassName="SayHello" >

<script runat="server">
  <protected void Page_Load(object sender, EventArgs e)
  {
    label.Text = "Hello at " DateTime.Now.ToShortTimeString();
  }       
</script>

<asp:Label runat="server" ID="label"/>

The second control, SayGoodbye.ascx, is the same, except it puts the Page_Load logic into a separate CodeFile by the name of SayGoodbye.cs.

Step 2: One of the cool features of Visual Studio 2005 is that the project files are MSBuild files. The default .csproj file for the class library I created does not know what to do with .ascx user control files, but I help it. I can right-click the project and select unload, then right-click the now disabled project and select Edit. Behold - the project is exposed naked before me. Pure angle-brackety goodness.

What I want to do at this point is modify the project to run the ASP.NET precompilation task – easy enough since there is an MSBuild task available by the name of AspNetCompiler. What is tricky is that AspNetCompiler will likely produce multiple assemblies. The compilation tool will batch compile by default, which means one assembly per directory of user control files. Of course we don’t want to keep all the ascx files in the root of the project, and we don't want to reference an entire directory of .dll files, so this is where ILMerge comes in.

ILMerge is a utility to merge multiple .NET assemblies into a single assembly. Combining AspNetCompiler and ILMerge together gives us something like the following:

<Project DefaultTargets="CompileUserControls" 
         xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
           ...
  <Target Name="CompileUserControls">
    <!-- TargetPath cannot be underneath PhysicalPath :( -->
    <AspNetCompiler 
      Debug="false"
      PhysicalPath="$(MSBuildProjectDirectory)" 
      TargetPath="$(TempDirectory)" 
      Updateable="false" 
      Force="true" 
      VirtualPath="$(MSBuildProjectName)" />

    <CreateItem Include="$(TempDirectory)\bin\*.dll">
      <Output ItemName="PrecompiledAssemblies" TaskParameter="Include" />
    </CreateItem>
    
    <Exec Command="$(ILMergeEXE) /out:$(MSBuildProjectName).dll 
                    /targetplatform:v2 @(PrecompiledAssemblies, ' ')" />
  </Target>
    ...

Inside the target I first run the AspNetCompiler and produce all the user control assemblies. Next, I need a list of all the assemblies the compiler just spit out. I do this with , which produces the Item PrecompiledAssemblies (thanks to Chris Tavares and the Chris Sells' Win-OT list for figuring this out). The last piece is to execute the ILMerge tool, passing all the assembly names as command line arguments.

Plop! Out comes ReusableControls.dll.

For the last step, I created a new web project and referenced ReusableControls.dll, then created a little test aspx web form.

<%@ Page Language="C#" %>
<%@ Register TagPrefix="rc" Namespace="ASP" Assembly="ReusableControls" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<form id="form1" runat="server">
   <rc:SayHello runat="server" ID="hello" />
  
   <br />
  
   <rc:saygoodbye_ascx runat="server" ID="goodbye" />
  <br />
</form>

Notice in the @ Register directive we need to specify a namespace of ASP, as this is the default given by the AspNetCompiler. The compiler also munges the user control name when a CodeFile is used – we are using the class that was code-generated from the SayGoodbye.ascx file and inherits from the SayGoodbye class in the CodeFile. With inline code there is no adjustment.

It might be possible to also re-use master pages and webforms with a little bit of VirtualPathProvider trickery, but I’m not going there as yet. I want to see how this will shake out at RTM time when combined with the Build Project that should arrive, as announced by others.

posted on Thursday, October 06, 2005 5:46 PM by scott

Comments

Thursday, October 06, 2005 3:09 PM by Stan

# re: Using MSBuild and ILMerge to Package User Controls For Reuse

This rocks! but how did you get the MSBuild file into the solution explorer?
Thursday, October 06, 2005 3:15 PM by scott

# re: Using MSBuild and ILMerge to Package User Controls For Reuse

The beauty of the system is MSBuild file == .csproj file, so VS2005 groks it. Once you edit the file by hand, just right-click and "reload project". VS2005 will run MSBuild against the project.
Friday, October 07, 2005 4:26 AM by Jason Haley

# Interesting Finds

Friday, October 07, 2005 9:08 AM by Raghu

# re: Using MSBuild and ILMerge to Package User Controls For Reuse

In 1.x, I had used virtual directories approach. This is really very cool way to reuse user control cross project.
Good digging scoot!!!
Friday, October 07, 2005 6:44 PM by scott

# re: Using MSBuild and ILMerge to Package User Controls For Reuse

The MSBuild team has the annoucement, too:

http://blogs.msdn.com/msbuild/archive/2005/10/08/478425.aspx
Wednesday, October 12, 2005 2:38 PM by LA.Net

# Reutiliza

Thursday, October 20, 2005 9:27 AM by scott

# re: Using MSBuild and ILMerge to Package User Controls For Reuse

Thursday, October 20, 2005 4:32 PM by Expert Texture

# Merging ASP.NET 2.0 without aspnet_merge

Thursday, October 20, 2005 4:49 PM by Robert W. Anderson

# re: Using MSBuild and ILMerge to Package User Controls For Reuse

Good article -- it gave me validation to try generally merging ASP.NET 2.0 assemblies for release. That is the article mentioned in the trackbacks.
Thursday, October 20, 2005 4:50 PM by Robert W. Anderson

# re: Using MSBuild and ILMerge to Package User Controls For Reuse

P.S. Sorry about all of the trackbacks -- editing my blog caused this to happen automatically. Feel free to delete them, and this one for that matter. Cheers.
Friday, October 21, 2005 5:58 AM by Scott Allen

# re: Using MSBuild and ILMerge to Package User Controls For Reuse

No problem, Robert! Glad you found it useful.
Wednesday, October 26, 2005 1:43 PM by Keith J. Farmer

# re: Using MSBuild and ILMerge to Package User Controls For Reuse

Very cool.

Now we just need to work on that class naming problem...
Wednesday, October 26, 2005 4:56 PM by Jason Haley

# Interesting Finds

Wednesday, October 26, 2005 5:37 PM by Jason Haley

# Interesting Finds

Monday, October 31, 2005 1:58 PM by Scott

# re: Using MSBuild and ILMerge to Package User Controls For Reuse

David Ebbo is also having a crack at this: http://blogs.msdn.com/davidebb/comments/487160.aspx

Thursday, November 03, 2005 9:20 PM by Expert Texture

# Merging ASP.NET 2.0 without aspnet_merge

Friday, November 11, 2005 9:00 AM by Paul V.

# re: Using MSBuild and ILMerge to Package User Controls For Reuse

Very interesting article. It would do just what I need. I just can't get it to work for user controls that rely on code in the same assembly or a remote one. What am i missing? :(
Friday, November 11, 2005 10:37 AM by scott

# re: Using MSBuild and ILMerge to Package User Controls For Reuse

Paul: I haven't tried either of those scenarios yet. I'd think if the code the controls needed was in App_Code you'd be ok, as it would all get merged togeter.

I'm going to be taking a second look at this now that the web deployment project released.
Monday, December 05, 2005 7:29 AM by Nicklas Johansson

# re: Using MSBuild and ILMerge to Package User Controls For Reuse

This is great, this helped me alot. The only problem I have right now is that the project is creating two .dll with the same classes in them. I'm kind of new to modding the Build-file, so I guess it's something very basic.

Any thoughts?
Tuesday, December 13, 2005 6:05 AM by Michael

# re: Using MSBuild and ILMerge to Package User Controls For Reuse

Great article, it has set me on the right track! However I have a problem building custom controls with a codefile, as every server control that I use in the ascx file then generates a "does not exist in current context" error when I refer to it in the ascx.cs file.
So apparently the "link" between the .ascx file and the .ascx.cs file is lost. Any idea? Could you maybe post the code of your SayGoodbyeClass? Although I set the CodeFile, Inherits and ClassName attributes in the control definition, I probably forgot to set one or another attribute correclty... Thanks!
Sunday, December 18, 2005 11:22 AM by [WX punto NET]

# ILMerge 2.0

Tuesday, December 20, 2005 12:56 AM by [WX punto NET]

# ILMerge 2.0

Tuesday, December 20, 2005 1:09 AM by [WX punto NET]

# ILMerge 2.0

Wednesday, January 18, 2006 1:40 AM by [ WillyXoft .NET ]

# ILMerge 2.0

Wednesday, January 18, 2006 1:53 AM by [ WillyXoft .NET ]

# ILMerge 2.0

Saturday, April 08, 2006 6:34 PM by jason kemp .ca

# MSBuild Resources

Sunday, April 09, 2006 11:30 AM by jason kemp .ca

# MSBuild Resources

Thursday, May 18, 2006 11:52 AM by paul

# re: Using MSBuild and ILMerge to Package User Controls For Reuse

Was the code for this ever submitted?
Thursday, July 06, 2006 8:11 PM by [VB punto NET]

# ILMerge 2.0


Microsoft liber&#243; la versi&#243;n 2.0 (final) de su herramienta ILMerge, una herramienta para combinar m&#250;ltiples...
Wednesday, July 26, 2006 4:22 AM by Graham

# A Newer Solution for ASP.net 2

I've just posted a new solution for .Net 2 that allows you to include UserControls, Pages and MasterPages in a single Web Application Project library that can be distrubed easily.

Its quick and easy to set up, there a description of how it works and a solution download that demonstrates everything working.

http://www.nearasmakesnomatter.co.uk/wapul.htm
Friday, August 18, 2006 11:52 AM by Insert Catchy Title Here

# Dependency Injection and UserControls with Castle MicroKernel

Wednesday, November 14, 2007 11:10 PM by SergioTarrillo's RichWeblog

# MCPD 70-547: Creando y seleccionando Controles

Damos inicio a la serie de post, basados en los temas de preparaci&#243;n para el examen 70-547 . Si eres