Collectible Assembly in non-collectible AssemblyLoadContext

.NET incorrectly allowed garbage-collectible assemblies to resolve into a non-collectible AssemblyLoadContext. In some cases, this lead to runtime crashes or unexpected NullReferenceException exceptions. This change prevents the incorrect behavior by throwing an exception when the AssemblyLoadContext.Load(AssemblyName) or AssemblyLoadContext.Resolving event returns a collectible Assembly and the AssemblyLoadContext is non-collectible.

Previous behavior

Returning a collectible Assembly in the AssemblyLoadContext.Load(AssemblyName) override or the AssemblyLoadContext.Resolving event of a non-collectible AssemblyLoadContext doesn't cause any exceptions to be thrown.

New behavior

Returning a collectible Assembly in the AssemblyLoadContext.Load(AssemblyName) override or the AssemblyLoadContext.Resolving event of a non-collectible AssemblyLoadContext throws a System.IO.FileLoadException with a NotSupportedException as the inner exception.

Version introduced

.NET 7

Type of breaking change

This change can affect binary compatibility.

Reason for change

This change fixes a bug. The collectible Assembly would be garbage-collected while the AssemblyLoadContext that has a reference to it is alive for the rest of the process lifetime. If the code running in that context references anything from that Assembly after it's collected, it would crash the runtime or result in a NullReferenceException, AccessViolationException, or other kinds of bad behavior.

Don't return collectible assemblies in AssemblyLoadContext.Load(AssemblyName) or the AssemblyLoadContext.Resolving event of a non-collectible AssemblyLoadContext. A possible workaround is to change the AssemblyLoadContext to be collectible by passing true for the isCollectible parameter in its constructor, and then keep a reference to that AssemblyLoadContext forever to make sure it's never collected.

Affected APIs

See also