-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Xaml parser doesn't work with AssemblyLoadContext #1700
Comments
@vitek-karas Reading through the docs etc., I'm trying to figured out the best way to enumerate loaded assemblies in an AssemblyLoadContext. We don't want to load an Assembly if it's not already loaded for other reasons - we just want to find out if an Assembly is already loaded, and if it is, then work with it. |
Whats wrong with AssemblyLoadContext.Assemblies ? doc says "Returns a collection of the Assembly instances loaded in the AssemblyLoadContext."
The key is probably to use CurrentContextualReflectionContext or provide some other way the caller can communicate which AssemblyLoadContext to use, otherwise you would just replicate the current behavior. |
I absolutely agree with @weltkante here - the key part of the fix should be to use the right As for enumerating assemblies, I'm really wondering why do you need to do that. As mentioned above the primary goal is to load the assembly through the right ALC. Once you have the right ALC you can just call That said I noticed that the current code in WPF tries to implement somewhat custom "assembly name" -> "assembly" resolution - for example it sometimes intentionally ignores versions and so on. If we need to keep that behavior, then you would probably need to rely on assembly enumeration, in which case the Personally I'm curious why does WPF need to implement all of this custom assembly loading logic - why not use simple Future looking: We recommend to not rely on the contextual reflection APIs, exactly because of the problem described in this issue. Almost all reflection APIs already have overloads which have some way to explicitly specify which ALC to use. For example |
Probably because it requires a fully qualified name including version and public key, and you don't have to specify fully qualified names in XAML. In fact most users probably don't use them (I certainly never wrote nor have seen a fully qualified assembly name in XAML ever). So removing that capability will be a breaking change to existing XAML. |
In fact in .NET Core Thanks for the link describing how WPF behaves. Roughly speaking |
This is probably historical, on Desktop Framework For the sake of compatibility I doubt they can move away from the established loading behavior, in particular how versions are treated in presence of loaded assemblies could differ. If this is really a major performance problem in .NET Core they could consider switching to |
I absolutely agree that solving the ALC problem should come first. |
I am currently struggling with what I assume is this issue. I have a .NET 5.0 WPF plugin architecture and encounter errors if I have multiple plugins in different assembly load contexts. It seems to come down to issues with the XAML parser resolving URIs (I get odd control behavior, and "The component 'XXX' does not have a resource identified by the URI" errors. Given that this is still an open issue, is there any known way to work around the problem? Thanks. |
Have you solved your problem? |
No, I have not. |
It seems as if there are some serious limitations to building a plug-in architecture with WPF/Core. As described above, it all appears to stem from the XAML parser's ignorance of assembly contexts. Here is a summary of our findings and resolutions.
In order to come up with a workable solution, we did the following:
|
I finally found a source where my issue has been described. Thanks to dt200r and vitek-karas, I have now a clue what is going wrong. It make sense. I have an assembly with a page and load the assembly two times (at start up and later in my code for reflection). Thanks for sharing all your thoughts on that topic. |
Curious why this is classed as a enhancement request. It looks like a regression between .NET Framework and .NET core which suggest it should be classified as a bug. |
This issue should get more attention, since it makes the plugin architecture in .NET (Core) unreliable when using WPF for providing UIs and though should be treated as bug rather than as an enhancement. |
For our case it helps to set different versions of assemblies. For example we had different assemblies Then I tried to increase version of first But then I found that during XAML compilation it stores version of assembly for references. For for reference Of course it will not solve original problem but perhaps it can help in some cases. |
this issue is critical to develop addins as it allows developers to create isolated dependency for the addins to avoid conflicts to other addins and this issue since 2019 . is there any plan when it gets fixed ? |
Trying to load XAML into non-default
AssemblyLoadContext
can lead to very confusing errors. The underlying problem is that XAML parser is not aware of assembly load contexts. The parser itself typically runs in theDefault
load context, but it may be triggered to load XAML into a custom (secondary) load context. In that case all assembly resolution should happen via the secondary load context.In order to make this easier .NET Core 3.0 introduced the "contextual reflection" concept, which can switch all reflection based APIs to use the secondary load context. More details about contextual reflection can be found in AssemblyLoadContext.ContextualReflection.md.
That fixes all cases where the XAML parser uses reflection APIs like
Assembly.GetType
and similar. Unfortunately the XAML parser implements its own assembly resolution logic in some cases. This logic was copied from the .NET Framework version of WPF and it still relies AppDomains, GAC and so on - it is not aware ofAssemblyLoadContext
. This logic can break the correct behavior: Among other things it walks all assemblies loaded into the current AppDomain (so all assemblies in the process, as .NET Core has only one AppDomain) and using custom logic resolves assembly against that list. If there are two assemblies of the same (or similar) names in that list, it will basically randomly pick the first one it finds. The code which does that is here:wpf/src/Microsoft.DotNet.Wpf/src/Shared/MS/Internal/SafeSecurityHelper.cs
Line 133 in ac9d1b7
Assembly load contexts are typically used to implement plugin architecture. To provide good levels of isolation for each plugin, every plugin is loaded into its own load context. This can very easily lead to cases where each plugin has its own version of a certain dependency. But the above mentioned code ignores the isolation of load contexts, and will resolve assembly globally - leading to cases where the plugins will get the wrong version of dependency used.
A sample repro app is here: https://github.com/vitek-karas/WPFPluginLoadProblem
This app shows the problem with a typical plugin architecture (host app loading two plugins, each using XAML parser to load some XAML).
Originally this problem was found trying to implement tests on WPF, using ALC to provide isolation of WPF itself. The repro of that case is here: https://github.com/nick-beer/ALC-XAML-LOAD-BUG
This repro boils down to the same underlying problem.
/cc @nick-beer
The text was updated successfully, but these errors were encountered: