Assemblies in C#
In C#, an assembly is a fundamental unit of deployment, versioning, and security within the .NET framework. An assembly is a compiled code library used by applications to perform specific tasks, and it is typically packaged as a DLL (Dynamic Link Library) or EXE (Executable) file.
Assemblies are crucial because they contain the metadata, code, and resources needed by .NET applications. Understanding assemblies is essential for managing code reuse, deploying applications, and handling versioning and security in .NET.
1. What is an Assembly?
An assembly is a collection of one or more files (DLLs or EXEs) that are compiled from C# code and other resources. It is the basic building block of .NET applications. Assemblies contain:
- Code: This includes the IL (Intermediate Language) code, which is platform-agnostic and can be executed by the Common Language Runtime (CLR).
- Metadata: Information about types, methods, properties, and other elements within the assembly. Metadata also includes versioning, culture, and security information.
- Manifest: The manifest contains metadata that describes the assembly itself, such as its version, name, culture, and a list of other assemblies it depends on.
- Resources: These are files like images, configuration files, and data that are needed by the assembly to function.
Assemblies can either be private (used by a single application) or shared (used by multiple applications).
2. Types of Assemblies
Assemblies in .NET can be categorized into two types:
A. Private Assemblies
- Private assemblies are used by a single application and are typically stored in the same directory as the application.
- They are only accessible to the application that references them.
- Most .NET applications use private assemblies, especially for custom libraries and components.
B. Shared Assemblies
- Shared assemblies are used by multiple applications and are usually stored in a centralized location, such as the Global Assembly Cache (GAC).
- A shared assembly must be strongly named, which includes its name, version, culture, and public key.
- The GAC is a global store that allows multiple applications to share assemblies without version conflicts.
3. Structure of an Assembly
An assembly is a collection of files, and it contains several key components:
A. Metadata
- Metadata is a set of data that describes the contents of the assembly. It provides information about the types (classes, interfaces, structs) and members (methods, properties) defined in the assembly.
- The metadata also includes information about the assembly's version, its dependencies, and security-related data.
B. IL Code
- IL (Intermediate Language) is the low-level language that the CLR understands. When you compile a C# program, the code is converted into IL rather than machine code. The CLR then JIT-compiles this IL into native machine code when it is executed.
C. Manifest
- The manifest is a special part of the assembly's metadata. It contains important information about the assembly such as:
- Name: The name of the assembly.
- Version: The version of the assembly.
- Dependencies: A list of other assemblies that this assembly depends on.
- Public Key: If the assembly is strongly named, it will include a public key used for identity and signature verification.
D. Resources
- Resources in an assembly can include things like strings, images, configuration files, etc. These resources are embedded in the assembly and can be accessed at runtime.
4. Strongly Named Assemblies
A strongly named assembly is an assembly that has a unique identity, which is guaranteed by signing the assembly with a public and private key pair. A strongly named assembly includes the following elements:
- Assembly Name: The name of the assembly.
- Version: The version of the assembly (e.g., 1.0.0.0).
- Culture: Information about the language and locale.
- Public Key: The public key used to uniquely identify the assembly.
A strongly named assembly can be stored in the Global Assembly Cache (GAC), which allows it to be shared across multiple applications. When creating a strongly named assembly, you are essentially ensuring that the assembly has a unique identity, which helps avoid conflicts when different versions of the same assembly are used.
To create a strongly named assembly, you need to generate a public/private key pair and sign the assembly.
5. Global Assembly Cache (GAC)
The Global Assembly Cache (GAC) is a central repository for storing shared assemblies in .NET. Assemblies that are shared by multiple applications are typically stored in the GAC.
A. Benefits of the GAC
- Centralized Storage: Assemblies are stored in one central location on the system, making it easier to manage shared assemblies.
- Versioning: The GAC allows multiple versions of the same assembly to coexist. Applications can reference a specific version of the assembly, which helps avoid version conflicts.
- Security: Assemblies stored in the GAC must be strongly named, ensuring that they cannot be tampered with.
B. How to Install Assemblies in the GAC
You can install assemblies into the GAC using tools like the GacUtil tool or by adding them through Visual Studio.
Using GacUtil:
- Open the Developer Command Prompt for Visual Studio.
- Use the
gacutil command to install the assembly into the GAC:
gacutil -i <path-to-assembly>\MyAssembly.dll
This command will install the specified assembly into the GAC.
6. Working with Assemblies in C#
A. Adding References to Assemblies
You can add references to assemblies in C# projects through the .NET CLI, Visual Studio, or by editing the project file manually.
Using the .NET CLI:
To add a reference to an assembly:
dotnet add reference <path-to-assembly>\MyAssembly.dll
Using Visual Studio:
- Right-click on References in the Solution Explorer.
- Click Add Reference.
- Select Browse to find the assembly, or choose from the list of assemblies already available.
Adding a NuGet Package Reference:
For a NuGet package, you can use the CLI to install it:
dotnet add package Newtonsoft.Json
7. Assembly Versioning
One of the key features of assemblies is versioning. Assembly versioning allows the runtime to ensure compatibility when different versions of assemblies are used. There are two types of version numbers in C#:
A. Assembly Version
This is a version number (typically in the format major.minor.build.revision) that helps identify the assembly. The version number is specified when the assembly is compiled and is included in the assembly’s metadata.
[assembly: AssemblyVersion("1.0.0.0")]
B. Assembly File Version
The file version is another version number that is used to describe the file itself (separate from the assembly version). It is typically set to match the assembly version but can be different.
[assembly: AssemblyFileVersion("1.0.0.0")]
C. Versioning Strategy
- Major Version: Changed when there are significant updates, such as breaking changes.
- Minor Version: Changed when there are backward-compatible updates, such as new features or functionality.
- Build Number: Used for incremental builds (often set automatically).
- Revision: Typically used for bug fixes.
8. Accessing Metadata from Assemblies
You can inspect the metadata of assemblies at runtime using reflection in C#:
using System;
using System.Reflection;
class Program
{
static void Main()
{
Assembly assembly = Assembly.LoadFrom("MyClassLibrary.dll");
Console.WriteLine($"Assembly Full Name: {assembly.FullName}");
Console.WriteLine($"Assembly Location: {assembly.Location}");
Type[] types = assembly.GetTypes();
foreach (var type in types)
{
Console.WriteLine(type.Name);
}
}
}
This code loads an assembly, displays its full name and location, and lists all the types defined in the assembly.
9. Summary
An assembly in C# is a compiled code library that contains executable code, metadata, resources, and a manifest. Assemblies are the building blocks of .NET applications and are essential for managing code reuse, versioning, and security.
Key Points:
- Assembly Types: Private (used by a single application) and Shared (used by multiple applications).
- Strongly Named Assemblies: Ensures unique identity and versioning, allowing for sharing in the Global Assembly Cache (GAC).
- Global Assembly Cache (GAC): A central store for shared assemblies, enabling versioning and security.
- Versioning: Assemblies have version numbers to ensure backward compatibility and prevent version conflicts.
- Reflection: Allows you to inspect and work with assembly metadata at runtime.
Understanding assemblies is crucial for deploying, managing, and maintaining .NET applications, as they provide the structure, versioning, and reusability needed in modern software development.