I wanted to find out exactly what the differences were between:
- "Do not merge" and "Do not merge. Create a separate assembly for each page and control."
- It sounds like these do the same thing, what's the difference?
- "Merge all outputs to a single assembly" and "Merge all pages and control outputs to a single assembly"
- Again, these sound like the same thing (when you don't have an
App_Code
folder).
And I want to find out why "Allow precompiled site to be updatable" didn't seem to do anything when it was checked (i.e. I thought it would precompile the pages to their own assembly/assemblies while also emitting the original editable *.aspx
, .ascx
, .master
files.
So, today I sat-down and created a spreadsheet and ran every different Publish Profile Precompilation setting with an ASP.NET WebForms *.csproj application - I also wanted to see what was the slowest vs. quickest output.
Background:
- My ASP.NET project targets .NET Framework 4.7.2
- It is not a "Website project".
- Raw C#
*.cs
files are not published to the production web-server.
- It is a WebForms project using
*.aspx
, *.ascx
, *.master
, *.ashx
and Global.asax
. It is not an MVC project using the Razor *.cshtml
nor WebForms *.aspx
view-engines).
- It does not use the
App_Code
folder (so the "Treat as library component" option has no effect).
Findings:
Important notes:
- These findings only apply if you're working with a "traditional" ASP.NET Web Forms Web Application project. These do not apply to ASP.NET Website Projects (where you don't have a
*.csproj
file), ASP.NET MVC (non-Core) projects, nor ASP.NET Core projects.
- I use the term "Page files" as a shorthand for
*.aspx
, *.ascx
, *.master
, *.asmx
, and *.ashx
files, but not Global.asax
.
- I use the term "Built normally" to refer to doing a "Build > Rebuild project" in Visual Studio, where you see the output in your
%projectdir%\bin
directory. This is compared to doing a Publish Build (which will perform a normal build first, then copy the output to another directory to run the Publish MSBuild steps)
Here are my findings for what each option results in:
"Precompile during publishing" (in Publish Settings window)
- If you don't have an
App_Code
folder and you want to publish editable *.aspx
/*.ascx
/`*.master files then there is no performance reason to check this box.
- This is because when this is checked but "Allow precompiled site to be updatable" is unchecked then it will only precompile your
Global.asax
file (not your Global.asax.cs
, which is compiled anyway).
- i.e. your
*.aspx
, *.ascx
, *.master
and *.ashx
files will not be precompiled to an assembly, and they'll still need to be compiled on-demand on the web-server.
- But it will still precompile them to check for compiler-errors and broken
<% @
-lines in your *.aspx
, *.ascx
, *.master
, *.asax
and *.ashx
files.
"Allow precompiled site to be updatable"
- When this checked your
*.aspx
, *.ascx
, *.master
and *.ashx
files will not be precompiled to an assembly, and they'll still need to be compiled on-demand on the web-server.
- I originally thought that it would precompile those files to an assembly (DLL) and additionally publish the original
*.aspx
files for editing on the server and only recompile them if they're changed - but I was wrong.
Emit debug information
- This generates
*.pdb
files for each new assembly generated by the precompilation process. It does not affect any *.pdb
files already present when your application is built normally.
- I think this should always be enabled - PDB files are essential for quickly investigating runtime problems and they don't add too much to the final publish size.
Do not merge
When you don't have an App_Code
folder and "Allow precompiled site to be updatable" is checked then "Do not merge" will only fully precompile Global.asax
into App_global.asax.dll
. No other DLL files will be added to the final publish output.
When "Allow precompiled site to be updatable" is unchecked then all Page files (defined under "Important notes" above) will be compiled into new DLL files App_Web_xxxxxxxx.dll
in groups of 10 classes.
- I cannot see how it decides to group files a pattern for which 10 files it uses - sometimes they're in alphabetical order, other times it's arbitrary.
Do not merge. Create a separate assembly for each page and control.
- This is the same as above, except rather than being in groups of 10 Page files (or classes) per assembly, it's 1-Page file-per-assembly.
- This is also one of the slowest publish builds when "Allow precompiled site to be updatable" is unchecked.
- The only advantage to this approach is if you want to individually replace each page's precompiled
*.dll
on the server - but I don't think that's a good idea as it will often break - it's better to replace all files at once. Only do this if you're on a 56K connection and can only upload less than 100KB at a time - which is just silly.
Merge all outputs to a single assembly
- Really does compile/merge all Page files and
Global.asax
(App_global.asax.dll
) to a single DLL file.
Treat as library component
- This option had zero effect on my project, whether it was checked or unchecked (as my project doesn't have an
App_Code
folder).
Merge each individual folder output to its own assembly
- This generates intermediate DLLs for each filesystem directory in your project that contains Page files and then merges them into a single DLL for each folder.
- This option resulted in the second longest Publish build time.
- I can't think of a good reason why you would need to use this feature today - unless you have a project with thousands of Page files spread over tens of folders and want to do manual incremental updates. (i.e. this isn't an option you'd use in a CI/CD process).
Merge all pages and control outputs to a single assembly
- If you have an
App_Code
folder:
- Then the contents of
App_Code
(and other "Special folders" like App_GlobalResources
, App_WebReferences
) will be precompiled to this separate assembly from your Page files assembly. This will not include Global.asax
(compiled to App_global.asax.dll
).
- If you don't have an
App_Code
folder then this option results in very similar output to "Merge all outputs to a single assembly" except the final output will precompile Global.asax
to its own assembly (App_global.asax.dll
).
- This option resulted in the longest publish build time of all the options - for zero real benefit in my case.
- So if you don't have an
App_Code
folder then there is no reason to choose this option.
Restated:
When "Allow precompiled site to be updatable" is checked and "Do not merge" is checked:
*.aspx
*.ascx
*.ashx
*.asmx
*.master
* Compiled only for error-checking.
* Not compiled to an assembly DLL in the `bin\` folder.
Global.asax
* Compiled to `App_global.asax.dll`
App_Code
* Compiled to `App_Code.dll`
When "Allow precompiled site to be updatable" is not checked and "Do not merge" is checked:
*.aspx
*.ascx
*.ashx
*.asmx
*.master
* Compiled to `App_Web_abcdefghij.dll` in groups of 10-per-DLL
Global.asax
* Compiled to `App_global.asax.dll`
App_Code
* Compiled to `App_Code.dll`
When "Allow precompiled site to be updatable" is not checked and "Merge each individual folder output to its own assembly" is checked:
*.aspx
*.ascx
*.ashx
*.asmx
*.master
* Each file compiled to its own `App_Web_OriginalFileName.abcdefghij.dll` file.
Global.asax
* Compiled to `App_global.asax.dll`
App_Code
* Compiled to `App_Code.dll`
When "Allow precompiled site to be updatable" is not checked and "Merge all outputs to a single assembly (named 'Everything')" is checked:
*.aspx
*.ascx
*.ashx
*.asmx
*.master
* Compiled and merged into the single Everything.dll
Global.asax
* Compiled and merged into the single Everything.dll
App_Code
* Compiled and merged into the single Everything.dll
When "Allow precompiled site to be updatable" is not checked and "Merge each individual folder output to its own assembly" is checked:
*.aspx
*.ascx
*.ashx
*.asmx
*.master
* Compiled into an assembly for each folder.
Global.asax
* Compiled to `App_global.asax.dll` (separate from the assembly for the *.aspx files in the root directory)
App_Code
* Compiled and merged into `App_Code.dll`
When "Merge all pages and control outputs to a single assembly (named 'PagesAndControls')" is checked:
*.aspx
*.ascx
*.ashx
*.asmx
*.master
* Compiled into PagesAndControls.dll
Global.asax
* Compiled to `App_global.asax.dll` (separate from PagesAndControls.dll)
App_Code
* Compiled and merged into `App_Code.dll`
Conclusion:
If you don't need to edit *.aspx
/*.ascx
,/*.master
files once they're deployed, and you don't have an App_Code
folder, then choose these settings for the best results:
[ ] Allow precompiled site to be updatable
[X] Emit debug information
[X] Merge all outputs to a single assembly
[ ] Treat as library component
Methodology:
- All builds are using Release.
- A "Folder" publish-profile was used.
- The target was a folder on the same disk volume (a PCI-Express Optane drive).
- The folder was cleared after each run.
- The only change between each test run was to changet the parameters in the
git
confirmed zero changes to source files and project files before each build and publish.
- I ran a shell script that completely clears the
bin
and obj
directories between each run, so the web-application project is fully rebuilt between runs instead of just the Publish).
- I used a Stopwatch program that recorded the exact time I clicked the Publish button, but was manually stopped by a keyboard press when I saw the Publish operation was completed.
Results:
(Screenshot of my spreadsheet)