Assemblies are the fundamental building blocks of a .NET Framework application. They contain the types and resources that make up an application and describe those contained types to the common language runtime. Assemblies enable code reuse, version control, security, and deployment.
Put simply, an assembly is a project that compiles to an EXE or a DLL file. Although .NET EXE and DLL files resemble their predecessors externally, the internal structure of an assembly is quite different from that of an EXE or DLL created with earlier development tools. An assembly consists of four internal parts:
The assembly manifest, or metadata. This contains information about the assembly that the common language runtime uses to obtain information about the assembly . The type metadata, which exposes information about the types contained within the assembly .
The intermediate language code for your assembly .
Resource files, which are non-executable bits of data, such as strings or images for a specific culture. The assembly manifest contains the metadata that describes the assembly to the common language runtime. The common language runtime then uses the information in the assembly manifest to make decisions about the assembly’s execution. An assembly manifest contains the following information: Identity.
It contains the name and version number of the assembly , and can contain optional information such as locale and signature information. Types and resources. It contains a list of all the types that will be exposed to the common language runtime as well as information about how those types can be accessed. Files: It contains a list of all files in the assembly as well as dependency information for those files. Security permissions
The manifest describes the security permissions required by the assembly . If the permissions required conflict with the local security policy, the assembly will fail to execute. For the most part, the developer does not have to be concerned with the contents of the assembly manifest. It is compiled and presented to the common language runtime automatically. The developer does, however, need to explicitly set the metadata that describes the identity of the assembly . The identity of the assembly is contained in the AssemblyInfo.vb or .cs file for your project. You can set identity information for your assembly by right-clicking the AssemblyInfo icon and choosing View Code from the drop-down menu. The code window will open to the AssemblyInfo code page, which contains default null values for several assembly identity attributes. The following code example shows an excerpt from the AssemblyInfo file.
Creating Class Library Assemblies
You will frequently want to create class library assemblies . These represent sets of types that can be referenced and used in other assemblies . For example, you might have a custom control that you want to use in several applications or a component that exposes higher math functions. Such an assembly is not executable itself, but rather must be referenced by an executable application to be used. You can create class library assemblies and control library assemblies by using the templates provided by Microsoft Visual Studio .NET.
The class library template is designed to help you create an assembly of types that can be exposed to other applications, and the Microsoft Windows control library template is provided to assist you in building assemblies of custom controls.
Creating Resource Files
The .NET Framework includes a sample application called ResEditor that can be used for creating text and image resource files. The ResEditor application is not integrated with Visual Studio .NET-it must be run separately. In fact, it is supplied as source code files and must be compiled before it can be used.
The ResEditor source files are located in the FrameworkSDKSamplesTutorialsresourcesandlocalizationreseditor folder, which is in the folder that Visual Studio .NET is installed in. You can build the application using either the batch file supplied in that folder or by adding the source files to an empty Visual Studio project, configuring, and then building them.
Once you have created resource files, you can embed them in your assembly . This allows you to package resources into the same assembly as the code files, thus increasing the portability of your code and reducing its dependence on additional files. To embed an externally created resource into your assembly , all you have to do is add the file to your project. When the project is built, the resource file will be compiled into the assembly .
Creating Resource Assemblies
You can create assemblies that only contain resources. You might find this useful in situations where you expect to have to update the data contained in resource files, but do not want to have to recompile your application to update it.
Creating Satellite Assemblies
When creating international applications, you might want to provide different sets of resources for different cultures. Satellite assemblies allow different sets of resources to automatically be loaded based on the CurrentUICulture setting of the thread. You learned how to automatically generate applications for localization in Chapter 8. In this section, you will learn how to create additional satellite assemblies and incorporate them into your application.
Visual Studio .NET allows you to effortlessly create satellite assemblies . All you need to do to create a satellite assembly is to incorporate alternate sets of resource files that are appropriately named into your application. Visual Studio .NET does the rest upon compilation.
To be incorporated into a satellite assembly , your resource file must follow a specific naming scheme based on the culture it is designed for. The name of a resource file for a specific culture is the same as the name of the resource file for the invariant culture, and the culture code is inserted between the base name and the extension. Thus, if we had a resource file named MyResources.resx, a resource file containing alternate resources for neutral German UIs would be named MyResources.de.resx. And a version of the file containing German resources specific for Luxembourg would be named MyResources.de-LU.resx.
Once these alternate versions of the file are added to your solution, they will automatically be compiled by Visual Studio .NET into satellite assemblies , and a directory structure for them will be created. At run time, the culture-specific resources contained in these files will automatically be located by the common language runtime.
Retrieving Resources at Run Time
At run time, you can use the ResourceManager class to retrieve embedded resources. A ResourceManager, as the name implies, manages access and retrieval of resources embedded in assemblies . Each instance of a ResourceManager is associated with an assembly that contains resources.
You can create a ResourceManager by specifying two parameters: the base name of the embedded resource file and the assembly in which that file is found. The new ResourceManager will be dedicated to the embedded resource file that you specify. The base name of the file is the name of the namespace that contains the file and the file without any extensions.
The assembly parameter refers to the assembly that the resource file is located in. If the assembly that contains the resources is the same assembly that contains the object that is creating the ResourceManager, you can get a reference to the assembly from the type object of your object.
Understanding Private and Shared Assemblies
Most of the assemblies you create will be private assemblies . Private assemblies are the most trouble free for developers and are the kind of assembly created by default. A private assembly is an assembly that can be used by only one application. It is an integral part of the application, is packaged with the application, and is only available to that application. Because private assemblies are used by one application only, they do not have versioning or identity issues. Up to this point, you have only created private assemblies .
When you add a reference to a private assembly to your project, Visual Studio .NET creates a copy of the DLL containing that assembly and writes it to your project folder. Thus, multiple projects can reference the same DLL and use the types it contains, but each project has its own copy of the DLL and therefore has its own private assembly .
Only one copy of shared assemblies , on the other hand, is present per machine. Multiple applications can reference and use a shared assembly . You can share an assembly by installing it to the Global Assembly Cache. There are several reasons why you might want to install your assembly to the Global Assembly Cache. For example:
Shared location. If multiple applications need to access the same copy of an assembly , it should be shared.
Security. The Global Assembly Cache is located in the C:WINNT (Microsoft Windows 2000) or WINDOWS (Microsoft Windows XP) folder, which is given the highest level of security by default.
Side-by-side versioning. You can install multiple versions of the same assembly to the Global Assembly Cache, and applications can locate and use the appropriate version.
For the most part, however, assemblies that you create should be private. You should only share an assembly when there is a valid reason to do so. Sharing an assembly and installing it to the Global Assembly Cache requires that your assembly be signed with a strong name.