MSBuild C# custom task throws MissingMethodException
- Dominant language
- C#
- Stars
- 5.5k
- Forks
- 1.5k
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 141
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 GetFromJsonAsync(this HttpClient client, string? requestUri, JsonTypeInfo 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:
```XML
```
When I run the task during the build, I get the following exception:
```plain
error MSB4018: System.MissingMethodException->
Microsoft.Build.Framework
.BuildException
.GenericBuildTransferredException:
Method not found: 'System.Threading.Tasks.Task`1
System.Net.Http
.Json
.HttpClientJsonExtensions
.GetFromJsonAsync(System.Net.Http.HttpClient,
System.String,
System.Text.Json.Serialization.Metadata.JsonTypeInfo`1,
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:
```csharp
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 `MissingMethodException` is 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.dll` is 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 `GetFromJsonAsync` method in .NET9 and .NET10 and there does not seem to be a difference in signature, even the parameter attribute for the `requestUri` parameter is the same.
- Added an event handler to `AppDomain.CurrentDomain.AssemblyLoad` that just logs what assembly is loaded and the assembly `System.Net.Http.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51` is 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 [System.Net.Http.Json]System.Net.Http.Json.HttpClientJsonExtensions::GetFromJsonAsync(class [System.Net.Http]System.Net.Http.HttpClient, string, class [System.Text.Json]System.Text.Json.Serialization.Metadata.JsonTypeInfo`1, valuetype [System.Runtime]System.Threading.CancellationToken)``. It seems to me that it wants to call the method from the `System.Net.Http.Json` assembly as expected.
- Using `dotnet-trace` I 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 ` (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 System.Net.Http.Json.HttpClientJsonExtensions.GetFromJsonAsync(System.Net.Http.HttpClient, System.String, System.Text.Json.Serialization.Metadata.JsonTypeInfo`1, 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 `MissingMethodException` is thrown, I managed to get the stacktrace:
```
System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Startd__3>(ref NpmRegistry.Wrapper.NpmRegistryClient.d__3 stateMachine) Line 38 C#
System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Startd__3>(ref NpmRegistry.Wrapper.NpmRegistryClient.d__3 stateMachine) Line 35 C#
NpmRegistry.Wrapper.dll!NpmRegistry.Wrapper.NpmRegistryClient.GetPackageData(string name, string ns, System.Threading.CancellationToken cancellationToken) Line 37 Unknown
...
```
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:
```C#
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);`
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.