MultiModule Assemblies

If you are programming with .Net framework, you will deal with Assemblies all the time. After all, assemblies are the building blocks of .Net framework.

 

Assemblies can have single file, or can have multiple files. We typically refer an assembly with multiple files as MultiModule Assembly, and each file as a module. An assembly will all ways have one manifest module, and zero or more non-manifest modules. Any non-manifest module will show up as “.file” in the assembly’s manifest. Here is an example:

 

// Metadata version: v2.0.40607

.module extern client.netmodule

.assembly extern mscorlib

{

  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..

  .ver 2:0:3600:0

}

.assembly extern Microsoft.VisualBasic

{

  .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:

  .ver 8:0:1200:0

}

.assembly myAssembly

{

  .hash algorithm 0x00008004

  .ver 0:0:0:0

}

.file client.netmodule

    .hash = (93 2D 15 13 F0 DE 8F D0 B2 1E 45 09 9E 21 4C 5F // .-........E..!L_

             E0 6D 8F 58 ) // .m.X

.file stringer.netmodule

    .hash = (B1 9B 7C AE AE 81 2E 6F BA 92 2D B1 66 66 6B BC // ..|....o..-.ffk.

             1E 2C 2E 87 ) // .,..

.class extern public myStringer.Stringer

{

  .file stringer.netmodule

  .class 0x02000002

}

.module myAssembly.exe

// MVID: {7E4BC53F-B02D-48D7-B422-C87DC359570F}

.imagebase 0x00400000

.file alignment 0x00000200

.stackreserve 0x00100000

.subsystem 0x0003 // WINDOWS_CUI

.corflags 0x00000001 // ILONLY

// Image base: 0x03B00000

There are several reasons for multimodule assemblies.

1. Combine modules written in different languages into one single assembly.

 

Currently there is no tool can create the assembly from source code written in different languages. Those sources have to be compiled into modules by the corresponding compilers, and then a separate tool will merge them into a single assembly. MSDN shows how to use Assembly Linker al.exe to create a multimodule assembly.

 

2. Incremental download.

 

The theory is, when you publish you assembly in internet, maybe you can separate the commonly used code from seldom used code. And CLR will only download the commonly used code most of the time, and download the seldom used code if necessary. If broadband adoption rate keeps increasing, this becomes less an issue.

 

3. Unfortunately, publisher policy

 

Publisher policy has to be carried with a publisher policy assembly to be validated, since we did not have the technology to validate XML files (there is XMLDSIG, but it is not available when publisher policy is designed). And the publisher policy config file is carried as the first module of the publisher policy assembly.

 

Multimodule assemblies have many problems:

 

1. Modules can’t reference each other without special techniques. Imagine there is a two modules assembly A, with module B and C. In order to use the types in module B, module B has to exist. So you have to build module B, then module C, then link to the final assembly. Module B can’t use any types in module C, unless special techniques are used, like the one described here. This is not a problem for single language single file assemblies.

 

2. When you link the modules into the final assembly, the hash of each module is recorded in the manifest file, as shown in the example above. Now if you change one source file, and build the corresponding module, you have to re-link the assembly again. Otherwise the assembly will have invalid hash value for that module. This either will result in a runtime load failure, or rejected by fusion if you want to install it to GAC. This one has been the source of many confusion and frustration, and it is not easy to track down exactly what was wrong.

 

3. Since multimodule assemblies have multiple files, when those assemblies are deployed, it is easy to leave some files behind, results in partial deployed assemblies.

 

For those reasons, multimodule assemblies are not recommended, unless necessary. The multiple languages assembly scenario is one of them.

 

Of course, the newest and greatest Whidbey will save the world. And this time, it is our old friend link.exe.

 

In Whidbey, link.exe is able to link several (.Net) modules (and obj files) into a single file assembly. There is really no new syntax. You simply put the modules on the command line.

 

Let’s use the MSDN sample as an example.

 

C:\ >more stringer.vb

' Assembly building example in the .NET Framework SDK.

Imports System

Namespace myStringer

   Public Class Stringer

      Public Sub StringerMethod()

         Console.WriteLine("This is a line from StringerMethod.")

      End Sub

   End Class

End Namespace

 

C:\ >more client.cs

using System;

using myStringer; //The namespace created in Stringer.netmodule.

class MainClientApp

{

   // Static method Main is the entry point method.

   public static void Main()

   {

      Stringer myStringInstance = new Stringer();

      Console.WriteLine("Client code executes");

      //myStringComp.Stringer();

      myStringInstance.StringerMethod();

   }

}

 

C:\ >vbc /t:module Stringer.vb

Microsoft (R) Visual Basic .NET Compiler version 8.0.40607.16

for Microsoft (R) .NET Framework version 2.0.40607.16

Copyright (C) Microsoft Corporation 1987-2003. All rights reserved.

 

 

C:\ >csc /addmodule:Stringer.netmodule /t:module Client.cs

Microsoft (R) Visual C# .NET Compiler version 8.00.40607.16

for Microsoft (R) Windows (R) .NET Framework version 2.0.40607

Copyright (C) Microsoft Corporation 2001-2003. All rights reserved.

 

C:\ >link /entry:MainClientApp.Main /out:main.exe client.netmodule stringer.netmodule

Microsoft (R) Incremental Linker Version 8.00.40607.16

Copyright (C) Microsoft Corporation. All rights reserved.

client.netmodule : non-native module found; restarting link with /LTCG; add /LTC

G to the link command line to improve linker performance

Microsoft (R) Incremental Linker Version 8.00.40607.16

Copyright (C) Microsoft Corporation. All rights reserved.

Generating code

Finished generating code

 

Here is main.exe’s manifest. It does not contain any “.file”.

 

// Metadata version: v2.0.40607

.assembly extern mscorlib

{

  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..

  .ver 2:0:3600:0

}

.assembly extern Microsoft.VisualBasic

{

  .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:

  .ver 8:0:1200:0

}

.assembly main

{

  .hash algorithm 0x00008004

  .ver 0:0:0:0

}

.module main.exe

// MVID: {EA1BE75E-F051-48B5-9B7E-B3D6C5048242}

.imagebase 0x00400000

.file alignment 0x00000200

.stackreserve 0x00100000

.subsystem 0x0003 // WINDOWS_CUI

.corflags 0x00000001 // ILONLY

// Image base: 0x03B00000