Not much talk has been around this error. There has been some incident reports in the ASP.NET forums that suggest the root cause of the problem is a duplicate type name, typically a page class, in the merging assemblies.
We did encounter some serious problems recently in my work relevant to this issue. The Web Deployment Project for our Web Site that served us well for some time, all of a sudden stopped working giving this error in it’s build output console.
One of my first attempts to solve this puzzle, after having searched the net for an answer, was to check if any of the containing types of the the assembly that seemed to be causing the problem, was given an already existent name across the project, but that was not the case.
I decided to look further the problem by manually compiling and merging the Web Application in order to gain more control over the issuing commands and, hopefully, get the duplicate type name.
As aspnet_compiler has always been compiling the project with success, I didn’t use any extra switches to manipulate it’s error/status output.
aspnet_compiler.exe -v /WebSite -p C:DevelopmentWebSite -u -f -d C:DevelopmentWebSiteBuildTempBuildDir
For aspnet_merge I used the extra -errorstack and -log arguments the functionality of which is described in the ASP.NET Merge Tool presentation article here.
aspnet_merge.exe C:DevelopmentWebSiteBuildTempBuildDir -o WebSiteBuild -a -debug -copyattrs -errorstack -log merge.log
From the extra -errorstack argument I’ve learned that an UnAuthorizedAccessException causes aspnet_merge to fail with this stack trace:
[UnauthorizedAccessException]: Access to the path 'C:DevelopmentWebSiteBuildTempBuildDirbinApp_Web_9imofmvu.dll' is denied.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.File.Delete(String path)
at System.Web.Compilation.Merge.DeleteFileNoThrow(String filepath)
at System.Web.Compilation.Merge.RemoveOldAssembly(Hashtable assemblyMapping)
at System.Web.Compilation.Merge.Main(String[] args)
or
[UnauthorizedAccessException]: Access to the path 'C:DevelopmentWebSiteBuildTempBuildDirbinApp_Code.dll' is denied.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.File.Delete(String path)
at System.Web.Compilation.Merge.DeleteFileNoThrow(String filepath)
at System.Web.Compilation.Merge.RemoveOldAssembly(Hashtable assemblyMapping)
at System.Web.Compilation.Merge.Main(String[] args)
And from the the -log argument I didn’t learn anything as the log file did not contain anything suspicious to me.
The gathered information didn’t help much to achieve my initial goal, to unveil the duplicate type name, so I needed to move onto this mini research.
Having trust to what others say about the problem, and continuing to believe that for some reason a duplicate type name existed in the project – I had nothing else to work on -, I thought I could merge the assemblies using some tool other than aspnet_merge, that will hopefully give me more details if any error occurs.
After some googling I came up with a tool called ILMerge. It is hosted in Microsoft, is authored by Michael Barnett and shares the same codebase as aspnet_merge.
You typically use this tool in command of the following form:
ILMerge /target:(library|exe|winexe) /out:filename Program.exe ClassLibrary1.dll ClassLibrary2.dll
For the specific situation of merging the pre-compiled assemblies of a Web Site, the correct command to use is:
ILMerge /out:WebSiteBuild.dll App_Web_*.dll App_Web_*.dll App_Web_*.dll ...
For ILMerge to work you, obviously, first need to use aspnet_compiler to pre-compile your Web Site. You then need to explicitly specify all the assembly names that you want to take part in the merge operation. If you have PowerShell installed in your system you may issue the following command instead of specifying each assembly one-by-one:
PS C:DevelopWebSiteBuildTempBuildDirbin> $assemblies = ls .* -include App_*.dll -name; &'C:Program FilesMicrosoftILMergeILMerge.exe' /t:lib /out:WebSiteBuild.dll $assemblies
NOTE: You may need a Visual Studio PowerShell Prompt to do this.
and.. BINGO!
If a duplicate type name exists in your set of assemblies you should get the following output:
An exception occurred during merging: ILMerge.Merge: ERROR!!: Duplicate type ‘Company.WebSite.YetAnotherClass’ found in assembly ‘App_Web_y1dnvgxw’.
at ILMerging.ILMerge.MergeInAssembly(AssemblyNode a, Boolean makeNonPublic)
at ILMerging.ILMerge.Merge()
at ILMerging.ILMerge.Main(String[] args)
Now that you have the name of the evil class name, all you have to do is to rename it, but in our case unfortunatelly things aren’t that sweet because the YetAnotherClass IS NOT a duplicate type, and that left me scratching my head..
I thought this should be related to the compilation, and I took a more thorough looked into the aspnet_compiler arguments.
Compiling using the -fixednames argument, and then merging using the ILMerge OR the aspnet_merge tools, makes the problem dissapear, meaning that the compiler no longer produces duplicate type names. Bug?
The problem is that from within VS I fnd no other way to pass the -fixednames argument to aspnet_compiler than to use the “Merge each individual folder output to its own assembly” option which, apparently, is not equivalent to “Merge all outputs to a single assembly”.
To the bottom line, if you experience the “Access Denied” error when merging all output to a single assembly, you may be able to overcome it but, probably, not from within VS, you’ll have to use the command prompt instead.
UPDATE: Using the “Merge all pages and control outputs to a single assembly” option, which calls aspnet_merge with the -w param instead of the -o param, resolves the issues we had.