Events
Mar 17, 9 PM - Mar 21, 10 AM
Join the meetup series to build scalable AI solutions based on real-world use cases with fellow developers and experts.
Register nowThis browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
The AssemblyLoadContext class was introduced in .NET Core and is not available in .NET Framework. This article supplements the AssemblyLoadContext API documentation with conceptual information.
This article is relevant to developers implementing dynamic loading, especially dynamic-loading framework developers.
Every .NET 5+ and .NET Core application implicitly uses AssemblyLoadContext. It's the runtime's provider for locating and loading dependencies. Whenever a dependency is loaded, an AssemblyLoadContext instance is invoked to locate it.
A single AssemblyLoadContext instance is limited to loading exactly one version of an Assembly per simple assembly name. When an assembly reference is resolved against an AssemblyLoadContext instance that already has an assembly of that name loaded, the requested version is compared to the loaded version. The resolution will succeed only if the loaded version is equal or higher to the requested version.
The restriction that a single AssemblyLoadContext instance can load only one version of an assembly can become a problem when loading code modules dynamically. Each module is independently compiled, and the modules may depend on different versions of an Assembly. This is often a problem when different modules depend on different versions of a commonly used library.
To support dynamically loading code, the AssemblyLoadContext API provides for loading conflicting versions of an Assembly in the same application. Each AssemblyLoadContext instance provides a unique dictionary that maps each AssemblyName.Name to a specific Assembly instance.
It also provides a convenient mechanism for grouping dependencies related to a code module for later unload.
The AssemblyLoadContext.Default instance is automatically populated by the runtime at startup. It uses default probing to locate and find all static dependencies.
It solves the most common dependency loading scenarios.
AssemblyLoadContext has various events and virtual functions that can be overridden.
The AssemblyLoadContext.Default instance only supports overriding the events.
The articles Managed assembly loading algorithm, Satellite assembly loading algorithm, and Unmanaged (native) library loading algorithm refer to all the available events and virtual functions. The articles show each event and function's relative position in the loading algorithms. This article doesn't reproduce that information.
This section covers the general principles for the relevant events and functions.
null
rather than throw when unable to find the requested dependency. Throwing will prematurely end the search and propagate an exception to the caller. Throwing should be restricted to unexpected errors like a corrupted assembly or an out of memory condition.null
and letting the AssemblyLoadContext.Default handle the load may be the simplest option.Each AssemblyLoadContext instance represents a unique scope for Assembly instances and Type definitions.
There's no binary isolation between these dependencies. They're only isolated by not finding each other by name.
In each AssemblyLoadContext:
name
.Dependencies can easily be shared between AssemblyLoadContext instances. The general model is for one AssemblyLoadContext to load a dependency. The other shares the dependency by using a reference to the loaded assembly.
This sharing is required of the runtime assemblies. These assemblies can only be loaded into the AssemblyLoadContext.Default. The same is required for frameworks like ASP.NET
, WPF
, or WinForms
.
It's recommended that shared dependencies be loaded into AssemblyLoadContext.Default. This sharing is the common design pattern.
Sharing is implemented in the coding of the custom AssemblyLoadContext instance. AssemblyLoadContext has various events and virtual functions that can be overridden. When any of these functions return a reference to an Assembly instance that was loaded in another AssemblyLoadContext instance, the Assembly instance is shared. The standard load algorithm defers to AssemblyLoadContext.Default for loading to simplify the common sharing pattern. For more information, see Managed assembly loading algorithm.
When two AssemblyLoadContext instances contain type definitions with the same name
, they're not the same type. They're the same type if and only if they come from the same Assembly instance.
To complicate matters, exception messages about these mismatched types can be confusing. The types are referred to in the exception messages by their simple type names. The common exception message in this case is of the form:
Object of type 'IsolatedType' cannot be converted to type 'IsolatedType'.
Given a pair of mismatched types, it's important to also know:
Given two objects a
and b
, evaluating the following in the debugger will be helpful:
// In debugger look at each assembly's instance, Location, and FullName
a.GetType().Assembly
b.GetType().Assembly
// In debugger look at each AssemblyLoadContext's instance and name
System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(a.GetType().Assembly)
System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(b.GetType().Assembly)
There are two design patterns for solving these type conversion issues.
Use common shared types. This shared type can either be a primitive runtime type, or it can involve creating a new shared type in a shared assembly. Often the shared type is an interface defined in an application assembly. For more information, read about how dependencies are shared.
Use marshalling techniques to convert from one type to another.
.NET feedback
.NET is an open source project. Select a link to provide feedback:
Events
Mar 17, 9 PM - Mar 21, 10 AM
Join the meetup series to build scalable AI solutions based on real-world use cases with fellow developers and experts.
Register nowTraining
Learning path
Use advance techniques in canvas apps to perform custom updates and optimization - Training
Use advance techniques in canvas apps to perform custom updates and optimization
Documentation
How to use and debug assembly unloadability in .NET - .NET
Learn how to use collectible AssemblyLoadContext for loading and unloading managed assemblies and how to debug issues preventing the unloading success.
Managed assembly loading algorithm - .NET Core - .NET
Description of the details of the managed assembly loading algorithm in .NET Core
System.Runtime.Loader.AssemblyLoadContext class - .NET
Learn about the System.Runtime.Loader.AssemblyLoadContext class.
Overview of managed and unmanaged dependency loading in .NET 5+ and .NET Core