Assemblies

An assembly is a logical package (similar to a DLL in Win32) that consists of a manifest, a set of one or more modules, and an optional set of resources. This package forms the basic unit of deployment and versioning, and creates a boundary for type resolution and security permissioning.

Elements of an Assembly

Every .NET application consists of at least one assembly, which is in turn built from a number of basic elements.

The manifest contains a set of metadata that describes everything the runtime needs to know about the assembly. This information includes:

  • The textual name of the assembly

  • The version number of the assembly

  • An optional shared name and signed assembly hash

  • The list of files in the assembly with file hashes

  • The list of referenced assemblies, including versioning information and an optional public key

  • The list of types included in the assembly, with a mapping to the module containing the type

  • The set of minimum and optional security permissions requested by the assembly

  • The set of security permissions explicitly refused by the assembly

  • Culture, processor, and OS information

  • A set of custom attributes to capture details such as product name, owner information, etc.

Modules contain types described using metadata and implemented using MSIL.

Resources contain nonexecutable data that is logically included with the assembly. Examples of this include bitmaps, localizable text, persisted objects, etc.

Packaging

The simplest assembly contains a manifest and a single module containing the application’s types, packaged as an EXE with a Main entry point. More complex assemblies can include multiple modules ( Portable Executable (PE) files), separate resource files, manifest, etc.

The manifest is generally included in one of the existing PE files in the assembly, although the manifest can also be a standalone PE file.

Modules are PE files, typically DLLs or EXEs. Only one module in an assembly can contain an entry point (either Main, WinMain, or DllMain).

An assembly may also contain multiple modules. This technique can reduce the working set of the application, as the CLR loads only the required modules. In addition, each module can be written in a different language, allowing a mixture of C#, VB.NET, and raw MSIL. Although not common, a single module could also be included in several different assemblies.

Finally, an assembly may contain a set of resources, which can either be kept in standalone files or included in one of the PE files in the assembly.

Deployment

An assembly is the smallest .NET unit of deployment. Due to the self-describing nature of a manifest, deployment can be as simple as copying the assembly (and in the case of a multifile assembly, all the associated files) into a directory.

This is a vast improvement over traditional COM development where components, their supporting DLLs, and their configuration information are spread out over multiple directories and the Windows registry.

Generally, assemblies are deployed into the application directory and are not shared. These are called private assemblies. However, assemblies can also be shared between applications, and these are called shared assemblies. To share an assembly you need to give it a shared name (also known as a “strong” name) and deploy it in the global assembly cache.

The shared name consists of a name, a public key, and a digital signature. The shared name is included in the assembly manifest and forms the unique identifier for the assembly.

The global assembly cache is a machine-wide storage area that contains assemblies intended for use by multiple applications.

For more information on working with shared assemblies and the global assembly cache, see Section 5.1.4 in Appendix E.

Versioning

The manifest of an application contains a version number for the assembly and a list of all the referenced assemblies with associated version information. Assembly version numbers are divided into four parts and look like this:

               <major>.<minor>.<build>.<revision>
               
               
               
               

This information is used to mitigate versioning problems as assemblies evolve over time.

At runtime, the CLR uses the version information specified in the manifest and a set of versioning policies defined for the machine to determine which versions of each dependent, shared assembly to load.

The default versioning policy for shared assemblies automatically uses the newest available version with matching major and minor version numbers. By changing a configuration file, the application or an administrator can override this behavior.

Private assemblies have no versioning policy, and the CLR simply loads the newest assemblies found in the application directory.

Type Resolution

The unique identifier for a type (known as a TypeRef ) consists of a reference to the assembly it was defined in and the fully qualified type name (including any namespaces). For example, this local variable declaration:

System.Net.WebRequest wr;

is represented in MSIL assembly language as follows:

.assembly extern System.Net { .ver 1:0:2204:4 ... }
.locals(class [System.Net]System.Net.WebRequest wr)

In this example, the System.Net.WebRequest type is scoped to the System.Net shared assembly, which is identified using a shared name and associated version number.

When your application starts, the CLR attempts to resolve all static TypeRefs by locating the correct versions of each dependent assembly (as determined by the versioning policy) and verifying that the types actually exist (ignoring any access modifiers).

When your application attempts to use the type, the CLR verifies that you have the correct level of access and throws runtime exceptions if there is a versioning incompatibility.

Security Permissions

The assembly forms a boundary for security permissioning.

The assembly manifest contains hashes for any referenced assemblies (determined at compile time), a list of the minimum set of security permissions the assembly requires in order to function, a list of the optional permissions that it requests, and a list of the permissions that it explicitly refuses (i.e., never wants to receive).

To illustrate how these permissions might be used, imagine an email client similar to Microsoft Outlook, developed using the .NET Framework. It probably requires the ability to communicate over the network on ports 110 (POP3), 25 (SMTP), and 143 (IMAP4). It might request the ability to run Javascript functions in a sandbox to allow full interactivity when presenting HTML emails. Finally, it probably refuses ever being granted the ability to write to disk or read the local address book, thus avoiding scripting attacks such as the ILoveYou virus.

Essentially, the assembly declares its security needs and assumptions, but leaves the final decision on permissioning up to the CLR, which enforces local security policy.

At runtime the CLR uses the hashes to determine if a dependent assembly has been tampered with and combines the assembly permission information with local security policy to determine whether to load the assembly and which permissions to grant it.

This mechanism provides fine-grained control over security and is a major advantage of the .NET Framework over traditional Windows applications.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.124.49