Issue with publishing web-site as non-updatable with "Use Fixed Naming and Single Page Assembly" and assembly versioning

Few days back I came across an issue with Publish Web Site and assembly versioning. One of my customers was trying to publish a web site as non-updatable with "Use Fixed Naming and Single Page Assembly" option. Also at the same time they are setting the assembly version to the assemblies as well. In this scenario once publish was completed, few assemblies were missing the version information (all those pages had huge HTML strings in the aspx source).

So I tried reproducing the issue and it was pretty simple to reproduce.

Below are the steps for it -

Add the below code in the ASPX Page -

<%@ Page Language="C#" %>

<script runat="server"></script>

<html xmlns="https://www.w3.org/1999/xhtml">

<head runat="server">

   <title>Untitled Page</title>

</head>

<body>

   <form id="form1" runat="server">

   <div>

   <table>

   <tr><td></td><td></td><td></td></tr>

   <tr><td></td><td></td><td></td></tr>

   <tr><td></td><td></td><td></td></tr>

   <tr><td></td><td></td><td></td></tr>

   </table>

   </div>

   </form>

</body>

</html>

Add below code in web.config -

<?xml version="1.0">

<configuration>

<appSettings/>

<connectionStrings/>

<system.web>

   <compilation debug="false"> </compilation>

   <authentication mode="Windows"/>

</system.web>

<system.codedom>

   <compilers>

   <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CSharp.CSharpCodeProvider,System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" compilerOptions="{physicalpath}\VersionInfo.cs">

   </compiler>

   </compilers>

</system.codedom>

</configuration>

And the VersionInfo.cs should have below code -  

using System;

using System.Reflection;

using System.Runtime.CompilerServices;

using System.Runtime.InteropServices;

[assembly: AssemblyVersion("1000.00.00.0001")]

[assembly: AssemblyFileVersion("1000.00.00.0001")]

 

Now try to publish web-site as non-updatable with "Use Fixed Naming and Single Page Assembly" you will not see the version in the explorer for the assembly created for this particular page.  

After digging in further around this issue I found out that when a page has string literals (html or text that is not part of a control) of length equal or longer to 256, ASP.NET stores those strings into a win32 resource file before embedding it into the assembly (using csc.exe /win32res:file.res).

As a result, the AssemblyVersion and AssemblyFileVersion attribute in the assembly is masked by the win32 resource. If you try using System.Diagnostics.FileVersionInfo or AssemblyName.GetAssemblyName, you won’t get any file or assembly version from the assembly. If you view the assembly in Explorer, you don’t see any version information either. But if you open the assembly in ILDASM it shows the version correctly.

The workarounds for this situation would be –

1. Insert dummy controls into pages with long string literals. This will break up the strings to avoid generating the win32 resource. (That means we have to make sure we are encapsulating all the html or Text within dummy server controls to make sure that there are no string equal or greater than 256 outside controls).

As per above repro if we replace the code in the ASPX with below code, it won’t fail for versioning –

<%@ Page Language="C#" %>

<script runat="server"></script>

<html xmlns="https://www.w3.org/1999/xhtml">

<head runat="server">

   <title>Untitled Page</title>

</head>

<body>

   <form id="form1" runat="server">

   <div>

   <asp:Literal runat="server" ID="Test">

   <table>

   <tr><td></td><td></td><td></td></tr>

   <tr><td></td><td></td><td></td></tr>

   <tr><td></td><td></td><td></td></tr>

   <tr><td></td><td></td><td></td></tr>

   </table>

   </asp:Literal>

   </div>

   </form>

</body>

</html>

OR  

2. Use web deployment projects, and use the “Version output assemblies” option.

(Note that you will be unable use this option if you choose “Create a separate assembly for each page and control output”, because that option is equivalent to running aspnet_compiler with - fixednames, and does not go through aspnet_merge.)

I hope this helps!