Closed Varorbc closed 4 years ago
@Varorbc does it cause any problems? What are the symptoms?
Could not load file or assembly 'System.ComponentModel.Annotations, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
my test demo https://github.com/Varorbc/Test
@karelz
a library "X" targets System.ComponentModel.Annotations nuget but only has netstandard2.0
as a framework. to it has a ref to the version from System.ComponentModel.Annotations.dll from the netstandard part of the package. then a net472 application tries to use both System.ComponentModel.Annotations and "X" nugets. u now have a binding conflict.
Not to mention if you are trying to debug something in production and there are all kinds of version mistmacthes between nugets and what is in prod, it make it very difficult to rull out some kind of deployment/build pipeline issue
the v 4.5 System.ComponentModel.Annotations nuget
file versions
assembly versions
I'm seeing similar issues using System.ComponentModel.Annotations package version 4.6.0-preview.18604.2.
cc @divega @ajcvickers
@ericstj Was an assumption supporting these lines broken in the past year?
<!-- Must match version supported by frameworks which support 4.2.* inbox.
Can be removed when API is added and this assembly is versioned to 4.3.* -->
<AssemblyVersion Condition="'$(TargetsNetFx)' != 'true'">4.2.0.0</AssemblyVersion>
<IsPartialFacadeAssembly Condition="'$(TargetsNetFx)' == 'true'">true</IsPartialFacadeAssembly>
.NET Framework test project redirects versions 0.0.0.0-4.2.0.0 to 4.2.0.0
That's the problem. It sounds like the .NETFramework project hasn't referenced the package and is instead picking up the .netstandard reference. If you examine the assembly version of the .NETFramework reference assembly in the package you will see it has 4.2.2.0. /cc @joperezr
You should either reference the package in the NETFramework test project, or enable PackageReference so that transitive dependencies flow to the test project.
note if u crack open some of those assemblies they are purely type forwarding. the weird thing is they are often typeforwarding to types in an assembly with a diff assembly version.
eg 4.4.1\lib\net461\System.ComponentModel.Annotations.dll
(assembly version 4.2) typeforwards to System.ComponentModel.DataAnnotations, Version=4.0.0.0
...or enable PackageReference...
We’re using PackageReference. I’ll dig a bit more...
yeah in my repros of this issue i was also using PackageReference
@SimonCropp All the type forwarding and mismatched versions are normal. There’s a lot of .NET history surrounding these tangled assemblies. Luckily when it’s all working correctly, most people can ignore the ugly details. 😆
@bricelam yeah i figured we were dealing some long history of technical debt here :)
cc @ryanbrandenburg (Who is seeing the same issue on another codebase)
See also https://github.com/aspnet/EntityFrameworkCore/issues/13268
I have been trying for months to get answers on this. The response keeps being that it's going to be documented how to make it work. But we haven't seen any documentation yet, and both myself and customers have been tearing their hair out trying to make it work.
@ericstj any thoughts here?
Got to the bottom of our issue: We were using the the Microsoft.NETFramework.ReferenceAssemblies package at build time then our tests compiled code via Roslyn but didn't reference the assemblies in Microsoft.NETFramework.ReferenceAssemblies.
@danmosemsft the problems here as @ericstj already pointed out are due to using packages.config instead of PackageReference. All of the instances that I've investigated around this issue are caused by transitive dependencies not flowing because of the use of packages.config. In order to fix this issue, users need to either manually add a reference to System.ComponentModel.Annotations package to their application, or they need to switch their project to use PackageReference instead which would flow the transitive dependencies.
My bad, I somehow missed that comment. If there is no action for us, we can close this right?
@joperezr @danmosemsft I would like to point out that I tried changing everything to package references and so did the customer. It still failed. So at least in my experience telling people to do this is not tha answer.
isnt this repro already using packagrereferences https://github.com/dotnet/corefx/issues/33643#issuecomment-441834688 ?
@SimonCropp I just tried that project locally with the latest VS, and I see that: 1) System.ComponentModel.Annotations.dll (version 4.2.1.0) is copied to the output folder, and 2) An app.config file binding redirect is generated successfully with the following contents:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.ComponentModel.Annotations" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.1.0" newVersion="4.2.1.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
That binding redirect is causing the app to work just fine at runtime, I get the following output:
@joperezr Binding redirection is certainly possible, but fixing the assembly version is the best approach
Assembly version isn't wrong. Your NServiceBus.DataAnnotations dependency targets netstandard2.0 for which the assembly version of System.ComponentModel.Annotations is 4.2.0.0. That said, you are running on .NET Framework, for which this assembly has been patched in the package, and since it is patched, it has a new assembly version: 4.2.1.0. Because of this, NServiceBus.DataAnnotations will look for the 4.2.0 version of the assembly, but will get 4.2.1 instead. In short, this is all caused because you are using an assembly that was targeting .NET Standard, and running on .NET Framework, which is totally supported, but requires assembly redirection like this in some cases.
I would also like to point out that I and the customer also tried adding binding redirects everywhere possible and still could not make this work.
Oh I see I did get a repro with the NServiceBus test, so the Test2 project. That happens because by default we don't generate dll config files so there is no way to set the binding redirect in that case. In order to force generate the dll config with the binding redirect, just add <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
property to that project and try to build and launch it again. This time, everything should work normally.
@joperezr Yep, tried that too. Didn't work for me.
The only reason why that wouldn't work would be if the NServiceBus host doesn't honor the dll config when starting up an AppDomain. If you launch(and enable) the fuslogvw utility you should be able to see when the error happens, to see if the host looked at the dll config or not.
@joperezr I was trying to make the repro from work https://github.com/aspnet/EntityFrameworkCore/issues/13268. I don't think NServiceBus was involved. I and the customer likely did something wrong.
If there is clear guidance somewhere on what should work, I'll point people to that and let it be. However, everything that has been mentioned here so far as already been suggested before and found not to work. That either means we're doing it wrong, or the guidance is wrong.
What I'm really looking for at this point is a clear place to point people for the guidance, and a clear place they can report issues when the guidance doesn't work.
IMO no binding redirect should be needed when referencing a single version of one package.
Another similar case reported here: https://github.com/aspnet/EntityFrameworkCore/issues/14368
did just a little extension on my data model. adding the migration resulted in a wired problem with needed to configure the foreign key as nullable (see a former post on that problem) and now not being allowed to have the key nullable.
So I did a remove-migration -Context blahContext AND NOW GUESS WHAT:
System.IO.FileLoadException: Die Datei oder Assembly "System.ComponentModel.Annotations, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"...
etc..
So now I need to undo the migration by hand?
is there an solution for this issue?
@ravenboilinux if you have a minimal repro of the problem, we can take a look at it and see if one of the above solutions fix the issue in your case.
We have tried manually adding System.ComponentModel.Annotations package and switching to PackageRegerence both did not work to solve the issue
That repo is not minimal unfortunately (only the code is already about 1.3 gb), IIRC it requires specific SDKs to be present on the machine to be even able to start to build.
this is the bare repo that is needed to complete the test to throw the error.
here is the Exception that I get
Exception:
System.TypeLoadException: Could not load type 'System.ComponentModel.DataAnnotations.Schema.InversePropertyAttribute' from assembly 'System.ComponentModel.Annotations, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.CoreConventionSetBuilder.CreateConventionSet()
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateConventionSet(IConventionSetBuilder conventionSetBuilder)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator)
at System.Lazy1.CreateValue() at System.Lazy
1.LazyInitValue()
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.1.get_EntityType() at Microsoft.EntityFrameworkCore.Internal.InternalDbSet
1.get_EntityQueryable()
at Microsoft.EntityFrameworkCore.Internal.InternalDbSet1.System.Linq.IQueryable.get_Provider() at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.Include[TEntity,TProperty](IQueryable
1 source, Expression1 navigationPropertyPath) at MGFConfiguration.MGFConfigurationProvider.Load() in E:\Code\IS\InnerSanctum\Servers\src\Config\MGFConfiguration\MGFConfigurationProvider.cs:line 30 at Microsoft.Extensions.Configuration.ConfigurationRoot..ctor(IList
1 providers)
at Microsoft.Extensions.Configuration.ConfigurationBuilder.Build()
at MGF_Photon.PhotonApplication.Setup() in E:\Code\IS\InnerSanctum\Servers\src\MGF.Photon\PhotonApplication.cs:line 114
at Photon.SocketServer.ApplicationBase.PhotonHostRuntimeInterfaces.IPhotonControl.OnPhotonRunning()
at PhotonHostRuntime.PhotonDomainManager.PhotonPlainAppDomainBehavior.PhotonRunning()
at PhotonHostRuntime.PhotonDomainManager.PhotonRunning()
One thing I was looking within the System.ComponentModel.Annotations.dll using dotpeek, and I only see two class FxResources.System.ComponentModel.Annotations.SR, and System.SR, two Resource files, and two assembly ref(mscorlib, and,System.ComponentModel.DataAnnotations) but nothing else.
I just tried your repro and it works fine for me:
One thing I was looking within the System.ComponentModel.Annotations.dll using dotpeek, and I only see two class FxResources.System.ComponentModel.Annotations.SR, and System.SR, two Resource files, and two assembly ref(mscorlib, and,System.ComponentModel.DataAnnotations) but nothing else.
Correct, the reason why you see that is because System.ComponentModel.Annotations.dll in .NET Framework is a facade that just type forwards to System.ComponentModel.DataAnnotations. That means that if you check with dotpeek, you should be able to see this:
Which means that when this type is trying to be loaded from this assembly, it will be instead looked for in your System.ComponentModel.DataAnnotations.dll installed on your GAC, which should have the type since .NET Framework 4.5+. My only suggestion here would be to make sure that your .NET Framework installation is correct, and that you do make sure that this type exists correctly in your GAC. One other thing you could try to diagnose this further, would be to use fuslogvw to log the bind to disk that is failing, so that we can figure out why it is not finding the type from the GAC.
Sorry after I posted that comment I saw the TypeForwardedToAttribute in the assembly properties, something that I am not use to. My .NET frameworks (from 3.5 to current version that vs allows) are all installed by the visual studio installer. The assembly that is has the type is in the GAC. How do you use fuslogvw?
Any thoughts on this https://github.com/dotnet/corefx/issues/33643#issuecomment-452451857 ?
@SimonCropp why do you think that? Are you sure it is truth in practice?
binding redirects are to resolve version conflicts. if u only ref one version, with no diamond dependencies, there should be no conflicts and no binding redirects.
@SimonCropp while compelling idea, unfortunately the reality is more complex than that :(. You can have collisions between references. You can have collisions with Framework built-in versions. You can have collisions with assemblies in GAC, or publisher policies. Binding redirects are mechanism to deal with all these problems (or cause more). Addressing diamond dependencies is just one of the main scenarios. Rather than jumping to conclusions how we think it should work, let's try to understand what is broken and why it is broken and let's deal with that.
How do you use fuslogvw?
Here is a good link that should get you started: https://docs.microsoft.com/en-us/dotnet/framework/tools/fuslogvw-exe-assembly-binding-log-viewer . Basically fuslogvw is a very useful tool whenever you get errors with TypeLoadExceptions, AssemblyLoadExceptions, FileNotFoundExceptions and MemberNotFoundExceptions. It helps by telling you exactly which assemblies each process is loading and also will tell you where did it look for a certain assembly in case it wasn't found.
@joperezr I repaired my visual studio and the the .net frameworks and still get the error. I tried the fuslogvw(which is a useful tool that i did not know about( I found the problem the runtime is looking within C:\ProgramData\Red Gate.NET Reflector\DevPath for dlls, and it finds the System.ComponentModel.Annotation.dll however that version of the dll does not have the TypeForwardedToAttribute to the System.ComponentModel.DataAnnotations.dll. How do you reset or remove the DEVOVERRIDE so that it looks into the GAC
If you are seeing that, it is most likely that you have DEVPATH
environment variable defined. Here is some info about that: http://ntcoder.com/bab/2014/08/28/how-to-locate-net-assemblies-by-using-devpath/
Unsetting that variable might do the trick.
BTW, fuslogvw is a very powerful tool but it is dangerous if you don't remember to disable the logs after you are done using it. If you forget to do it, then you will eventually run into issues where your whole disk will be filled with binding logs.
I have the same problem, any solution?
It is really bad thing. almost 20 years ago, when we said Goodbye --COM dll hell and embraced brand dotnet... but right now what happened? the same thing.. maybe worse. wish MS reconsiders the way for releasing production component(dlls).
Detailed repro steps so we can see the same problem
1.The target framework of my project is net472
3.the package depend on System.ComponentModel.Annotations
4.When my project restores the package(
System.ComponentModel.Annotations
), the net461 package is restored5.NServiceBus.DataAnnotations restores the package(
System.ComponentModel.Annotations
),the netstandard2.0 package is restored