Assemblies
Peter Drayton
peter@[Link]
1
Assemblies and the .NET Framework
• The Common Language Runtime requires all types to belong to
an assembly. Assemblies act as the smallest distribution unit for
component code in the .NET Framework.
2
Assemblies defined
• Assemblies are used to package and distribute executable code
– Assemblies are the atom of deployment in the CLR
– Assemblies are collections of type definitions
– Type names are scoped by their containing assembly
– Only types and members marked public are visible outside
the assembly
– internal members and types inaccessible outside of
assembly
– private members inaccessible outside of their declaring
type
3
Figure 1: Access modifiers
C# [Link] Meaning
public Public Type is visible everywhere
Type
internal Private Type is only visible inside of assembly
public Public* Member is visible everywhere
Member internal Friend Member is only visible inside of assembly
private Private* Member is only visible inside of declaring type
* [Link] defaults to Public for methods and Private
for fields declared using the Dim keyword
4
Assemblies and modules
• An assembly consists of one or more physical files known as
modules
– A module is an executable file containing code and metadata
– Each module may be produced using different programming
languages
– Exactly one module in an assembly contains an assembly
manifest
– [Link]'s /t:module and /addmodule switches support
module-level compilation/references
– The assembly linker [Link] can link multiple modules and
create the manifest
5
Figure 2: Modules and Assemblies
/t:module /t:library
.module [Link] .module [Link]
.assembly extern mscorlib .assembly extern mscorlib
.assembly extern paul .assembly extern paul
.class public PP { .class public PP {
.field [paul]Bassist m .field [paul]Bassist m
} }
.assembly pete Manifest
6
Figure 3: A multi-module assembly
/t:library /addmodule:[Link],[Link]
.module [Link] /t:module
.assembly extern mscorlib .module [Link]
.assembly extern paul
.assembly extern john .assembly extern mscorlib
.assembly extern paul
.class public Manager {
} .class public PP {
.field [paul]Bassist m
.assembly band }
.file [Link] /t:module
.file [Link]
.module [Link]
Manifest
.class extern public GP
{.file [Link] .assembly extern mscorlib
.class nnnn } .assembly extern john
.class extern public PP .class public GP {
{.file [Link] .field [john]Singer m
.class nnnn } }
7
Figure 4: Multi-module assemblies using [Link]
Component Assembly
[Link] [Link] /t:module [Link]
[Link] /t:library
[Link] [Link]
/addmodule:[Link]
Application Assembly
[Link] csc /r:[Link] [Link]
8
Figure 5: Multi-module assemblies using [Link] and NMAKE
# [Link] cannot be loaded as is until an assembly
# is created
[Link] : [Link]
csc /t:module [Link]
# types in [Link] can see internal and public members
# and types defined in [Link]
[Link] : [Link] [Link]
csc /t:library /addmodule:[Link] [Link]
# types in [Link] cannot see internal members and
# types defined in [Link] (or [Link])
[Link] : [Link] [Link]
csc /t:exe /r:[Link] [Link]
9
Public Keys and Assemblies
• Assemblies use public-key technology both to identify the
developer and to prevent tampering
– Cryptographic signature based on public/private key pair
– Cannot tamper with assembly without resigning
– Originator in target assembly contains complete 1024-bit
RSA public key
– Originator in assembly reference contains 64-bit hash of full
public key
– The [Link] tool manages public/private key files
– The AssemblyKeyFile and AssemblyDelaySign
attributes associate keys with assemblies
10
Figure 6: Managing public/private keys using [Link]
[Link] -k [Link]
Public Key
Private Key
[Link] (128 bytes + 32
(436 bytes)
byte header)
[Link] -p [Link] [Link]
Public Key
[Link] (128 bytes + 32
byte header)
[Link] -t [Link]
Public key token is 883dd0182e81d815
11
Figure 7: Strong assembly references
[Link]
[Link]
using [Link];
Public Key
[assembly: AssemblyKeyFile("[Link]")]
(128 bytes + 32
[assembly: AssemblyDelaySign(false)] byte header)
csc /t:library [Link] Private Key
(436 bytes)
[Link]
Public Key
(128 bytes + 32 Signature
byte header)
PE/COFF
Header CLR Header Code
[Link]
mylib
Public Key Token (8 bytes)
Assembly Reference
PE/COFF
Header CLR Header Code
12
Figure 8: Delay signing an assembly
[Link]
using [Link];
[assembly: AssemblyKeyFile("[Link]")]
[assembly: AssemblyDelaySign(true)]
[Link]
Public Key
csc /t:library [Link] (128 bytes + 32
byte header)
[Link]
Public Key Space
(128 bytes + 32 For [Link]
byte header) Signature Public Key
PE/COFF (128 bytes + 32
Header CLR Header Code byte header)
Private Key
sn -R [Link] [Link] (436 bytes)
[Link]
Public Key
(128 bytes + 32 Signature
byte header)
PE/COFF
Header CLR Header Code
13
Assembly names
• All assemblies have a four-part name that uniquely identifies the locale
and developer of the component
– The simple Name typically corresponds to the file name (no
extension)
– The Version identifies the major/minor/build/revision numbers
– The (optional) CultureInfo corresponds to language and region
– The (optional) Originator/PublicKey identifies the developer
– Display names are stringified assembly names suitable for human
entry
– Note: Namespace prefixes of types may or may not match the
Name of the assembly
14
Figure 9: Inside the AssemblyVersion attribute
Attribute Actual
Parameter Value
1 [Link]
1.2 [Link] * where d is the
number of days
1.2.3 [Link] since Feb. 1, 2000
[Link] [Link] and s is the
number of seconds
1.2.* 1.2.d.s since midnight /2
1.2.3.* 1.2.3.s
<absent> [Link]
15
Figure 10: Fully specified assembly names
Display Name of Assembly Reference
yourcode, Version=[Link], Culture=en-US, PublicKeyToken=1234123412341234
or neutral or null
C# Code
using [Link];
[assembly: AssemblyVersion("[Link]") ]
[assembly: AssemblyCulture("en-US") ] // resource-only assm
[assembly: AssemblyKeyFile("[Link]") ]
16
Loading and resolving assemblies
• Assemblies can be loaded either by an explicit URL or a four-part
assembly name
– [Link] loads an assembly based on an explicit
CODEBASE (e.g., a file name or URL)
– [Link] first uses the assembly resolver to resolve a 4-
part assembly name to a file prior to loading
– Subordinate assemblies always loaded using assembly resolver
– Subordinate modules and assemblies only loaded on demand
– CODEBASE hints specified using per-application/machine
configuration files
– Assemblies from non-file URLs are cached in the download cache
(watch out for SecurityException from untrusted code)
17
Figure 11: Loading an assembly with an explicit CODEBASE
using System;
using [Link];
public static Object LoadCustomerType() {
Assembly a = [Link](
"[Link]
return [Link]("[Link]");
}
18
Figure 12: Assembly resolution and loading
[Link](name,culture,version,token) [Link]
APPBASE <bindingRedirect>
POLICY <codeBase>
Assembly
Resolver
CODEBASE <probing>
PRIVATE_BINPATH
Assembly
Loader
Loaded Assembly
19
Figure 13: Loading an assembly using the assembly resolver
using System;
using [Link];
public static Object LoadCustomerType() {
Assembly a = [Link](
"xyzzy, Version=[Link], " +
"Culture=en-UK, PublicKeyToken=9a33f27632997fcc");
return [Link]("[Link]");
}
20
Version policy
• The assembly resolver can map the requested version of an
assembly to a newer (or older) one via configured version
policies
– Only applies to fully-specified assembly references (name,
version, culture, publickey)
– Only applies when the assembly resolver is used
– Applied before any other actions are taken by the resolver
– Specified via configuration files per application and machine-
wide
21
Figure 14: Assembly resolver configuration file format
configuration
0..1 Element (xmlns="") Attribute
runtime Element (xmlns="urn:[Link]:asm.v1")
0..1
assemblyBinding
0..N 0..1 0..1
dependentAssembly probing publisherPolicy
privatePath apply
name
assemblyIdentity publicKeyToken
0..1
culture
0..N version
codeBase
href
0..N oldVersion
bindingRedirect
newVersion
0..1
publisherPolicy apply
22
Figure 15: Setting the version policy
<?xml version="1.0" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- one dependentAssembly per unique assembly name -->
<dependentAssembly>
<assemblyIdentity
name="[Link]"
publicKeyToken="38218fe715288aac" />
<!-- one bindingRedirect per redirection -->
<bindingRedirect oldVersion="[Link]"
newVersion="[Link]“ />
<bindingRedirect oldVersion="1-[Link]"
newVersion="[Link]" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
23
Figure 16: Setting the application to safe-mode
<?xml version="1.0" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<publisherPolicy apply="no"/>
</assemblyBinding>
</runtime>
</configuration>
24
The assembly cache
• Assemblies are first loaded from the machine-wide assembly
cache
– The assembly cache makes assemblies available
independent of where the application is located
– The download cache holds assemblies loaded from non-file-
based URL
– The global assembly cache (GAC) holds system-level
assemblies
– The assembly resolver always consults the GAC first
– The GAC is a secured resource and requires admin
privileges to add/delete entries
– The GAC only contains signed assemblies with public keys
25
Figure 17: Global Assembly Cache
Public Key Mangled
Name Version Culture
Token Path
yourcode [Link] de 89abcde... t3s\e4\[Link]
yourcode [Link] en 89abcde... a1x\bb\[Link]
yourcode [Link] en 89abcde... vv\a0\[Link]
libzero [Link] en 89abcde... ig\u\[Link]
26
Assembly resolving via CODEBASE or probing
• If the assembly cannot be found in the GAC, the assembly
resolver tries to use a CODEBASE hint to access the assembly
– Configuration files can/should provide a CODEBASE hint
– If matching file not accessible via provided CODEBASE
URL, Load fails
– If no hint is provided, the assembly resolver must probe
several location
– Relative search path uses subdirectories of the APPBASE
– Probe path can be augmented using configuration files
– Resultant assembly must match all specified properties (e.g.,
(policy-adjusted) version, culture)
27
Figure 18: Specifying the codebase using configuration files
<?xml version="1.0" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- one dependentAssembly per unique assembly name -->
<dependentAssembly>
<assemblyIdentity name="[Link]"
publicKeyToken="38218fe715288aac"/>
<!-- one codeBase per version -->
<codeBase version="[Link]"
href="[Link]
<codeBase version="[Link]"
href="[Link]
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
28
Figure 19: APPBASE and the relative search path
m
[Link]
(APPBASE)
C:\
n o q
Eligible Ineligable
Directories Directories p
C:\m C:\
C:\m\o C:\n
C:\m\o\q
C:\m\p
29
Figure 20: Setting the relative search path
<?xml version="1.0" ?>
<configuration>
<runtime>
<assemblyBinding
xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="shared;aux" />
</assemblyBinding>
</runtime>
</configuration>
30
Figure 21: Culture-neutral probing
Assembly Reference Potential CODEBASEs (in order)
yourcode, Culture=neutral,... [Link]
[Link]
APPBASE [Link]
[Link]
[Link] [Link]
[Link]
Application Configuration File
[Link]
<configuration xmlns:asm="...">
[Link]
<runtime>
[Link]
<asm:assemblyBinding>
[Link]
<asm:probing
[Link]
privatePath="shared;aux" />
[Link]
</asm:assemblyBinding>
</runtime>
</configuration>
31
Figure 22: Culture-dependent probing
Assembly Reference Potential CODEBASEs (in order)
yourcode, Culture=en-US,... [Link]
[Link]
APPBASE [Link]
[Link]
[Link] [Link]
[Link]
Application Configuration File
[Link]
<configuration xmlns:asm="...">
[Link]
<runtime>
[Link]
<asm:assemblyBinding>
[Link]
<asm:probing
[Link]
privatePath="shared;aux" />
[Link]
</asm:assemblyBinding>
</runtime>
</configuration>
32
Figure 23: Assembly resolution
Apply Version Policy
(if reference fully specified)
Match already Use assembly
Y
loaded? already loaded
N
Match in Use file found in
Y
Global Cache? Global Cache
N
Is file found
<codeBase> N
N via probing?
hint provided?
Y
Y
Does file match
N
[Link] N
Does file match
reference? Fails reference?
Y Y
Use file found at Use file found
CODEBASE from probing
33
Versioning hazards
• Loading multiple versions of the same assembly is not without
risks and problems
– The CLR treats same-named types as distinct when they
come from different physical assemblies
– One copy of global/static variables per version
– Types from V2 cannot be passed where types defined in V1
are expected
– Putting globals/static variables in a non-versioned assembly
addresses the former
– Avoiding using versioned types as parameters addresses
the latter
34
Summary
• The assembly is the "component" of the CLR
• All types belong to exactly one assembly
• Assemblies carry a digital signature from the developer who
created them
• Assemblies support multiple versions loaded simultaneously in
the same program
• Assemblies can be automatically downloaded from the Internet
35
Questions?
36