Skip to content
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

System.Xaml FileNotFoundException when using XmlnsPrefix and .resx in a referenced assembly #804

Closed
koyote opened this issue Dec 11, 2019 · 20 comments
Labels
area-System.Reflection backlog-cleanup-candidate An inactive issue that has been marked for automated closure. no-recent-activity
Milestone

Comments

@koyote
Copy link

koyote commented Dec 11, 2019

Hi,

When a .Net Core project references a .Net Framework project which has "XmlnsPrefix" set in AssemblyInfo AND we call code that accesses a resource in a .resx file, we get the following exception:

System.IO.FileNotFoundException: Could not load file or assembly 'System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. The system cannot find the file specified.
File name: 'System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
at System.ModuleHandle.ResolveTypeHandleInternal(RuntimeModule module, Int32 typeToken, RuntimeTypeHandle[] typeInstantiationContext, RuntimeTypeHandle[] methodInstantiationContext)
at System.Reflection.RuntimeModule.ResolveType(Int32 metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
at System.Reflection.CustomAttribute.FilterCustomAttributeRecord(MetadataToken caCtorToken, MetadataImport& scope, RuntimeModule decoratedModule, MetadataToken decoratedToken, RuntimeType attributeFilterType, Boolean mustBeInheritable, ListBuilder1& derivedAttributes, RuntimeType& attributeType, IRuntimeMethodInfo& ctor, Boolean& ctorHasParameters, Boolean& isVarArg) at System.Reflection.CustomAttribute.AddCustomAttributes(ListBuilder1& attributes, RuntimeModule decoratedModule, Int32 decoratedMetadataToken, RuntimeType attributeFilterType, Boolean mustBeInheritable, ListBuilder`1 derivedAttributes)
at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeModule decoratedModule, Int32 decoratedMetadataToken, Int32 pcaCount, RuntimeType attributeFilterType)
at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeAssembly assembly, RuntimeType caType)
at System.Reflection.RuntimeAssembly.GetCustomAttributes(Type attributeType, Boolean inherit)
at System.Attribute.GetCustomAttributes(Assembly element, Type attributeType, Boolean inherit)
at System.Attribute.GetCustomAttribute(Assembly element, Type attributeType, Boolean inherit)
at System.Reflection.CustomAttributeExtensions.GetCustomAttribute[T](Assembly element)
at System.Resources.ManifestBasedResourceGroveler.GetNeutralResourcesLanguage(Assembly a, UltimateResourceFallbackLocation& fallbackLocation)
at System.Resources.ResourceManager.CommonAssemblyInit()
at System.Resources.ResourceManager..ctor(String baseName, Assembly assembly)
at ClassLibrary1.Strings.get_ResourceManager() in Strings.Designer.cs:line 42
at ClassLibrary1.Strings.get_XXX() in Strings.Designer.cs:line 68

See attached Project:
ConsoleApp2.zip

@danmoseley danmoseley transferred this issue from dotnet/corefx Dec 12, 2019
@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added area-System.Reflection untriaged New issue has not been triaged by the area owner labels Dec 12, 2019
@danmoseley
Copy link
Member

@ericstj do you know where this should go?

@ericstj ericstj removed the untriaged New issue has not been triaged by the area owner label Dec 13, 2019
@ericstj
Copy link
Member

ericstj commented Dec 13, 2019

a .Net Core project references a .Net Framework project

We do our best to make .NETCore work with .NETFramework libraries when the types exist, but in the case of this sample the type used by the .NETFramework library (System.Xaml) doesn't exist in the base shared framework.

You can change your .NETCore console project use the WindowsDesktop sdk instead, this contains WPF and will be able to resolve System.Xaml. That's probably the best workaround if you're compiling for windows.

There's not a great way to avoid this since reflection needs to be able to load assemblies in order to reflect.

One could argue that Assembly.GetCustomAttribute(type) shouldn't throw for other attribute types which cannot be resolved, since the caller passed in a resolved runtime type. This is probably correct most of the time, but it could be wrong in the case the type that wasn't resolved was actually forwarding to the type you were looking for. Perhaps FilterCustomAttributeRecord could be improved to only throw when it cannot resolve a type and that type has the same name as the one your filtering on. Otherwise it can ignore the unresolved type since it cannot possibly match the one its looking for (since it has a different name). That makes this a make reflection more resilient bug, so keeping this tagged as reflection.

@ericstj ericstj added this to the 5.0 milestone Dec 13, 2019
@ericstj
Copy link
Member

ericstj commented Dec 13, 2019

/cc @steveharter

@maryamariyan maryamariyan added the untriaged New issue has not been triaged by the area owner label Feb 23, 2020
@steveharter
Copy link
Member

steveharter commented Mar 6, 2020

Per discussion with @GrabYourPitchforks the proposed work-around will not work in the general case because GetCustomAttributes(Type) will enumerate all attributes that are compatible with Type (checking base types). So just comparing the type name wouldn't work.

We could attempt to detect it the Type passed in is sealed, but then this becomes very specific.

A better work-around is to have System.Resources.ManifestBasedResourceGroveler use GetCustomAttributeData instead of GetCustomAttribute so no attribute is instantiated. So moving to System.Resources.

Is this issue blocking any key scenarios?

@steveharter steveharter removed the untriaged New issue has not been triaged by the area owner label Mar 6, 2020
@GrabYourPitchforks
Copy link
Member

@buyaa-n @tarekgh We think a better workaround would be to change ManifestBasedResourceGroveler. See above.

@steveharter steveharter added the untriaged New issue has not been triaged by the area owner label Mar 6, 2020
@ericstj
Copy link
Member

ericstj commented Mar 6, 2020

GetCustomAttributeData doesn't avoid load of the assembly which defines the custom attribute. We would need something that just reads the metadata and doesn't try to create Type objects (or activate types).

Unhandled exception. System.IO.FileNotFoundException: Could not load file or assembly 'System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. The system cannot find the file specified.
File name: 'System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
   at System.ModuleHandle.ResolveMethodHandleInternalCore(RuntimeModule module, Int32 methodToken, IntPtr[] typeInstantiationContext, Int32 typeInstCount, IntPtr[] methodInstantiationContext, Int32 methodInstCount)
   at System.ModuleHandle.ResolveMethodHandleInternal(RuntimeModule module, Int32 methodToken, RuntimeTypeHandle[] typeInstantiationContext, RuntimeTypeHandle[] methodInstantiationContext)
   at System.Reflection.CustomAttributeData..ctor(RuntimeModule scope, MetadataToken caCtorToken, ConstArray& blob)
   at System.Reflection.CustomAttributeData.GetCustomAttributes(RuntimeModule module, Int32 tkTarget)
   at System.Reflection.CustomAttributeData.GetCustomAttributesInternal(RuntimeAssembly target)
   at System.Reflection.RuntimeAssembly.GetCustomAttributesData()
   at custAttr.Program.GetCustomAttribute[T](Assembly assembly) in C:\Users\erics\source\repos\custAttr\custAttr\Program.cs:line 19
   at custAttr.Program.Main(String[] args) in C:\Users\erics\source\repos\custAttr\custAttr\Program.cs:line 14

custAttr.zip

@GrabYourPitchforks
Copy link
Member

At that point then it seems that addressing this in the reflection layer would be a non-trivial work item, and per Steve's earlier comment it wouldn't solve the issue more generally anyway. The workaround previously given by retargeting the assembly against WindowsDesktop seems like it'd work since it'd allow the runtime to discover System.Xaml, no?

@ericstj
Copy link
Member

ericstj commented Mar 6, 2020

Retargeting the application to WindowsDesktop would work, but that's not always possible.

I think the problem in general is that Reflection isn't very resilient to dangling references. It's pretty unfortunate that this surfaces in the cases where the user isn't calling reflection but the framework itself needs to do so as part of its basic functionality.

@GrabYourPitchforks
Copy link
Member

GrabYourPitchforks commented Mar 6, 2020

Would xcopying System.Xaml alongside their app work? You know heaps more about assembly loading nits than I do. :)

(Edit: This still assumes changing the app, not the library.)

@steveharter
Copy link
Member

Would xcopying System.Xaml alongside their app work? You know heaps more about assembly loading nits than I do. :)

You can't just copy (.NET Core requires entry in .deps.json), but you can modify the project to add an assembly reference to System.Xaml and make sure it exists alongside their app.

I think the problem in general is that Reflection isn't very resilient to dangling references

Is there an argument to be made that the current behavior is desired -- i.e. that for consistency attributes should never be "skipped" because the attribute's Type can't be loaded?

Also what scenario this is current blocking, if any (WPF interop with existing assemblies?). The work-around of copying the assembly may be fine for this particular case.

If we think this scenario is important for 5.0 I will investigate potential fix.

@ericstj
Copy link
Member

ericstj commented Mar 9, 2020

The scenario blocked would be someone building a shared class-library that needs to work in both WPF apps and console apps. I suspect this is @koyote's scenario, but I could be wrong. The specific attribute is https://docs.microsoft.com/en-us/dotnet/api/system.windows.markup.xmlnsprefixattribute?view=netframework-4.8

The workaround would be move this attribute (and presumably any others like https://docs.microsoft.com/en-us/dotnet/api/system.windows.markup.xmlnsdefinitionattribute?view=netframework-4.8) into an assembly which is only used when WPF is available.

I don't think this scenario alone warrants prioritizing new API for 5.0, but I do think it's a ref count against reflection APIs that are resilient to missing types/assemblies.

@steveharter
Copy link
Member

The workaround would be move this attribute (and presumably any others like https://docs.microsoft.com/en-us/dotnet/api/system.windows.markup.xmlnsdefinitionattribute?view=netframework-4.8) into an assembly which is only used when WPF is available.

Along with a [TypeForwardedTo] in System.Xaml I assume.

Should we create a new WPF issue then? (keep this issue to track resilient missing types).

@ericstj
Copy link
Member

ericstj commented Mar 10, 2020

Right. This would need to happen in runtime repo, not WPF. WPF would need to react to it afterwards. We would need to add a System.Xaml shim to the set that we build in runtime, like WindowsBase. I’m not inclined to do this based on a single report for the reasons I called out above as well as the cost & complexity it adds.

If we hear from more folks that need this to work and can’t depend on WindowsDesktop we can reconsider. @vatsan-madhavan

@vatsan-madhavan
Copy link
Member

Agree that a System.Xaml shim is not yet warranted. A separate System.Xaml package (dotnet/wpf#46) might be of help to those who can't retarget to windowsdesktop entirely.

@vatsan-madhavan
Copy link
Member

/cc @dotnet/wpf-developers

@koyote
Copy link
Author

koyote commented Mar 10, 2020

The scenario blocked would be someone building a shared class-library that needs to work in both WPF apps and console apps. I suspect this is @koyote's scenario, but I could be wrong. The specific attribute is https://docs.microsoft.com/en-us/dotnet/api/system.windows.markup.xmlnsprefixattribute?view=netframework-4.8

That is correct.
The dotnet core application was extracted from a larger .net framework/WPF application and both share some assemblies including the .net framework assembly with the issue above.

You can't just copy (.NET Core requires entry in .deps.json), but you can modify the project to add an assembly reference to System.Xaml and make sure it exists alongside their app.

So if I understand correctly, the workaround is for the referenced project (or the dotnet core project?) to add a reference to System.Xaml?

@steveharter
Copy link
Member

Based on discussion, moving to Future. If there are additional scenarios or hits on this, please re-open.

@steveharter steveharter removed this from the 5.0 milestone Mar 10, 2020
@steveharter steveharter added this to the Future milestone Mar 10, 2020
@steveharter steveharter removed the untriaged New issue has not been triaged by the area owner label Mar 10, 2020
@ericstj
Copy link
Member

ericstj commented Mar 10, 2020

@koyote here's the workarounds in order of precedence:

  1. Make your application target WindowsDesktop.
  2. Either remove, or factor your usage of System.Xaml attributes into a separate assembly.
  3. Add a System.Xaml to your app that defines these attributes.

MichalStrehovsky added a commit to MichalStrehovsky/runtime that referenced this issue Mar 25, 2021
StelemRef with a negative index would result in a fun heap corruption. The `IList_Generic_ItemSet_NegativeIndex_ThrowsException` test in System.Runtime.Tests was leaving us with a corrupted heap.
radical pushed a commit to radical/runtime that referenced this issue Jul 7, 2022
@steveharter steveharter added the backlog-cleanup-candidate An inactive issue that has been marked for automated closure. label Oct 13, 2022
@ghost
Copy link

ghost commented Oct 13, 2022

Due to lack of recent activity, this issue has been marked as a candidate for backlog cleanup. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will undo this process.

This process is part of our issue cleanup automation.

@ghost ghost added the no-recent-activity label Oct 13, 2022
@ghost
Copy link

ghost commented Oct 28, 2022

This issue will now be closed since it had been marked no-recent-activity but received no further activity in the past 14 days. It is still possible to reopen or comment on the issue, but please note that the issue will be locked if it remains inactive for another 30 days.

@ghost ghost closed this as completed Oct 28, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Nov 27, 2022
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Reflection backlog-cleanup-candidate An inactive issue that has been marked for automated closure. no-recent-activity
Projects
No open projects
Development

No branches or pull requests

8 participants