Assemblies in .NET
An assembly is the fundamental unit of deployment, versioning, reuse, activation, and security in the .NET ecosystem. It's a collection of types and resources that are built to work together and form a logical unit of functionality. Every .NET application, whether it's a simple console application or a complex enterprise system, is composed of one or more assemblies.
What an Assembly Contains
An assembly is the smallest deployable unit in the .NET Framework. It's typically packaged as a DLL (Dynamic Link Library) or an EXE (executable) file. Internally, an assembly is composed of:
- A manifest: This is metadata that describes the assembly itself, including its version, culture, name, public key token, and a list of all the files that constitute the assembly. It also contains information about the types defined in the assembly and the other assemblies it depends on.
- Type metadata: This describes all the types (classes, interfaces, enums, delegates, etc.) that are defined in the assembly.
- MSIL (Microsoft Intermediate Language) code: This is the compiled code that the .NET Common Language Runtime (CLR) will execute. It's not machine code but an intermediate representation that can be further compiled by the Just-In-Time (JIT) compiler into native machine code for the target platform.
- Optional resources: This can include things like string tables, images, or other data files that are embedded within the assembly.
Key Characteristics and Benefits
- Versioning: Assemblies provide a robust versioning mechanism. The CLR uses assembly versions to ensure that applications load the correct versions of their dependencies, preventing version conflicts.
- Deployment: Assemblies are the units that are deployed. This simplifies the process of distributing and installing applications.
- Code Reuse: Assemblies can be shared across multiple applications, promoting code reuse and reducing redundancy.
- Security: The CLR can apply security policies at the assembly level, controlling the permissions granted to code.
- Self-Describing: The manifest within an assembly makes it self-describing, providing all the necessary information for the CLR to load and execute it correctly.
Types of Assemblies
- Executable Assemblies (EXEs): These are applications that have an entry point (a `Main` method) and can be directly executed.
- Library Assemblies (DLLs): These contain code and types that are intended to be used by other assemblies. They do not have a direct entry point for execution.
Assembly Loading
When an application needs to use types from another assembly, the CLR is responsible for locating and loading that assembly into memory. This process involves:
- Checking the application's configuration files for assembly binding information.
- Searching the application's directory and the Global Assembly Cache (GAC).
- If found, the assembly is loaded into the application domain.
- The CLR performs verification and JIT compilation of the code before it can be executed.
Example of referencing an assembly:
In your C# project, you typically add a reference to another assembly. This tells the compiler that the types defined in that assembly are available for use in your code. For instance, referencing the System.Text.Json
assembly would allow you to use its JSON serialization/deserialization capabilities.
// Example in C#
using System.Text.Json;
public class Person {
public string Name { get; set; }
public int Age { get; set; }
}
public class Program {
public static void Main(string[] args) {
var person = new Person { Name = "Alice", Age = 30 };
string jsonString = JsonSerializer.Serialize(person);
System.Console.WriteLine(jsonString);
}
}