Skip to content

fix/11848: BAML assembly resolution to respect AssemblyLoadContext - #11849

Open
cunhamauro wants to merge 2 commits into
dotnet:mainfrom
cunhamauro:fix/11848
Open

fix/11848: BAML assembly resolution to respect AssemblyLoadContext#11849
cunhamauro wants to merge 2 commits into
dotnet:mainfrom
cunhamauro:fix/11848

Conversation

@cunhamauro

@cunhamauro cunhamauro commented Aug 20, 2026

Copy link
Copy Markdown

Fixes #11848

Description

A BAML reference normally identifies an assembly by its name and version. If more than one loaded assembly in the global appdomain satisfies that criteria, it becomes ambiguous. Selecting the last loaded matching assembly from a process-wide set of loaded assemblies can bind BAML to a type from an unrelated ALC.

The parser must instead resolve the reference in the loading context appropriate to the BAML-owning assembly. This preserves the normal rule that code and the BAML it owns refer to the same component-local types.

Customer Impact

This issue has impact on both companies that develop and ship products and on their clientes that load different products simultaneously into a single host application.

Regression

This issue was not present in .NET Framework because it did not allow assemblies with the same combination of name and version to be loaded more than once.

Testing

The fix has been validated locally using this project: https://github.com/cunhamauro/XamlParserTypeIdentityMismatch

image

Risk

The implementation risk is minimal because the fix follows the CLR’s existing assembly-loading semantics: a dependency is resolved in the AssemblyLoadContext of the assembly that requests it.
In most applications, this change will not produce any observable difference because assemblies are loaded into the default AssemblyLoadContext. The change only affects scenarios where the same assembly identity is loaded in multiple ALCs.

Microsoft Reviewers: Open in CodeFlow

Read more about this @:

Update Baml2006SchemaContext to resolve BAML-referenced assemblies in the
AssemblyLoadContext of the assembly that initiated the resolution.

Previously, BAML assembly resolution was effectively AssemblyLoadContext-
unaware: it relied on global assembly resolution through the application
domain, which could return an assembly loaded into a different context or
fail to resolve assemblies that only existed in a custom
AssemblyLoadContext.

Resolve assemblies through the requesting assembly's AssemblyLoadContext
first, preserving the load-context identity of the requesting assembly and
ensuring BAML dependencies are resolved from the same isolated context.
Fall back to the existing global resolution logic when the requesting
assembly has no associated AssemblyLoadContext or the context cannot
resolve the requested assembly.

This enables proper BAML support for applications and plugins using custom
AssemblyLoadContexts and prevents cross-context assembly resolution.
@cunhamauro
cunhamauro requested review from a team and a lite review from Copilot August 20, 2026 05:47
@cunhamauro
cunhamauro requested a review from a team as a code owner August 20, 2026 05:47
@dotnet-policy-service dotnet-policy-service Bot added PR metadata: Label to tag PRs, to facilitate with triage Community Contribution A label for all community Contributions labels Aug 20, 2026
@cunhamauro

Copy link
Copy Markdown
Author

@dotnet-policy-service agree

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates WPF’s BAML assembly resolution to prefer resolving referenced assemblies within the AssemblyLoadContext associated with the BAML-owning (“local”) assembly, addressing type identity mismatches when multiple ALCs load assemblies with the same identity.

Changes:

  • Add a NETCOREAPP-guarded resolution path that calls AssemblyLoadContext.GetLoadContext(_localAssembly) and attempts alc.LoadFromAssemblyName(...) before legacy lookup.
  • Preserve existing legacy resolution behavior as a fallback when ALC-based resolution is unavailable or fails.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Swallow only specific assembly-load failures and not non-load-related exceptions.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@h3xds1nz

h3xds1nz commented Aug 20, 2026

Copy link
Copy Markdown
Member

This unfortunately requires fixes in numerous other places, it is not as simple. Beyond fixes there are also considerations since fixing this won't come without trade-offs and explaining silent failures.

@cunhamauro

cunhamauro commented Aug 20, 2026

Copy link
Copy Markdown
Author

This unfortunately requires fixes in numerous other places, it is not as simple. Beyond fixes there are also considerations since fixing this won't come without trade-offs and explaining silent failures.

I cannot dismiss that concern with certainty. All existing tests and checks pass, and I have also validated the change successfully against a focused reproduction using multiple isolated AssemblyLoadContext instances. However, I agree that resolving this specific issue does not by itself prove that every existing WPF loading scenario remains unaffected.
That said, the proposed change is intentionally narrow and conservative. ResolveAssembly has only two direct call paths: resolution of assemblies associated with XAML namespaces, and resolution of CLR/XAML types referenced by BAML. These paths subsequently cover elements, properties, attached properties, markup extensions, resource keys, styles, templates, and deferred content, so the potential impact is broad, but the new behavior is entered only when all of the following are true:

  • The assembly has not already been resolved and cached by that Baml2006SchemaContext.
  • The schema context has a non-null local assembly.
  • An AssemblyLoadContext can be obtained for that local assembly.
  • Resolution initiated from that context succeeds.

Known WPF assemblies and previously resolved entries continue through the existing cache fast path. Readers created without a local assembly also retain the previous behavior entirely. If context-based resolution fails with one of the expected assembly-loading exceptions, FileNotFoundException, FileLoadException, or BadImageFormatException, the existing legacy resolution logic is preserved as a fallback.
For most ordinary WPF applications, the local assembly belongs to the Default ALC. The new code will therefore initiate the bind from the Default ALC, which should normally produce the same assembly identity that the application already expects. For isolated add-in scenarios, however, it gives the requesting assembly’s ALC the first opportunity to resolve the dependency instead of selecting an arbitrary matching assembly through the existing process-wide lookup.
Strictly speaking, AssemblyLoadContext.LoadFromAssemblyName initiates the bind from the selected context; the runtime may still resolve a shared dependency from the Default ALC as part of its normal binding algorithm. The change therefore follows the runtime’s established ALC resolution semantics rather than forcing an assembly into a particular context.
I also agree that there are trade-offs worth considering:

  • A custom ALC’s Load override or Resolving handlers may now be invoked earlier.
  • Applications with resolvers that have observable side effects may see a different resolution order.
  • Applications that implicitly relied on WPF selecting an assembly from an unrelated ALC may observe different behavior, although that cross-context selection is the source of the type-identity problem being addressed.
  • Unexpected exceptions thrown by custom resolver code will propagate. Only expected load failures are swallowed, specifically to avoid hiding unrelated resolver bugs or other silent failures.

Deferred resources and templates reuse the same Baml2006SchemaContext, whose local assembly remains fixed, so their subsequent cached resolutions remain associated with the same requesting context. Concurrent resolution should also converge on the same assembly because AssemblyLoadContext controls its own assembly cache.
You may therefore be right that additional affected scenarios exist, and I am not claiming that this single change resolves every possible ALC-related issue in WPF. My current assessment is that it fixes this specific incorrect BAML binding at the common point where assembly identity is chosen, while retaining the original behavior whenever context-based resolution is unavailable or encounters a normal load failure.

If you are aware of specific flows or other areas that may be affected by this change, I would be very interested in investigating them and adding targeted tests. I am fully open to revising the approach if those tests reveal regressions or additional trade-offs that should be addressed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Community Contribution A label for all community Contributions PR metadata: Label to tag PRs, to facilitate with triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BAML parser resolves assemblies ignoring AssemblyLoadContext

3 participants