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