How To: Use the Ngen tool to improve the performance in CAB / SCSF applications
There are some scenarios, like applications with a very big number of modules and views, that could present performance issues at startup due to the just-in-time (JIT) compilation process. In these cases it could be useful to precompile the assemblies using the Ngen tool.
The Native Image Generator (Ngen.exe) is a tool that improves the performance of managed applications by creating native images, which are files containing compiled processor-specific machine code. This allows the runtime to use native images instead of using the just-in-time (JIT) compiler to compile the original assembly code in runtime. One disadvantage of native images is that you cannot use the Assembly.LoadFrom method to load them.
If you are a user of CAB / SCSF, you may be aware of the Module Loader Service. This service allows you to load modules’ assemblies at run time when the application starts. The default implementation of this service uses the Assembly.LoadFrom method to load the assemblies enumerated by the Module Enumerator Service. So, if you try to “Ngen a CAB based application”, the native images of all your modules are not going to be used (the modules will be JIT compiled like always).
Workaround: Change the Module Loader Service class to use Assembly.Load method
This workaround enables the usage of the Assembly.Load method instead of the Assembly.LoadFrom method in the Module Loader Service class. The only limitation is that the modules’ assemblies must be physically located in the application’s working directory. To apply the workaround follow these steps:
- If you have an SCSF solution, open the DependentModuleLoaderService.cs file located in the Services folder of the Infrastructure.Library project. If you are using CAB without SCSF, open the ModuleLoaderService.cs file located in the Services folder of the CompositeUI project.
- Replace the implementation of the Load(WorkItem workItem, params Assembly[] assemblies) method for the following one:
public void Load(WorkItem workItem, params Assembly[] assemblies) { Guard.ArgumentNotNull(workItem, “workItem”); Guard.ArgumentNotNull(assemblies, “assemblies”); List<IModuleInfo> modules = new List<IModuleInfo>(); foreach (Assembly assembly in assemblies) { ModuleInfo mi = new ModuleInfo(assembly); // Use Assembly’s Full Name instead of the Assembly’s File Name. mi.SetAssemblyFile(assembly.FullName); modules.Add(mi); } InnerLoad(workItem, modules.ToArray()); }
- Replace the implementation of the LoadAssembly(string assemblyFile) method for the following one:
private Assembly LoadAssembly(string assemblyName) { Guard.ArgumentNotNullOrEmptyString(assemblyName, “assemblyName”); Assembly assembly = null; try { // Use Assembly.Load instead of Assembly.LoadFrom assembly = Assembly.Load(assemblyName); } catch (Exception ex) { throw new ModuleLoadException(assemblyName, ex.Message, ex); } if (traceSource != null) traceSource.TraceInformation(Properties.Resources.LogModuleAssemblyLoaded, assemblyName); return assembly; }
- Replace the implementation of the GuardLegalAssemblyFile(IModuleInfo modInfo) method for the following one:
private void GuardLegalAssemblyFile(IModuleInfo modInfo) { Guard.ArgumentNotNull(modInfo, “modInfo”); Guard.ArgumentNotNull(modInfo.AssemblyFile, “modInfo.AssemblyFile”); }
- Open your ProfileCatalog.xml file.
- Change the value of the AssemblyFile attribute of each of your ModuleInfo tags to the assembly’s Full Name:
<ModuleInfo AssemblyFile=“Module1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null“ /> <ModuleInfo AssemblyFile=“Module2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null“ />
Running Ngen on CAB based applications
When you run Ngen.exe on an assembly, it also generates native images for the all its dependencies (dependencies are determined from references in the assembly manifest). The only scenario in which you need to install a dependency separately is when the application loads it using reflection, for example by calling the Assembly.Load method.
This is the case for CAB / SCSF applications, so you must run Ngen for the your application executable (exe file) and all its modules. To do this follow these steps:
- Open a Visual Studio Command Prompt.
Note: If you are running on Vista with the User Account Control (UAC) activated, you must open it with the option Run as administrator. - Navigate to the directory where all your applications binaries are located and run the following command:
ngen install YourApplication.exe
- Run the same command for all of your business and foundational modules.
ngen install ModuleN.dll
Results
After applying the workaround on the BankTeller Quickstart and running Ngen to its binaries, the JIT compilation time was eliminated. To profile the application I used the ANTS Profiler.
- Before generation the native images, the application presented some peaks in the JIT compilation time.

- After generating the native images, the JIT compilation time was eliminated.

Note: In order to perform profiling to native images, you must install them using the /Profile scenario as follows:
ngen install YourApplication.exe /Profile |
Feedback is appreciated!
Mariano
Works like a charm. I also got the same difference in % Time in JIT with ANTS profiler.
One thing though, we compile some of the modules as part of our application, so the build number changes on each build and we have to manually update the profilecatalog to keep the version attribute up to date. This is the only drawback in comparison with the previous version that uses LoadFrom, there was no need to specify version attribute when you load from using only the assembly name.
This assembly was set as a project reference and copied over to the bin directory each time the solution builds. Now each time the solution builds we should update the profilecatalog.
Are we missing something or is there a way to automate the module build version?
Note: our deployment script uses ngen update to update the assembly native image each time we deploy the module.
Hi Lizet:
The Version, Culture and PublicKeyToken fields are not required in your ProfileCatalog.xml.
In Addition, if your assemblies’ are not signed with a strong name, the Version field is ignored.
Hope it helps
Mariano Converti
Hi Mariano,
thanks for this article!
Is it also possible to use ngen, if you are deploying a scsf based application via clickonce?
Hi Marc,
Unfortunately ClickOnce application deployment does not support Ngen. Check this article for more information:
Application Startup Time
However, you can use another deployment mechanism like regular Windows Installers to run Ngen after deploying your application.
I also found this article that deals with the same question. I didn’t try it, but perhaps you could find it useful:
Is it possible to use NGen with ClickOnce deployment?
Hope it helps.
Mariano Converti
How To: Use the Ngen tool to improve the performance in CAB / SCSF app…
You’ve been kicked (a good thing) - Trackback from DotNetKicks.com…
Hi,
I have 10 assembly used in my SCSF application.
I run ngen first for the shell.exe of my application and then the 10 assembly(dll’s).
Am I following the correct process?
Please guide if incorrect.
Thanks,
Sakshi