Friday, August 31, 2007

Assemblies in C#

Assemblies

An assembly is the functional unit of sharing and reuse in the Common Language Runtime. It provides the Common Language Runtime with the information it needs to be aware of type implementations. To the runtime, a type does not exist outside the context of an assembly. Assemblies are a fundamental part of the runtime.

In physical terms, an assembly is a collection of physical files that are owned by the assembly. These assemblies, called static assemblies, can include .NET Framework types (interfaces and classes) as well as resources for the assembly (bitmaps, JPEG files, resource files, etc.). In addition, the Common Language Runtime provides API's that script engines use to create dynamic assemblies when executing scripts. These assemblies are run directly and are never saved to disk, though you can save them to disk if you so choose.

Assembly Concepts

An assembly forms a logical unit of functionality, a “logical” dll. An assembly forms the fundamental unit of deployment, version control, reuse, activation scoping, and security permissions. Contained in an assembly is the assembly manifest, which contains all the metadata needed to specify the version requirements, security identity, and all information needed to define the scope of the assembly and resolve references to resources and classes.

It is important to understand what an assembly is not. An assembly is not a unit of application deployment. It is a unit of class deployment, much like a dll. An application is built from assemblies, and these assemblies can be packaged for deployment in several ways.

Versioning and DLL Conflicts

Currently there are two versioning problems that occur with Win32 applications. First, current applications cannot express versioning rules between pieces of an application and have these rules honored and enforced by the operating system. The current approach relies on “common-sense” coding practices that state that interface definitions are static once published and that a single piece of code must maintain backward compatibility with previous versions. Furthermore, code is typically designed so that only a single version of it can be present and executing on a machine at any given time.

The second versioning problem is the fact that there is no way to maintain consistency between the sets of components that were built together and the set that will be present at run time. These two versioning problems combine to create DLL conflicts, where installing one application can inadvertently break an existing application because a certain software component or DLL was installed that was not fully backward compatible with a previous version. Once this situation occurs, there is no support in the system for diagnosing and fixing the problem.

An End to DLL Conflicts

Windows 2000 introduced some progress toward fixing DLL conflicts. First, Windows 2000 enables you to create client applications where the dependent DLLs are located in the same directory as the application’s EXE. Windows 2000 first check for the component in the directory where the EXE is located before checking the fully qualified path or doing the normal path search. This allows components to be independent of components installed and used by other applications.

The second feature in Windows 2000 designed to partially fix DLL conflicts is System File Protection. The operating system locks the files in the System32 directory that are shipped with the OS so they cannot be inadvertently replaced when applications are installed.

The Common Language Runtime continues this evolution toward a complete solution to DLL conflicts. To solve the remaining problems that lead to DLL conflicts, the runtime:

· Allows developers to specify version rules between different software components

· Provides the infrastructure to enforce versioning rules

· Provides the infrastructure to allow multiple versions of a software component to be run simultaneously (called side-by-side execution)

The runtime solves versioning problems by using assemblies.

Assemblies and Deploying

An assembly is not a packaging format in and of itself. An assembly to be deployed is usually made up of PE files and resource files, and these files can be deployed in a number of ways. How you choose to create assemblies will dictate much of your deployment story.

You can deploy assemblies using the Windows Installer, Internet Explorer, or by copying the assembly. Assemblies can be deployed in as .cab files or as .msi files. You can also simply download or xcopy an assembly to deploy.

How the Common Language Runtime Works with Assemblies

The Common Language Runtime can only execute code in assemblies. The runtime works with two types of assemblies: static assemblies and dynamic assemblies. A static assembly is the kind of assembly you will most often work with; this is the unit produced when working with most developer environments. A static assembly consists of code modules and resources that are loaded from disk or downloaded for use by the runtime.

In contrast, a dynamic assembly is one built “on-the-fly” by the runtime from scripts on a web page or with Reflection.Emit. These dynamic assemblies can be transient---never persisted to disk---or they can be persisted and saved to disk. Persisted dynamic assemblies can be emitted with Reflection.Emit and saved for later use.

The Minimum You Need to Know About Assemblies

As a developer, you can think of an assembly as a “logical” dll. Here is a list of things you should remember about an assembly:

· It contains code that the runtime will execute. MSIL code in a PE file will not be executed if it does not have an assembly manifest associated with it. Note too that each assembly can have only one entry point (i.e. DllMain, WinMain, or Main).

· It forms a security boundary – An assembly is the unit at which permissions are requested and granted. For more information on security boundaries as they apply to assemblies

· It forms a type boundary – Every type has as part of its identity the assembly in which it resides. Therefore, a type MyType loaded in the scope of one assembly is not the same as type MyType loaded in the scope of another assembly. For more information on assemblies and type boundaries.

· It forms a reference scope boundary – The assembly’s manifest contains the rules for resolving types and resources. It specifies what types and resources are exposed outside the assembly. The manifest also enumerates other assemblies on which it is dependent.

· It forms a version boundary – The assembly is the smallest versionable unit in the Common Language Runtime; all types and resources in the same assembly are versioned as a unit. The assembly’s manifest describes the version dependencies you specify for any dependent assemblies.

· It forms a deployment unit – An application when launched only requires those assemblies it initially calls. All assemblies of an application do not have to be present at run time; other assemblies, such as localization resources, can be retrieved on demand. This allows downloaded applications to be kept simple and thin.

· It is the unit at which side-by-side execution is supported. For more information on running multiple versions of the same assembly.

Some of the information in an assembly manifest can be overridden by an application or machine-wide configuration file.

Assembly Manifest

An assembly’s manifest contains information on all items considered part of an assembly; this information is known as the assembly's metadata. The manifest indicates what items are exposed outside of the assembly and what items are accessible only within the current assembly’s scope. The assembly’s manifest also contains a collection of references to other assemblies. These references are resolved by the runtime based on information stored in the manifest. The assembly's manifest contains all information needed to use an assembly.

All assemblies have a manifest, and all applications that use the runtime must be made up of an assembly or assemblies. All files that make up the assembly must be listed in a manifest.

Figure:1

As you can see from the above illustration, the manifest can be stored in several ways. For an assembly with one associated file, the manifest is incorporated into the PE file to form a single-file assembly. A multi-file assembly can be created with either the manifest as a stand-alone file or incorporated into one of the PE files in the assembly.

From an external view (i.e. that of the assembly consumer), an assembly is a named and version-constrained collection of exported types and resources. From the internal view (i.e. that of the assembly developer), an assembly is a collection of one or more files that implement types and resources. Each assembly’s manifest enumerates the files that make up the assembly and governs how references to the assembly's types and resources are mapped to the files that contain their declarations and implementations. The manifest also enumerates other assemblies on which it depends. The existence of a manifest provides a level of indirection between consumers of the assembly and the implementation details of the assembly and renders assemblies self-describing.

The manifest contains the following information:

· Assembly name - contains a textual string name of the assembly.

· Version information -consists of a major and minor version number, and a revision and build number. These numbers are used by the runtime when enforcing version policy.

· Shared name information - contains the public key from the publisher and a hash of the file containing the manifest signed with the publisher's private key. For more information on shared names.

· Culture, processor and OS supported - contains information on the cultures, processors, and operating systems the assembly supports. For this release, this processor and OS information is ignored by the runtime.

· List of all files in the assembly - consists of a hash of each file contained in the assembly and a relative path to the file from the manifest file. Note that all files that make up the assembly must be in the same directory as the manifest file.

· Type reference information - contains information used by the runtime to map a type reference to the file that contains its declaration and implementation.

· Information on referenced assemblies - contains a list of other assemblies that are statically referenced by the assembly. Each reference includes the dependent assembly's name, metadata (version, culture, OS, etc.), and public key if the assembly is shared.

A developer can also set, in code, custom assembly attributes. These attributes are informational only and are not used by the runtime in any way. Custom attributes include:

· Title - Provides a friendly name, which can include spaces. For example, the assembly name of an assembly might be “comdlg,” while the assembly title would be “Microsoft Common Dialog Control.”

· Description - a short description of the assembly.

· Default Alias - Provides a friendly default alias in cases where the assembly name is not friendly or a GUID.

· Configuration information - consists of a string that can be set to any value for configuration information such as Retail or Debug.

· Product information such as Trademark, Copyright, Product, Company, and InformationalVersion.

Assembly Custom Attributes

You can view the attributes assigned to an assembly when it was first created, and you can add information to an assembly by using custom attributes. There are two sets of assembly attributes for this release.

The first set of assembly attributes include four fields from the assembly manifest (Title, Description, DefaultAlias, and Configuration) and five custom attributes for company or product information (Trademark, Copyright, Product, Company, InformationalVersion). These attributes are represented by nine classes in the System.Reflection namespace. The runtime adds these values to the assembly manifest when the assembly is created. You can query this information using the class System.Reflection.

Table :1

Assembly Attribute Class

Description

AssemblyCompanyAttribute

Company or additional product information

AssemblyConfigurationAttribute

Build information, such as “retail” or “debug”

AssemblyCopyrightAttribute

Copyright information for the product or assembly

AssemblyDefaultAliasAttribute

Additional information on the assembly’s name or alias

AssemblyDescriptionAttribute

Description of the product or modules that make up the assembly

AssemblyInformationalVersionAttribute

Additional or supporting version information, such as a commercial product version number

AssemblyProductAttribute

Product information

AssemblyTitleAttribute

The assembly's title

AssemblyTrademarkAttribute

Trademark information

The second set of assembly attributes are contained in the System.Runtime.CompilerServices namespace. These are custom attributes that you can add to code, and this information is added to an assembly when the assembly is created. You can put these custom attributes in any module to be included in the assembly.

Table :2 shows the attribute which include :

Assembly Attribute

Description

AssemblyCultureAttribute

Information on what cultures or languages the assembly supports

AssemblyDelaySignAttribute

Specifies that the assembly should not be fully signed when created, but rather “delay signed,” which means space is reserved for the signature which is later filled by a signing tool like the sn.exe utility

AssemblyKeyFileAttribute

Specifies the name of the file containing the key pair used to sign the assembly (i.e. give it a shared name)

AssemblyKeyNameAttribute

Specifies the name of the key container. Instead of placing a key pair in a fie, you can store it in a key container in the CSP. If you choose this option, this attribute will contain the name of the key container

AssemblyOperatingSystemAttribute

Information on which operating system the assembly was built to support.

AssemblyProcessorAttribute

Information on which processors the assembly was built to support.

AssemblyVersionAttribute

Specifies the assembly’s version information, in the format major.minor.build.rev

No comments: