Search this blog

Friday, April 11, 2008

Assemblies

What is an assembly?

An assembly is sometimes described as a logical .EXE or .DLL, and can be an application (with a main entry point) or a library. An assembly consists of one or more files (dlls, exes, html files etc), and represents a group of resources, type definitions, and implementations of those types. An assembly may also contain references to other assemblies. These resources, types and references are described in a block of data called a manifest. The manifest is part of the assembly, thus making the assembly self-describing.

An important aspect of assemblies is that they are part of the identity of a type. The identity of a type is the assembly that houses it combined with the type name. This means, for example, that if assembly A exports a type called T, and assembly B exports a type called T, the .NET runtime sees these as two completely different types. Furthermore, don't get confused between assemblies and namespaces - namespaces are merely a hierarchical way of organising type names. To the runtime, type names are type names, regardless of whether namespaces are used to organise the names. It's the assembly plus the typename (regardless of whether the type name belongs to a namespace) that uniquely indentifies a type to the runtime.

Assemblies are also important in .NET with respect to security - many of the security restrictions are enforced at the assembly boundary.

How can I produce an assembly?

The simplest way to produce an assembly is directly from a .NET compiler.

For example, the following C# program:

public class CTest
{
public CTest()
{
System.Console.WriteLine( "Hello from CTest" );
}
}

can be compiled into a library assembly (dll) like this:

csc /t:library ctest.cs

You can then view the contents of the assembly by running the "IL Disassembler" tool that comes with the .NET SDK.

Alternatively you can compile your source into modules, and then combine the modules into an assembly using the assembly linker (al.exe). For the C# compiler, the /target:module switch is used to generate a module instead of an assembly.


What is the difference between a private assembly and a shared assembly?

The terms 'private' and 'shared' refer to how an assembly is deployed, not any intrinsic attributes of the assembly.

  • Location and Visiblity:
A private assembly is normally used by a single application, and is stored in the application's directory, or a sub-directory beneath. A shared assembly is intended to be used by multiple applications, and is normally stored in the global assembly cache (GAC), which is a central repository for assemblies maintained by the CLR. (A shared assembly can also be stored outside the GAC, in which case each application must be pointed to its location via a codebase entry in the application's configuration file.) shared assemblies are usually libraries of code which many applications will find useful. E.g. the .NET framework classes.

The main advantage of deploying assemblies to the GAC is that the GAC can support multiple versions of the same assembly side-by-side. Assemblies deployed to the GAC must be strong-named. Outside the GAC, strong-naming is optional.
  • Versioning:
The runtime enforces versioning constraints only on shared assemblies, not on private assemblies


How do assemblies find each other?

By searching directory paths. There are several factors that can affect the path (such as the AppDomain host, and application configuration files), but for weakly named assemblies (Private Assembly) the search path is normally the application's directory and its sub-directories. For strongly named assemblies(shared Assembly), the search path is the GAC followed by the private assembly path

How does assembly versioning work?

Each assembly has a version number called the compatiblity version. Also each reference to an assembly (from another assembly) includes both the name and versions of referenced assembly.

An assembly has a version number consisting of four parts, e.g. 2.2.150.2. These are typically interpreted as Major.Minor.Build.Revision, but this is just a convention.

The CLR applies no version constraints on weakly named assemblies, so the assembly version has no real significance.

For strongly named assemblies, the version of a referenced assembly is stored in the referring assembly, and by default only this exact version will be loaded at run-time. If the exact version is not available, the referring assembly will fail to load. It is possible to override this behaviour in the config file for the referring assembly - references to a single version or a range of versions of the referenced assembly can be redirected to a specific version. For example, versions 1.0.0.0 to 2.0.0.0 can be redirected to version 3.0.125.3. However note that there is no way to specify a range of versions to be redirected to. Publisher policy files offer an alternative mechanism for redirecting to a different version for assemblies deployed to the GAC - a publisher policy file allows the publisher of the assembly to redirect all applications to a new version of an assembly in one operation, rather than having to modify all of the application configuration files.

The restrictions on version policy for strongly named assemblies can cause problems when providing patches or 'hot fixes' for individual assemblies within an application. To avoid having to deploy config file changes or publisher policy files along with the hot fix, it makes sense to reuse the same assembly version for the hot fix. If desired, the assemblies can be distinguised by altering the assembly file version, which is not used at all by the CLR for applying version policy.

Note that the versioning of strongly named assemblies applies whether the assemblies are deployed privately or to the GAC.


No comments:

Post a Comment