Where do pages and user controls end up when you precompile but not merge?

682 Views Asked by At

When publishing a website you have several precompile options. For this example, let's assume it's a .ascx user control (though page behavior is similar) and "Allow precompiled site to be updatable" is not checked. These are some of the options you have:

  1. Don't precompile: User control content stays in the .ascx file and is compiled on demand to the temporary ASP.NET folders.
  2. Precompile, no merge: main DLL (projectName.dll) is slightly different, .ascx disappears, and I can't find the ascx content anywhere??
  3. Precompile, merge to single assembly: main DLL is slightly different, the .ascx content is in the new single assembly, and .compiled files appear
  4. Precompile, merge pages and controls to single assembly: almost identical to #3, single assembly slightly smaller (presumably it doesn't include the top-level assemblies) some of the code #3 included)Same as #3 but now we also have .compiled files.

Methodology: I used WinMerge to compare the publish output between #1 and #2, then #2 and #3 and so on. I also picked a unique word from one ascx and searched the publish output using Agent Ransack (finds everything, not just indexed content).

Question: For #2, where does the user control HTML content end up? Or in other words, how does the site work without the published ascx content in a DLL or without the .compiled files? For #1 it picks up the content from .ascx as needed, but #2 doesn't have it availaible.

Edit: The site went readonly right after I asked and I realized my build output was invalid. I have updated the question to be more accurate and thorough.

1

There are 1 best solutions below

1
On

it ends up in a produced .dll in a published bin folder one way or another

.aspx and .ascx files produce control object trees with all strings between %>aaa<% being converted to Literal("aaa") and inserted to a control tree at correct places.

These classes that are descendant from Page (or base Page class of your choice) and WebUserControl are always compiled but without precompilation they reside in temporary asp.net folders; with pre-compilation they are placed inside your precompiled package right away.

For example the following .ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="WebUserControl.ascx.cs" Inherits="WebUserControl" %>
<div class="customhtml">
    <asp:Label ID="Label1" runat="server" Text="<%#Page.Title %>"></asp:Label>
    <asp:Button ID="Button1" runat="server" Text="Button" />
</div>

results in the following (option no merge): webusercontrol.ascx.#hash#.compiled

<?xml version="1.0" encoding="utf-8"?>
<preserve resultType="3" virtualPath="/WebSite1/WebUserControl.ascx" hash="fffffff7f6e43006" filehash="8f74adc78f7714d1" flags="110000" assembly="App_Web_aslslubn" type="ASP.webusercontrol_ascx">
    <filedeps>
        <filedep name="/WebSite1/WebUserControl.ascx" />
        <filedep name="/WebSite1/WebUserControl.ascx.cs" />
    </filedeps>
</preserve>

that allows you to find what assembly it is compiled to - App_Web_#hash# and type - ASP.webusercontrol_ascx

Disassembling it shows the following class declaration:

using System;
using System.Diagnostics;
using System.Globalization;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace ASP
{
  public class webusercontrol_ascx : WebUserControl
  {
    private static bool __initialized;

    [DebuggerNonUserCode]
    public webusercontrol_ascx()
    {
      this.AppRelativeVirtualPath = "~/WebUserControl.ascx";
      if (webusercontrol_ascx.__initialized)
        return;
      webusercontrol_ascx.__initialized = true;
    }

    [DebuggerNonUserCode]
    private Label __BuildControlLabel1()
    {
      Label label = new Label();
      this.Label1 = label;
      label.ApplyStyleSheetSkin(this.Page);
      label.ID = "Label1";
      label.DataBinding += new EventHandler(this.__DataBindingLabel1);
      return label;
    }

    public void __DataBindingLabel1(object sender, EventArgs e)
    {
      Label label = (Label) sender;
      Control bindingContainer = label.BindingContainer;
      label.Text = Convert.ToString(this.Page.Title, (IFormatProvider) CultureInfo.CurrentCulture);
    }

    [DebuggerNonUserCode]
    private Button __BuildControlButton1()
    {
      Button button = new Button();
      this.Button1 = button;
      button.ApplyStyleSheetSkin(this.Page);
      button.ID = "Button1";
      button.Text = "Button";
      return button;
    }

    [DebuggerNonUserCode]
    private void __BuildControlTree(webusercontrol_ascx __ctrl)
    {
      IParserAccessor parserAccessor = (IParserAccessor) __ctrl;
      parserAccessor.AddParsedSubObject((object) new LiteralControl("\r\n<div class=\"customhtml\">\r\n    "));
      Label label = this.__BuildControlLabel1();
      parserAccessor.AddParsedSubObject((object) label);
      parserAccessor.AddParsedSubObject((object) new LiteralControl("\r\n    "));
      Button button = this.__BuildControlButton1();
      parserAccessor.AddParsedSubObject((object) button);
      parserAccessor.AddParsedSubObject((object) new LiteralControl("\r\n</div>\r\n"));
    }

    [DebuggerNonUserCode]
    protected override void FrameworkInitialize()
    {
      base.FrameworkInitialize();
      this.__BuildControlTree(this);
    }
  }
}

In particular you can find your HTML code as LiteralControl being addedd

[DebuggerNonUserCode]
private void __BuildControlTree(webusercontrol_ascx __ctrl)
{
  IParserAccessor parserAccessor = (IParserAccessor) __ctrl;
  parserAccessor.AddParsedSubObject((object) new LiteralControl("\r\n<div class=\"customhtml\">\r\n    "));
  Label label = this.__BuildControlLabel1();
  parserAccessor.AddParsedSubObject((object) label);
  parserAccessor.AddParsedSubObject((object) new LiteralControl("\r\n    "));
  Button button = this.__BuildControlButton1();
  parserAccessor.AddParsedSubObject((object) button);
  parserAccessor.AddParsedSubObject((object) new LiteralControl("\r\n</div>\r\n"));
}