-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Description
I have a very strange situation. Currently I am writing a custom MSBuild task in C# that I want to use in my build process. This task references a NuGet package, that calls the HttpClient extension method Task<TValue?> GetFromJsonAsync<TValue>(this HttpClient client, string? requestUri, JsonTypeInfo<TValue> jsonTypeInfo, CancellationToken cancellationToken) that is implemented in the System.Net.Http.Json assembly. My own task is targeted against .NET10 and the NuGet package is targeted against .NET9.
I have added the task to my build in the following way:
<UsingTask AssemblyFile="MyTaskAssembly.dll"
Runtime="NET"
TaskName="MyCustomTask" />
<Target Name="MyCustomTarget">
<MyCustomTask />
</Target>When I run the task during the build, I get the following exception:
error MSB4018: System.MissingMethodException->
Microsoft.Build.Framework
.BuildException
.GenericBuildTransferredException:
Method not found: 'System.Threading.Tasks.Task`1<!!0>
System.Net.Http
.Json
.HttpClientJsonExtensions
.GetFromJsonAsync(System.Net.Http.HttpClient,
System.String,
System.Text.Json.Serialization.Metadata.JsonTypeInfo`1<!!0>,
System.Threading.CancellationToken)'.
Now, when I create a console application that references the assembly with my custom task and then execute the task, using the following code:
MyTask task = new MyTask();
task.BuildEngine = new BuildEngine();
task.Execute();the task succeeds without any runtime exceptions.
To find the cause of this, I tried and investigated the following things:
- Clone the NuGet package source repository and changed the projects to target .NET10 instead of .NET9 and use my custom NuGet package build. This did not fix the issue and the
MissingMethodExceptionis still thrown. - Run sysinternals' Process Monitor to see if what DLLs are loaded during the execution of the task during a build. I saw that the file
C:\Program Files\dotnet\shared\Microsoft.NETCore.App\10.0.1\System.Net.Http.Json.dllis loaded correctly and loaded this file in ILSpy to see if the method actually exists in that assembly and it does. - Compared the signature of the
GetFromJsonAsyncmethod in .NET9 and .NET10 and there does not seem to be a difference in signature, even the parameter attribute for therequestUriparameter is the same. - Added an event handler to
AppDomain.CurrentDomain.AssemblyLoadthat just logs what assembly is loaded and the assemblySystem.Net.Http.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51is logged as being loaded (confirming what Process Monitor already indicated). - Looked at the IL of the method in the NuGet package to see what method is actually called:
call class [System.Runtime]System.Threading.Tasks.Task`1<!!0> [System.Net.Http.Json]System.Net.Http.Json.HttpClientJsonExtensions::GetFromJsonAsync<class NpmRegistry.Wrapper.Models.NpmPackage>(class [System.Net.Http]System.Net.Http.HttpClient, string, class [System.Text.Json]System.Text.Json.Serialization.Metadata.JsonTypeInfo`1<!!0>, valuetype [System.Runtime]System.Threading.CancellationToken). It seems to me that it wants to call the method from theSystem.Net.Http.Jsonassembly as expected. - Using
dotnet-traceI hopefully have some additional information. I ran the tool with the following command line:dotnet-trace collect --clreventlevel 5 --clrevents assemblyloader+loader+exception+codesymbols --process-id <pid of the task>(this is needed because the task is run out of process since it is built with .NET10) while performing a build in Visual Studio.This led to the following events right before the exception is thrown:
Provider Name/Event Name Text
Microsoft-Windows-DotNETRuntime/AssemblyLoader/Start [ClrInstanceID, 9], [AssemblyName, System.Net.Http.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51], [AssemblyPath, ], [RequestingAssembly, NpmRegistry.Wrapper, Version=1.3.0.0, Culture=neutral, PublicKeyToken=null], [AssemblyLoadContext, "MSBuild plugin E:\WebPages\personal.NET\_bin\_tools\Simulation\net10.0\Tasks.dll" Microsoft.Build.Shared.MSBuildLoadContext #0], [RequestingAssemblyLoadContext, "MSBuild plugin E:\WebPages\personal.NET\_bin\_tools\Simulation\net10.0\Tasks.dll" Microsoft.Build.Shared.MSBuildLoadContext #0]
Microsoft-Windows-DotNETRuntime/AssemblyLoader/ResolutionAttempted [ClrInstanceID, 9], [AssemblyName, System.Net.Http.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51], [Stage, FindInLoadContext], [AssemblyLoadContext, "MSBuild plugin E:\WebPages\personal.NET\_bin\_tools\Simulation\net10.0\Tasks.dll" Microsoft.Build.Shared.MSBuildLoadContext #0], [Result, AssemblyNotFound], [ResultAssemblyName, ], [ResultAssemblyPath, ], [ErrorMessage, Could not locate assembly]
Microsoft-Windows-DotNETRuntime/AssemblyLoader/ResolutionAttempted [ClrInstanceID, 9], [AssemblyName, System.Net.Http.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51], [Stage, AssemblyLoadContextLoad], [AssemblyLoadContext, "MSBuild plugin E:\WebPages\personal.NET\_bin\_tools\Simulation\net10.0\Tasks.dll" Microsoft.Build.Shared.MSBuildLoadContext #0], [Result, AssemblyNotFound], [ResultAssemblyName, ], [ResultAssemblyPath, ], [ErrorMessage, Could not locate assembly]
Microsoft-Windows-DotNETRuntime/AssemblyLoader/KnownPathProbed [ClrInstanceID, 9], [FilePath, C:\Program Files\dotnet\shared\Microsoft.NETCore.App\10.0.1\System.Net.Http.Json.dll], [Source, ApplicationAssemblies], [Result, 0]
Microsoft-Windows-DotNETRuntime/AssemblyLoader/ResolutionAttempted [ClrInstanceID, 9], [AssemblyName, System.Net.Http.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51], [Stage, FindInLoadContext], [AssemblyLoadContext, Default], [Result, AssemblyNotFound], [ResultAssemblyName, ], [ResultAssemblyPath, ], [ErrorMessage, Could not locate assembly]
Microsoft-Windows-DotNETRuntime/AssemblyLoader/ResolutionAttempted [ClrInstanceID, 9], [AssemblyName, System.Net.Http.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51], [Stage, ApplicationAssemblies], [AssemblyLoadContext, Default], [Result, Success], [ResultAssemblyName, System.Net.Http.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51], [ResultAssemblyPath, C:\Program Files\dotnet\shared\Microsoft.NETCore.App\10.0.1\System.Net.Http.Json.dll], [ErrorMessage, ]
Microsoft-Windows-DotNETRuntime/AssemblyLoader/ResolutionAttempted [ClrInstanceID, 9], [AssemblyName, System.Net.Http.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51], [Stage, DefaultAssemblyLoadContextFallback], [AssemblyLoadContext, "MSBuild plugin E:\WebPages\personal.NET\_bin\_tools\Simulation\net10.0\Tasks.dll" Microsoft.Build.Shared.MSBuildLoadContext #0], [Result, Success], [ResultAssemblyName, System.Net.Http.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51], [ResultAssemblyPath, C:\Program Files\dotnet\shared\Microsoft.NETCore.App\10.0.1\System.Net.Http.Json.dll], [ErrorMessage, ]
Microsoft-Windows-DotNETRuntime/AssemblyLoader/Stop [ClrInstanceID, 9], [AssemblyName, System.Net.Http.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51], [AssemblyPath, ], [RequestingAssembly, NpmRegistry.Wrapper, Version=1.3.0.0, Culture=neutral, PublicKeyToken=null], [AssemblyLoadContext, "MSBuild plugin E:\WebPages\personal.NET\_bin\_tools\Simulation\net10.0\Tasks.dll" Microsoft.Build.Shared.MSBuildLoadContext #0], [RequestingAssemblyLoadContext, "MSBuild plugin E:\WebPages\personal.NET\_bin\_tools\Simulation\net10.0\Tasks.dll" Microsoft.Build.Shared.MSBuildLoadContext #0], [Success, True], [ResultAssemblyName, System.Net.Http.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51], [ResultAssemblyPath, C:\Program Files\dotnet\shared\Microsoft.NETCore.App\10.0.1\System.Net.Http.Json.dll], [Cached, False]
Microsoft-Windows-DotNETRuntime/Loader/AssemblyLoad [AssemblyID, 2354263771168], [AppDomainID, 2355714450368], [AssemblyFlags, ReadyToRun], [FullyQualifiedAssemblyName, System.Net.Http.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51], [BindingID, 0], [ClrInstanceID, 9]
Microsoft-Windows-DotNETRuntime/Loader/ModuleLoad [ModuleID, 140719892123472], [AssemblyID, 2354263771168], [ModuleFlags, Manifest, ReadyToRunModule], [ModuleILPath, C:\Program Files\dotnet\shared\Microsoft.NETCore.App\10.0.1\System.Net.Http.Json.dll], [ModuleNativePath, ], [ManagedPdbSignature, 7543d2be-596d-99e2-edcc-08858346c399], [ManagedPdbAge, 1], [ManagedPdbBuildPath, /_/src/runtime/artifacts/obj/System.Net.Http.Json/Release/net10.0/System.Net.Http.Json.pdb], [NativePdbSignature, 43cb33d4-065a-2db8-dfdf-2768c026b1dc], [NativePdbAge, 1], [NativePdbBuildPath, System.Net.Http.Json.ni.pdb], [ModuleILFileName, System.Net.Http.Json.dll]
Microsoft-Windows-DotNETRuntime/Loader/DomainModuleLoad [ModuleID, 140719892123472], [AssemblyID, 2354263771168], [AppDomainID, 2355714450368], [ModuleFlags, Manifest, ReadyToRunModule], [ModuleILPath, C:\Program Files\dotnet\shared\Microsoft.NETCore.App\10.0.1\System.Net.Http.Json.dll], [ModuleNativePath, ], [ClrInstanceID, 9]
Microsoft-Windows-DotNETRuntime/AssemblyLoader/Start [ClrInstanceID, 9], [AssemblyName, System.Text.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51], [AssemblyPath, ], [RequestingAssembly, System.Net.Http.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51], [AssemblyLoadContext, Default], [RequestingAssemblyLoadContext, Default]
Microsoft-Windows-DotNETRuntime/AssemblyLoader/KnownPathProbed [ClrInstanceID, 9], [FilePath, C:\Program Files\dotnet\shared\Microsoft.NETCore.App\10.0.1\System.Text.Json.dll], [Source, ApplicationAssemblies], [Result, 0]
Microsoft-Windows-DotNETRuntime/AssemblyLoader/ResolutionAttempted [ClrInstanceID, 9], [AssemblyName, System.Text.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51], [Stage, FindInLoadContext], [AssemblyLoadContext, Default], [Result, AssemblyNotFound], [ResultAssemblyName, ], [ResultAssemblyPath, ], [ErrorMessage, Could not locate assembly]
Microsoft-Windows-DotNETRuntime/AssemblyLoader/ResolutionAttempted [ClrInstanceID, 9], [AssemblyName, System.Text.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51], [Stage, ApplicationAssemblies], [AssemblyLoadContext, Default], [Result, Success], [ResultAssemblyName, System.Text.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51], [ResultAssemblyPath, C:\Program Files\dotnet\shared\Microsoft.NETCore.App\10.0.1\System.Text.Json.dll], [ErrorMessage, ]
Microsoft-Windows-DotNETRuntime/AssemblyLoader/Stop [ClrInstanceID, 9], [AssemblyName, System.Text.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51], [AssemblyPath, ], [RequestingAssembly, System.Net.Http.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51], [AssemblyLoadContext, Default], [RequestingAssemblyLoadContext, Default], [Success, True], [ResultAssemblyName, System.Text.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51], [ResultAssemblyPath, C:\Program Files\dotnet\shared\Microsoft.NETCore.App\10.0.1\System.Text.Json.dll], [Cached, False]
Microsoft-Windows-DotNETRuntime/Loader/AssemblyLoad [AssemblyID, 2354263765792], [AppDomainID, 2355714450368], [AssemblyFlags, ReadyToRun], [FullyQualifiedAssemblyName, System.Text.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51], [BindingID, 0], [ClrInstanceID, 9]
Microsoft-Windows-DotNETRuntime/Loader/ModuleLoad [ModuleID, 140719892128080], [AssemblyID, 2354263765792], [ModuleFlags, Manifest, ReadyToRunModule], [ModuleILPath, C:\Program Files\dotnet\shared\Microsoft.NETCore.App\10.0.1\System.Text.Json.dll], [ModuleNativePath, ], [ManagedPdbSignature, 598db87f-20be-99e5-3876-4757d3bbc727], [ManagedPdbAge, 1], [ManagedPdbBuildPath, /_/src/runtime/artifacts/obj/System.Text.Json/Release/net10.0/System.Text.Json.pdb], [NativePdbSignature, 36eb7d03-7580-e63a-3c25-1d4e2af43414], [NativePdbAge, 1], [NativePdbBuildPath, System.Text.Json.ni.pdb], [ModuleILFileName, System.Text.Json.dll]
Microsoft-Windows-DotNETRuntime/Loader/DomainModuleLoad [ModuleID, 140719892128080], [AssemblyID, 2354263765792], [AppDomainID, 2355714450368], [ModuleFlags, Manifest, ReadyToRunModule], [ModuleILPath, C:\Program Files\dotnet\shared\Microsoft.NETCore.App\10.0.1\System.Text.Json.dll], [ModuleNativePath, ], [ClrInstanceID, 9]
Microsoft-Windows-DotNETRuntime/Exception/Start [ExceptionType, System.MissingMethodException], [ExceptionMessage, Method not found: 'System.Threading.Tasks.Task`1<!!0> System.Net.Http.Json.HttpClientJsonExtensions.GetFromJsonAsync(System.Net.Http.HttpClient, System.String, System.Text.Json.Serialization.Metadata.JsonTypeInfo`1<!!0>, System.Threading.CancellationToken)'.], [ExceptionEIP, 0x00000000], [ExceptionHRESULT, -2146233069], [ExceptionFlags, CLSCompliant], [ClrInstanceID, 9]
This shows that first the System.Net.Http.Json version 10.0.0.0 is loaded (though version 9.0.0.0 is requested) and then System.Text.Json version 10.0.0.0. According to the Microsoft-Windows-DotNETRuntime/AssemblyLoader/Stop events, both assemblies are loaded correctly. And right after loading System.Text.Json the MissingMethodException is thrown. The NuGet package that calls the "missing method" is compiled using .NET9, but in my local copy I also compiled it for .NET10 and that did not resolve this issue.
- By debugging the task and let the debugger break when the
MissingMethodExceptionis thrown, I managed to get the stacktrace:
System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start<NpmRegistry.Wrapper.NpmRegistryClient.<GetPackageData>d__3>(ref NpmRegistry.Wrapper.NpmRegistryClient.<GetPackageData>d__3 stateMachine) Line 38 C#
System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.__Canon>.Start<NpmRegistry.Wrapper.NpmRegistryClient.<GetPackageData>d__3>(ref NpmRegistry.Wrapper.NpmRegistryClient.<GetPackageData>d__3 stateMachine) Line 35 C#
NpmRegistry.Wrapper.dll!NpmRegistry.Wrapper.NpmRegistryClient.GetPackageData(string name, string ns, System.Threading.CancellationToken cancellationToken) Line 37 Unknown
... <left out the rest of the stack trace as that is just where I call this GetPackageData method and the startup methods for the process>
The stateMachine variable is generated by the compiler, because the called method is an async one. I also verified if there is an inner exception in the thrown exception, but that property is null.
I am using Visual Studio version 18.1.1 (latest) and building from the IDE, but it also fails when performing the build using MSBuild on the command line, or when using dotnet build.
The version reported by MSBuild is:
MSBuild version 18.0.5+e22287bf1 for .NET Framework
18.0.5.56406
The version reported by dotnet is:
10.0.101
The JsonTypeInfo is generated using the following code:
using System.Text.Json;
using System.Text.Json.Serialization;
namespace NpmRegistry.Wrapper.Models;
[JsonSerializable(typeof(NpmPackage))]
[JsonSourceGenerationOptions(AllowTrailingCommas = true,
GenerationMode = JsonSourceGenerationMode.Default,
IgnoreReadOnlyFields = false,
IgnoreReadOnlyProperties = false,
IncludeFields = false,
MaxDepth = 15,
NumberHandling = JsonNumberHandling.Strict,
PreferredObjectCreationHandling = JsonObjectCreationHandling.Replace,
ReadCommentHandling = JsonCommentHandling.Skip,
UnknownTypeHandling = JsonUnknownTypeHandling.JsonElement,
UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip,
UseStringEnumConverter = true,
WriteIndented = false)]
internal sealed partial class ModelsSerializerContext : JsonSerializerContext
{
}and then passed to the call to GetFromJsonAsync as follows: httpClient.GetFromJsonAsync(url, ModelsSerializerContext.Default.NpmPackage, cancellationToken);