Sie sind auf Seite 1von 36

Assemblies

Peter Drayton
peter@develop.com

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# VB.NET 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

* VB.NET 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
– CSC.EXE's /t:module and /addmodule switches support
module-level compilation/references
– The assembly linker al.exe can link multiple modules and
create the manifest

5
Figure 2: Modules and Assemblies

/t:module /t:library
.module pete.netmodule .module pete.dll
.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:pete.netmodule,george.netmodule
.module band.dll /t:module
.assembly extern mscorlib .module pete.netmodule
.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 pete.netmodule /t:module
.file george.netmodule
.module george.netmodule
Manifest

.class extern public GP


{.file george.netmodule .assembly extern mscorlib
.class nnnn } .assembly extern john
.class extern public PP .class public GP {
{.file pete.netmodule .field [john]Singer m
.class nnnn } }

7
Figure 4: Multi-module assemblies using CSC.EXE

Component Assembly

code.cs csc.exe /t:module code.netmodule

csc.exe /t:library
component.cs component.dll
/addmodule:code.netmodule

Application Assembly

application.cs csc /r:component.dll application.exe

8
Figure 5: Multi-module assemblies using CSC.EXE and NMAKE

# code.netmodule cannot be loaded as is until an assembly


# is created
code.netmodule : submodule.cs
csc /t:module submodule.cs

# types in component.cs can see internal and public members


# and types defined in submodule.cs
component.dll : component.cs code.netmodule
csc /t:library /addmodule:code.netmodule component.cs

# types in application.cs cannot see internal members and


# types defined in submodule.cs (or component.cs)
application.exe : application.cs component.dll
csc /t:exe /r:component.dll application.cs

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 SN.EXE tool manages public/private key files
– The AssemblyKeyFile and AssemblyDelaySign
attributes associate keys with assemblies

10
Figure 6: Managing public/private keys using SN.EXE

sn.exe -k publicprivate.snk

Public Key
Private Key
publicprivate.snk (128 bytes + 32
(436 bytes)
byte header)

sn.exe -p publicprivate.snk public.snk

Public Key
public.snk (128 bytes + 32
byte header)

sn.exe -t public.snk

Public key token is 883dd0182e81d815

11
Figure 7: Strong assembly references

mylib.cs
publicprivate.snk
using System.Reflection;
Public Key
[assembly: AssemblyKeyFile("publicprivate.snk")]
(128 bytes + 32
[assembly: AssemblyDelaySign(false)] byte header)

csc /t:library mylib.cs Private Key


(436 bytes)
mylib.dll
Public Key
(128 bytes + 32 Signature
byte header)
PE/COFF
Header CLR Header Code

myapp.exe
mylib
Public Key Token (8 bytes)
Assembly Reference
PE/COFF
Header CLR Header Code

12
Figure 8: Delay signing an assembly

mylib.cs
using System.Reflection;
[assembly: AssemblyKeyFile("public.snk")]
[assembly: AssemblyDelaySign(true)]
public.snk
Public Key
csc /t:library mylib.cs (128 bytes + 32
byte header)
mylib.dll
Public Key Space
(128 bytes + 32 For publicprivate.snk
byte header) Signature Public Key
PE/COFF (128 bytes + 32
Header CLR Header Code byte header)

Private Key
sn -R mylib.dll publicprivate.snk (436 bytes)
mylib.dll
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 1.0.0.0
1.2 1.2.0.0 * where d is the
number of days
1.2.3 1.2.3.0 since Feb. 1, 2000
1.2.3.4 1.2.3.4 and s is the
number of seconds
1.2.* 1.2.d.s since midnight /2
1.2.3.* 1.2.3.s
<absent> 0.0.0.0

15
Figure 10: Fully specified assembly names

Display Name of Assembly Reference


yourcode, Version=1.2.3.4, Culture=en-US, PublicKeyToken=1234123412341234
or neutral or null
C# Code

using System.Reflection;
[assembly: AssemblyVersion("1.2.3.4") ]
[assembly: AssemblyCulture("en-US") ] // resource-only assm
[assembly: AssemblyKeyFile("acmecorp.snk") ]

16
Loading and resolving assemblies

• Assemblies can be loaded either by an explicit URL or a four-part


assembly name
– Assembly.LoadFrom loads an assembly based on an explicit
CODEBASE (e.g., a file name or URL)
– Assembly.Load 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 System.Reflection;

public static Object LoadCustomerType() {


Assembly a = Assembly.LoadFrom(
"file://C:/usr/bin/xyzzy.dll");
return a.CreateInstance("DevelopMentor.LOB.Customer");
}

18
Figure 12: Assembly resolution and loading

Assembly.Load(name,culture,version,token) AppDomain.BaseDirectory

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 System.Reflection;

public static Object LoadCustomerType() {


Assembly a = Assembly.Load(
"xyzzy, Version=1.2.3.4, " +
"Culture=en-UK, PublicKeyToken=9a33f27632997fcc");
return a.CreateInstance("DevelopMentor.LOB.Customer");
}

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:schemas-microsoft.com: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="Acme.HealthCare"
publicKeyToken="38218fe715288aac" />

<!-- one bindingRedirect per redirection -->


<bindingRedirect oldVersion="1.2.3.4"
newVersion="1.3.0.0“ />
<bindingRedirect oldVersion="1-1.2.3.399"
newVersion="1.2.3.7" />
</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 1.0.1.3 de 89abcde... t3s\e4\yourcode.dll
yourcode 1.0.1.3 en 89abcde... a1x\bb\yourcode.dll
yourcode 1.0.1.8 en 89abcde... vv\a0\yourcode.dll
libzero 1.1.0.0 en 89abcde... ig\u\libzero.dll

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="Acme.HealthCare"
publicKeyToken="38218fe715288aac"/>

<!-- one codeBase per version -->


<codeBase version="1.2.3.4"
href="file://C:/acmestuff/Acme.HealthCare.DLL"/>
<codeBase version="1.3.0.0"
href="http://www.acme.com/bin/Acme.HealthCare.DLL"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

28
Figure 19: APPBASE and the relative search path

m
Main.EXE
(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,... file://C:/myapp/yourcode.dll


file://C:/myapp/yourcode/yourcode.dll
APPBASE file://C:/myapp/shared/yourcode.dll
file://C:/myapp/shared/yourcode/yourcode.dll
file://C:/myapp/myapp.exe file://C:/myapp/aux/yourcode.dll
file://C:/myapp/aux/yourcode/yourcode.dll
Application Configuration File
file://C:/myapp/yourcode.exe
<configuration xmlns:asm="...">
file://C:/myapp/yourcode/yourcode.exe
<runtime>
file://C:/myapp/shared/yourcode.exe
<asm:assemblyBinding>
file://C:/myapp/shared/yourcode/yourcode.exe
<asm:probing
file://C:/myapp/aux/yourcode.exe
privatePath="shared;aux" />
file://C:/myapp/aux/yourcode/yourcode.exe
</asm:assemblyBinding>
</runtime>
</configuration>

31
Figure 22: Culture-dependent probing

Assembly Reference Potential CODEBASEs (in order)

yourcode, Culture=en-US,... file://C:/myapp/en-US/yourcode.dll


file://C:/myapp/en-US/yourcode/yourcode.dll
APPBASE file://C:/myapp/shared/en-US/yourcode.dll
file://C:/myapp/shared/en-US/yourcode/yourcode.dll
file://C:/myapp/myapp.exe file://C:/myapp/aux/en-US/yourcode.dll
file://C:/myapp/aux/en-US/yourcode/yourcode.dll
Application Configuration File
file://C:/myapp/en-US/yourcode.exe
<configuration xmlns:asm="...">
file://C:/myapp/en-US/yourcode/yourcode.exe
<runtime>
file://C:/myapp/shared/en-US/yourcode.exe
<asm:assemblyBinding>
file://C:/myapp/shared/en-US/yourcode/yourcode.exe
<asm:probing
file://C:/myapp/aux/en-US/yourcode.exe
privatePath="shared;aux" />
file://C:/myapp/aux/en-US/yourcode/yourcode.exe
</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
Assembly.Load 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