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

MSBuild on .NET Core does not allow tasks with same assembly name, but different assembly versions #3572

Closed
nguerrera opened this issue Aug 1, 2018 · 12 comments
Labels
Area: Engine Issues impacting the core execution of targets and tasks. bug .NET Core triaged

Comments

@nguerrera
Copy link
Contributor

nguerrera commented Aug 1, 2018

With desktop MSBuild / VS, we've gotten around issues with node reuse and varying versions of the SDK by increasing the assembly version of the SDK tasks on every build. (Aside: we've regressed that a bunch of times with infrastructure changes.)

However, this does not work on .NET Core. I suspect we haven't noticed this until now because node reuse has only made its way to .NET Core recently.

Steps to reproduce

Run ReproCore.cmd from nguerrera/repros@fc1e1df

WARNING: First step of repro kills msbuild.exe processes, so don't do this with real builds in progress in parallel.

Command line

git clone https://github.com/nguerrera/repros
cd repros
git checkout fc1e1df38786edff4258c6c2ed09ec6f4c89c4a3
cd NodeReuseAndAssemblyVer
ReproCore.cmd

Expected behavior

Final build command in .cmd succeeds as it does on Desktop (try ReproDesktop.cmd instead).

Actual behavior

D:\Src\repros\NodeReuseAndAssemblyVer\repro.proj(16,9): error MSB4062: The "MyTask" task could not be loaded from the assembly D:\Src\repros\NodeReuseAndAssemblyVer\bin\2.0.0\netstandard2.0\MyTask.dll.
Assembly with same name is already loaded Confirm that the <UsingTask> declaration is correct, that the assembly and all its dependencies are available, and that the task contains a public class that implements
Microsoft.Build.Framework.ITask.

Environment data

Microsoft (R) Build Engine version 15.8.160-preview+gaf9d27ba72 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

15.8.160.40367

.NET Core SDK (reflecting any global.json):
 Version:   2.1.400-preview-009171
 Commit:    6f5d38734b

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.17134
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\2.1.400-preview-009171\

cc @davkean @rainersigwald @dsplaisted

@nguerrera
Copy link
Contributor Author

Hmm, this repro might not be good because the assembly isn't strong name signed. I suspect desktop is silently reloading old version. Let me update it to strong name sign the assembly...

@nguerrera
Copy link
Contributor Author

Repro fixed to strong name task. Still gives the unexpected behavior on core.

@rainersigwald
Copy link
Member

@nguerrera
Copy link
Contributor Author

This may be a limitation of putting all tasks in default assembly load context.

@rainersigwald
Copy link
Member

That's plausible. This throws:

image

System.IO.FileLoadException: Assembly with same name is already loaded
   at System.Runtime.Loader.AssemblyLoadContext.LoadFromPath(IntPtr ptrNativeAssemblyLoadContext, String ilPath, String niPath, ObjectHandleOnStack retAssembly)
   at System.Runtime.Loader.AssemblyLoadContext.LoadFromAssemblyPath(String assemblyPath)
   at Microsoft.Build.Shared.CoreClrAssemblyLoader.LoadAndCache(String fullPath) in /_/src/Shared/CoreCLRAssemblyLoader.cs:line 146
   at Microsoft.Build.Shared.CoreClrAssemblyLoader.LoadFromPath(String fullPath) in /_/src/Shared/CoreCLRAssemblyLoader.cs:line 72
   at Microsoft.Build.Shared.TypeLoader.LoadAssembly(AssemblyLoadInfo assemblyLoadInfo) in /_/src/Shared/TypeLoader.cs:line 181
   at Microsoft.Build.Shared.TypeLoader.AssemblyInfoToLoadedTypes.ScanAssemblyForPublicTypes() in /_/src/Shared/TypeLoader.cs:line 370
   at Microsoft.Build.Shared.TypeLoader.AssemblyInfoToLoadedTypes.<>c__DisplayClass8_0.<GetLoadedTypeByTypeName>b__0(String key) in /_/src/Shared/TypeLoader.cs:line 341
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.Build.Shared.TypeLoader.AssemblyInfoToLoadedTypes.GetLoadedTypeByTypeName(String typeName) in /_/src/Shared/TypeLoader.cs:line 314
   at Microsoft.Build.Shared.TypeLoader.GetLoadedType(ConcurrentDictionary`2 cache, String typeName, AssemblyLoadInfo assembly) in /_/src/Shared/TypeLoader.cs:line 242
   at Microsoft.Build.Shared.TypeLoader.Load(String typeName, AssemblyLoadInfo assembly) in /_/src/Shared/TypeLoader.cs:line 208
   at Microsoft.Build.BackEnd.AssemblyTaskFactory.InitializeFactory(AssemblyLoadInfo loadInfo, String taskName, IDictionary`2 taskParameters, String taskElementContents, IDictionary`2 taskFactoryIdentityParameters, Boolean taskHostFactoryExplicitlyRequested, TargetLoggingContext targetLoggingContext, ElementLocation elementLocation, String taskProjectFile) in /_/src/Build/Instance/TaskFactories/AssemblyTaskFactory.cs:line 278

And indeed, from https://github.com/dotnet/coreclr/blob/master/Documentation/design-docs/assemblyloadcontext.md#custom-loadcontext

Multiple assemblies with the same simple name cannot be loaded into a single load context (Default or Custom). Also, .Net Core ignores strong name token for assembly binding process.

So I guess we should have a load context per . . . assembly path?

@rainersigwald rainersigwald added bug .NET Core Area: Engine Issues impacting the core execution of targets and tasks. labels Aug 1, 2018
@nguerrera
Copy link
Contributor Author

nguerrera commented Aug 1, 2018

So I guess we should have a load context per . . . assembly path?

Yes. More precisely, per UsingTask AssemblyFile path. Dependencies of the task would come into the same load context as the task.

This is very much related to the challenges that @natemcmaster outlined here: https://natemcmaster.com/blog/2018/07/25/netcore-plugins/

Many things he has mentioned have bit msbuild loading tasks and roslyn loading analyzers in turn.

cc @jeffschwMSFT

@nguerrera
Copy link
Contributor Author

I guess this comes down to more motivation for #1754

@dasMulli
Copy link
Contributor

dasMulli commented Aug 1, 2018

I'm currently using something similar to https://github.com/AArnott/Nerdbank.MSBuildExtension/blob/master/src/Nerdbank.MSBuildExtension/netstandard1.5/ContextIsolatedTask.cs
to work around conflicting references.

What popped up on SO was that loading assemblies that are also used by the SDK (newtonsoft.json) are impossible to load (without a custom AssemblyLoadContext to execute your logic).

TL;DR having a load context per task assembly in general would be great! (#1754)

@JamesNK
Copy link
Member

JamesNK commented Dec 14, 2019

What's the status of this bug? Customers are encountering problems with the build tasks in Grpc.Tools:

grpc/grpc#20501

@nguerrera
Copy link
Contributor Author

I believe #4916 would address this and planned for 16.5 / sdk 3.1.200, right, @rainersigwald ?

@rainersigwald
Copy link
Member

Correct; I'll close this as a duplicate.

@rainersigwald
Copy link
Member

Duplicate of #1754

@rainersigwald rainersigwald marked this as a duplicate of #1754 Dec 16, 2019
@AR-May AR-May added the triaged label Feb 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: Engine Issues impacting the core execution of targets and tasks. bug .NET Core triaged
Projects
None yet
Development

No branches or pull requests

5 participants