4/13/2005

AssemblyLoadFrom and CAB files and multiple assemblies

Junfeng Zhang is one of the few MS folks that focus on and are acutely aware of the lower-level intricacies of the .NET framework. His blog is at:

http://blogs.msdn.com/junfeng/

One of the valuable snippets I've picked up from Zhang is about using CAB files. I reproduce a portion here. Note that when Junfeng uses the word "we", what he means is "This is what the Framework does":

You can deploy assemblies using cab files.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpcondeployingcommonlanguageruntimeapplicationusingcabfiles.asp

There are two ways to load assemblies from cab files.

1. Assembly.LoadFrom

You can give the URL of the cab file to Assembly.LoadFrom. For example,

Assembly.LoadFrom("http://myserver/myasm.cab");

2. Use app.config, and specify codebase hint, then use Assembly.Load.

For example:


<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="myasm" culture=whatever publicKeyToken="0123456789abcdef "/>
<codeBase version="1.0.0.0"
href="http://myserver/myasm.cab"/>
</dependentAssembly>

</assemblyBinding>
</runtime>
</configuration>


When we locate the cab file, we extract them to a temporary directory. The temporary directory becomes the application base now and we will probe the desired assembly in the temporary directory. We then copy the assembly to download cache, and remove the temporary directory we created. The final assembly location you see from Assembly.Location will be in download cache directory.

There are subtle differences in using Assembly.LoadFrom and codebase hint.

In Assembly.LoadFrom case, after we extract the cab file, we will only look for assembly with the same name as the cab file, excluding the extension. In our example above, we will only look for myasm.dll/myasm.exe.

In codebase hint case, we will look for the assembly specified in Assembly.Load, instead of the name of the cab file. This means, the cab file does not have to have the same name as the assembly.

A side effect of codebase hint behavior is that you can put multiple assemblies in one cab file. You will need to specify multiple assemblyBinding statements in app.config file to use the same cab file as codebase hint for different assemblies.

If you use this technique, due to how we extract the cab file and find the assembly (see above), we will download, and extract the same cab file multiple times. So bundling multiple assemblies in one cab file may actually hurt performance, instead of improving performance.

Of course, in reality, we use IE to download the cab file. You may benefit from IE's caching of the downloaded cab file. You really want to measure your scenario, to decide if you want to use this technique or not.

------------------------

You can also actually put a complete MSI Installer inside a CAB and have it run when the downloaded CAB is unpacked:

Installer.inf -- The Inf file for the CAB file. It has the following contents:

[Setup Hooks]
hook1=hook1

[hook1]
run= msiexec /i %EXTRACT_DIR%\ActiveXInstaller.msi /qn

[Version]
; This section is required for compatibility on both Windows 95 and Windows NT.
Signature="$CHICAGO$"
AdvancedInf=2.0

Here run specifies the command we would like to run after IE extracts the CAB. The command line will install the MSI ActiveXInstaller.msi under silent mode.