-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
LoadFrom Resource Fallback search fails to search next to current executing assembly #11463
Comments
This issue is about Did you try this on the .NET Framework? I assume it works there, but would be nice to double check just to make sure. I think it makes sense to try to fix this. |
I think
Looking at the code it doesn't look like it is functionally complete. However the Satellite assembly fallback logic should look next to the current executing assembly. That is not happening either. It shouldn't really matter that it came from LoadFrom, LoadAssemblyFromPath…. |
The document is about .NET Framework. On .NET Core Whether satellite loading should proactively probe "next to" to the referencing assembly... I'm not so sure about that. We do this for native libraries, but those have rather complex probing logic. Satellite assemblies today don't have much of a probing logic, they simply search the resource probing paths as specified by the host. Basically the question is if this should be an inherent feature of the runtime, or just a feature of |
If you look at the docs for the .NET Framework resource fallback algorithm, https://github.com/dotnet/docs/blob/77cd71d17d37696f73ba5279a798f36def3cdb24/docs/framework/resources/packaging-and-deploying-resources-in-desktop-apps.md Then filter it for what is expected in .NET Core, you get something like my PR dotnet/docs#8920 From draft PR...
The draft is slightly inaccurate as it is missing the AppDomain.AssemblyResolve event. Ultimately this is a more stable algorithm for finding satellites. It is independent of how its base asembly was loaded so it should just work. |
OK I looked closely at the
Seems reasonable to fix I also looked at revising the general fallback algorithm. It looks much more error prone. Seems fixing |
Unless we have a strong appcompat reason, I would not necessarily look to adjust LoadFrom. I do think we should ensure this code pattern works well when using AssemblyLoadContext.LoadFrom*. |
@jeffschwMSFT I believe we are under .NET Standard 2.0 compatibility obligation to make this statement true
Since it is not true for culture dependent assemblies, I think we should fix it. |
I believe this is is true, just not for resource assemblies. What is the corresponding behavior on .NET Framework? |
I'll run the code in the morning. I suspect it is intend to just work. |
I have no doubt that with all the probing we do no desktop it may. In my mind, it is fine to fix this code path, but for a concrete reason in mind. The more important case is that we ensure that the recommended path (AssemblyLoadContext) has an even better experience. |
It is possible |
I fear that may be out of reach, as Assembly.LoadFrom has a lot of legacy behaviors that have been honed and crafted with many changes to match expectations of existing apps. This is part of my rationale to go after AssemblyLoadContext behavior and leave this one alone until it is necessary to match given an apps expectation. |
I think that for That leaves the I think that would be the best option, assuming we should do something here at all. Indirectly this would also fix Two concerns:
|
I have spent more time looking at this. When loading satellites the algorithm currently is:
The algorithm should be:
The |
The native code which is implementing this algorithm seems overly complicated. A snapshot of the back trace on Linux is here
To implement To load the satellite for mscorlib, To solve this it seems we will need to modify/extend |
We do not need these internal interfaces defined in IDL. Feel free to delete/simplify them. We never really needed them. It is just that folks working on the assembly loader in the past liked to use them. |
I've already looked at the possibility to pass the "parent" assembly throughout the binder, and the outcome was what you state above (need to modify the interface, or get rid of it). |
Question about step # 4 above. Do you know if calling the default context will also trigger extension points on the default context (namely the |
AFAIK it does not right now. It triggers the tpa binder. I can instrument it if you need 100% certainty. |
I think I agree with your new list of operations. dotnet/coreclr#4 (fallback to default) should remain. What that will effectively do is trigger a search in the resource paths (as specified by the host). While I understand that for well behaved apps this should not actually resolve anything, what this will for example do is resolve satellites of app assemblies which are intentionally loaded into separate context (but are otherwise normal parts of the app, for example Regarding where the satellite is loaded - it really doesn't matter. Load context of an assembly really only matters for isolation and when that assembly triggers another bind. Satellites will participate in isolation, but they are effectively inert with regard to triggering binds (as satellite can have no assembly refs and it has no code to trigger it programatically). For isolation, it really only matters for version collisions, in which case it's the same story as normal code assemblies, and thus having the same behavior (fallback to default in dotnet/coreclr#4) is preferrable. |
I am not sure about this. Consider the following:
We do not want the plugin to fallback to localized satellites in the app in this case. |
Based on personal bias and @jkotas comments I would prefer to remove (fallback to default) |
OK - that's a good point. We should find out if we're tracking breaking changes in .NET Core 3 (I think we should) and add this to the list. It is technically a breaking change, although it should be pretty rare. |
There is a request to make the culture directory search case-insensitive. I believe this is reasonable. |
When loading satellite assemblies, we should probe next to the parent assembly and load into the same AssemblyLoadContext as the parent assembly. Disable fallback probing for satellite assemblies. Add AssemblyLoadContext.Resolving handler to probe for satellite assemblies next to parent Fixes #20979
When loading satellite assemblies, we should probe next to the parent assembly and load into the same AssemblyLoadContext as the parent assembly. Disable fallback probing for satellite assemblies. Add AssemblyLoadContext.Resolving handler to probe for satellite assemblies next to parent Fixes #20979
When loading satellite assemblies, we should probe next to the parent assembly and load into the same AssemblyLoadContext as the parent assembly. Disable fallback probing for satellite assemblies. Add AssemblyLoadContext.Resolving handler to probe for satellite assemblies next to parent Fixes #20979
* Fix Satellite Assembly loading When loading satellite assemblies, we should probe next to the parent assembly and load into the same AssemblyLoadContext as the parent assembly. Disable fallback probing for satellite assemblies. Add AssemblyLoadContext.Resolving handler to probe for satellite assemblies next to parent Fixes #20979 * Call ResolveSatelliteAssembly from native Only call ResolveSatelliteAssembly from native when resolving a satellite assembly * PR Feedback Minimize string creation Remove unnecessary if null checks Eliminate corner cases by only allowing one case insensitive matching directory. * ResolveSatelliteAssembly should ... ResolveSatelliteAssembly should always be called on the ALC which loaded parentAssembly Simplify code. Add Debug.Assert * Remove case insensitive culture search * PR Feedback * Fix parentAssembly logic * Fixes from initial testing * Add probe for lower case culture name * PR feedback
Satellite assembly resolution does not work in a very basic console app built against .NET Core 3.0.0. I created the console application in VS2019 and added welcome.resx and welcome.de.resx. Both have a string resource called Greeting. When the project builds, it creates a subfolder called de containing MyTest.resources.dll. The main method does this:
When I add an AssemblyResolve event handler and manually specify the desired assembly (workaround listed in dotnet/core#2041), it works. However, I believe the work-around should no longer be necessary based on the comments in this issue. |
@ericjohannsen thanks for reporting the issue, we'll try to take a look and get back to you. |
@ericjohannsen by the way, are you running on Windows or Mac? I guess you are running Windows using VS2019 as you mentioned. |
@tarekgh Windows 10. VS2019 is the latest build. |
@ericjohannsen I have tried the same code and I am seeing everything is working just fine. I have attached here the project I used. This project created with VS2019 and targetting .NET Core 3.0. The code is doing: Console.WriteLine("Hello World!");
ResourceManager r = new ResourceManager("ResourceSatellite.welcome", Assembly.GetExecutingAssembly());
string greeting = r.GetString("String1");
Console.WriteLine(greeting);
greeting = r.GetString("String1", new System.Globalization.CultureInfo("de"));
Console.WriteLine(greeting);
Console.WriteLine("Done!"); And that is producing the following output
|
@tarekgh Thanks for the prompt reply. Your project works as expected on my system, but mine still does not. I'm combing through for differences. |
@tarekgh OK here's the difference: My project also had a manifest file (the default one you get when using Add/New Item). When I deleted the manifest from the project, it ran as expected. Strangely, though, when I added a manifest file back in, it continued to run as expected. Since it's a small test project, I don't have the old project state in source control, so I can't get back to the broken state. I appreciate your efforts and will post a concrete repro if I come across the situation again. |
Thanks @ericjohannsen for the update. Let's know if you run into the problem again. And please try to add the needed information to https://stackoverflow.com/q/58193794/141172 to help other users. |
For .NET Core the primary location to look for satellite resource assemblies should be in the culture directory next to the current executing assembly.
This directory is not currently being searched unless it happens to be already on the search path
@jkotas @jeffschwMSFT @tarekgh @vitek-karas FYI
See dotnet/core#2041
The text was updated successfully, but these errors were encountered: