dotnet / sdk

Core functionality needed to create .NET Core projects, that is shared between Visual Studio and CLI
https://dot.net/core
MIT License
2.71k stars 1.07k forks source link

CopyLocalLockFileAssemblies changes the behavior of AutoGenerateBindingRedirects for good #35093

Open qlikTERror opened 1 year ago

qlikTERror commented 1 year ago

In our test projects when not using flag CopyLocalLockFileAssemblies at true the task ResolveAssemblyReference produces a different list of SuggestedBindingRedirects that turns into a different project app.config file. And you need to set it to true on each project direct or transient dependency.

In this test project examples, the test project is built under net4.8.

Example of SuggestedBindingRedirects with CopyLocalLockFileAssemblies at false:

SuggestedBindingRedirects
    System.Runtime.CompilerServices.Unsafe, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
        MaxVersion = 5.0.0.0

Example of SuggestedBindingRedirects with CopyLocalLockFileAssemblies at true:

SuggestedBindingRedirects
    System.Buffers, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
        MaxVersion = 4.0.3.0
    System.Memory, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
        MaxVersion = 4.0.1.2
    System.Runtime.CompilerServices.Unsafe, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
        MaxVersion = 5.0.0.0
    System.Text.Encoding.CodePages, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
        MaxVersion = 5.0.0.0
    System.Security.Principal.Windows, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
        MaxVersion = 5.0.0.0
    System.Security.Permissions, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
        MaxVersion = 5.0.0.0

These depends on the fact that with CopyLocalLockFileAssemblies at false on each projects, the final test project when it runs the task ResolveAssemblyReference and tries to resolve the references obtains many of them in this status:

Dependency "Autofac, Version=6.5.0.0, Culture=neutral, PublicKeyToken=17863af14b0044da".
    Could not resolve this reference. Could not locate the assembly "Autofac, Version = 6.5.0.0, Culture=neutral, PublicKeyToken=17863af14b0044da". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors.
    For SearchPath "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Printing\bin\Debug\netstandard2.0".
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Printing\bin\Debug\netstandard2.0\Autofac.winmd", but it didn't exist.
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Printing\bin\Debug\netstandard2.0\Autofac.dll", but it didn't exist.
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Printing\bin\Debug\netstandard2.0\Autofac.exe", but it didn't exist.
    For SearchPath "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Reports.Tree\bin\Debug\netstandard2.0".
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Reports.Tree\bin\Debug\netstandard2.0\Autofac.winmd", but it didn't exist.
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Reports.Tree\bin\Debug\netstandard2.0\Autofac.dll", but it didn't exist.
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Reports.Tree\bin\Debug\netstandard2.0\Autofac.exe", but it didn't exist.
    For SearchPath "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik\Qlk.Reporting.Excel\bin\Debug\netstandard2.0".
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik\Qlk.Reporting.Excel\bin\Debug\netstandard2.0\Autofac.winmd", but it didn't exist.
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik\Qlk.Reporting.Excel\bin\Debug\netstandard2.0\Autofac.dll", but it didn't exist.
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik\Qlk.Reporting.Excel\bin\Debug\netstandard2.0\Autofac.exe", but it didn't exist.
    For SearchPath "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Printing\bin\Debug\netstandard2.0".
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Printing\bin\Debug\netstandard2.0\Autofac.winmd", but it didn't exist.
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Printing\bin\Debug\netstandard2.0\Autofac.dll", but it didn't exist.
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Printing\bin\Debug\netstandard2.0\Autofac.exe", but it didn't exist.
    For SearchPath "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik\Qlk.Reporting.Excel\bin\Debug\netstandard2.0".
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik\Qlk.Reporting.Excel\bin\Debug\netstandard2.0\Autofac.winmd", but it didn't exist.
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik\Qlk.Reporting.Excel\bin\Debug\netstandard2.0\Autofac.dll", but it didn't exist.
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik\Qlk.Reporting.Excel\bin\Debug\netstandard2.0\Autofac.exe", but it didn't exist.
    Required by "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Printing\bin\Debug\netstandard2.0\Qlik.Printing.dll".
    Required by "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Reporting.Engine.Messages\bin\Debug\netstandard2.0\Qlik.Reporting.Engine.Messages.dll".
    Required by "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Reports.Tree\bin\Debug\netstandard2.0\Qlik.Reporting.Reports.Tree.dll".
    Required by "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik\Qlk.Reporting.Excel\bin\Debug\netstandard2.0\Qlik.Reporting.Excel.dll".

When this happens, due to the fact that the task could not find the assembly it is not able to read its dependencies and act according to it.

And there is another problem related to transient dependencies of project dependency. For example in the previous good list of SuggestedBindingRedirects, the assembly System.Memory has been resolved to version 4.0.1.2 just because it has been added as a direct dependency of the test project. If I will remove it and let the test project build with the CopyLocalLockFileAssemblies at true (for each project) I will obtain this:

Dependency "System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51".
    Could not resolve this reference. Could not locate the assembly "System.Memory, Version = 4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors.
    For SearchPath "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Reporting.Addin\bin\Debug\netstandard2.0".
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Reporting.Addin\bin\Debug\netstandard2.0\System.Memory.winmd", but it didn't exist.
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Reporting.Addin\bin\Debug\netstandard2.0\System.Memory.dll",
            but its name "System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51"
            didn't match the expected name "System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51".
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Reporting.Addin\bin\Debug\netstandard2.0\System.Memory.exe", but it didn't exist.
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Reporting.Addin\bin\Debug\netstandard2.0\System.Memory.winmd", but it didn't exist.
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Reporting.Addin\bin\Debug\netstandard2.0\System.Memory.dll",
            but its name "System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51"
            didn't match the expected name "System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51".
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Reporting.Addin\bin\Debug\netstandard2.0\System.Memory.exe", but it didn't exist.
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Reporting.Addin\bin\Debug\netstandard2.0\System.Memory.winmd", but it didn't exist.
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Reporting.Addin\bin\Debug\netstandard2.0\System.Memory.dll",
            but its name "System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51"
            didn't match the expected name "System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51".
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Reporting.Addin\bin\Debug\netstandard2.0\System.Memory.exe", but it didn't exist.
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Reporting.Addin\bin\Debug\netstandard2.0\System.Memory.winmd", but it didn't exist.
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Reporting.Addin\bin\Debug\netstandard2.0\System.Memory.dll",
            but its name "System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51"
            didn't match the expected name "System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51".
        Considered "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Reporting.Addin\bin\Debug\netstandard2.0\System.Memory.exe", but it didn't exist.
    For SearchPath "{CandidateAssemblyFiles}".
        Considered "C:\Users\ter\.nuget\packages\grpc.core\2.46.6\build\net45\..\..\runtimes\win-x86\native\grpc_csharp_ext.x86.dll",
            but its name "grpc_csharp_ext.x86"
            didn't match the expected name "System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51".
        Considered "C:\Users\ter\.nuget\packages\grpc.core\2.46.6\build\net45\..\..\runtimes\win-x64\native\grpc_csharp_ext.x64.dll",
            but its name "grpc_csharp_ext.x64"
            didn't match the expected name "System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51".
        Considered "C:\Users\ter\.nuget\packages\nunit3testadapter\4.5.0\build\net462\NUnit3.TestAdapter.dll",
            but its name "NUnit3.TestAdapter"
            didn't match the expected name "System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51".
        Considered "C:\Users\ter\.nuget\packages\nunit3testadapter\4.5.0\build\net462\nunit.engine.dll",
            but its name "nunit.engine"
            didn't match the expected name "System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51".
        Considered "C:\Users\ter\.nuget\packages\nunit3testadapter\4.5.0\build\net462\nunit.engine.api.dll",
            but its name "nunit.engine.api"
            didn't match the expected name "System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51".
        Considered "C:\Users\ter\.nuget\packages\nunit3testadapter\4.5.0\build\net462\nunit.engine.core.dll",
            but its name "nunit.engine.core"
            didn't match the expected name "System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51".
        Considered "C:\Users\ter\.nuget\packages\nunit3testadapter\4.5.0\build\net462\testcentric.engine.metadata.dll",
            but its name "testcentric.engine.metadata"
            didn't match the expected name "System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51".
    For SearchPath "{TargetFrameworkDirectory}".
        Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.Memory.winmd", but it didn't exist.
        Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.Memory.dll", but it didn't exist.
        Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.Memory.exe", but it didn't exist.
        Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\Facades\System.Memory.winmd", but it didn't exist.
        Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\Facades\System.Memory.dll", but it didn't exist.
        Considered "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\Facades\System.Memory.exe", but it didn't exist.
    Required by "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Reporting.Addin\bin\Debug\netstandard2.0\Qlik.Reporting.AddIn.dll".

But if we look at the build of the referenced project Qlik.Reporting.AddIn.dll, for which System.Memory is still not a direct dependency and that is a netstandard2.0, we will find:

Unified primary reference "System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51".
    Using this version instead of original version "4.0.1.1" in "C:\Users\ter\.nuget\packages\google.protobuf\3.23.3\lib\netstandard2.0\Google.Protobuf.dll" because AutoUnify is 'true'.
    Using this version instead of original version "4.0.1.1" in "C:\Users\ter\.nuget\packages\grpc.core\2.46.6\lib\netstandard2.0\Grpc.Core.dll" because AutoUnify is 'true'.
    Using this version instead of original version "4.0.1.1" in "C:\Users\ter\.nuget\packages\grpc.core.api\2.46.6\lib\netstandard2.0\Grpc.Core.Api.dll" because AutoUnify is 'true'.
    Using this version instead of original version "4.0.1.1" in "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Printing\bin\Debug\netstandard2.0\System.Collections.Immutable.dll" because AutoUnify is 'true'.
    Using this version instead of original version "4.0.1.1" in "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Printing\bin\Debug\netstandard2.0\System.Diagnostics.DiagnosticSource.dll" because AutoUnify is 'true'.
    Using this version instead of original version "4.0.1.1" in "C:\dev\Projects\opera-the-5th\server\NPrinting\src\Qlik.Printing\bin\Debug\netstandard2.0\System.Reflection.MetadataLoadContext.dll" because AutoUnify is 'true'.
    Resolved file path is "C:\Users\ter\.nuget\packages\system.memory\4.5.5\lib\netstandard2.0\System.Memory.dll".
    Reference found at search path location "{HintPathFromItem}".
    This reference is not "CopyLocal" because at least one source item had "Private" set to "false" and no source items had "Private" set to "true".

SuggestedBindingRedirects
    ...
    System.Memory, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
        MaxVersion = 4.0.1.2
    ...

In this project, System.Memory enters in the build during the execution of the task ResolvePackageAssets and is present in its project.assets.json (due to the fact that it is a netstandard2.0???)

The interesting part is that even in the test project it is present in the ResolvePackageAssets with the correct version but discarded for some reason later.

I could not produce a working example, but my idea is: if each dependency and transient dependency project is correctly generating its binding redirects even when CopyLocalLockFileAssemblies is set at false, why the generation for the final project is not just a merge of all of them?

If you need other informations or log I can produce them on request

qlikTERror commented 1 year ago

On the other side from further tests, setting CopyLocalLockFileAssemblies at true for every project will make netstandard2.0 projects reach final build directory. So for example netstandard2.0 System.Reflection.DispatchProxy that is not supported in .NET standard will be run instead of the platform specific one.

And this is another problem too.