Пользовательская задача MSBuild C# вызывает исключение MissingMethodExceptionC#

Место общения программистов C#
Ответить
Anonymous
 Пользовательская задача MSBuild C# вызывает исключение MissingMethodException

Сообщение Anonymous »

У меня очень странная ситуация. В настоящее время я пишу специальную задачу MSBuild на C#, которую хочу использовать в процессе сборки. Эта задача ссылается на пакет NuGet, который вызывает метод расширения HttpClient Task GetFromJsonAsync(этот клиент HttpClient, string? requestUri, JsonTypeInfo jsonTypeInfo, CancellationToken cancelToken), который реализован в сборке System.Net.Http.Json. Моя собственная задача ориентирована на .NET10, а пакет NuGet ориентирован на .NET9.
Я добавил задачу в свою сборку следующим образом: Когда я запускаю задачу во время сборки, я получаю следующее исключение:

Код: Выделить всё

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)'.

Теперь, когда я создаю консольное приложение, которое ссылается на сборку с моей пользовательской задачей, а затем выполняю задачу, используя следующий код:

Код: Выделить всё

MyTask task = new MyTask();
task.BuildEngine = new BuildEngine();
task.Execute();
задача выполняется без каких-либо исключений во время выполнения.
Чтобы найти причину этого, я попробовал и исследовал следующие вещи:
  • Клонировал репозиторий исходного кода пакета NuGet и изменил проекты на .NET10 вместо .NET9 и использовал свою собственную сборку пакета NuGet. Это не устранило проблему, и исключение MissingMethodException по-прежнему выдается.
  • Запустите Process Monitor sysinternals, чтобы узнать, какие библиотеки DLL загружаются во время выполнения задачи во время сборки. Я увидел, что файл C:\Program Files\dotnet\shared\Microsoft.NETCore.App\10.0.1\System.Net.Http.Json.dll загружен правильно, и загрузил этот файл в ILSpy, чтобы проверить, действительно ли метод существует в этой сборке, и он существует.
  • Сравнил подпись метода GetFromJsonAsync в .NET9 и .NET10 и похоже, нет разницы в подписи, даже атрибут параметра для параметра requestUri один и тот же.
  • Добавлен обработчик событий в AppDomain.CurrentDomain.AssemblyLoad, который просто регистрирует, какая сборка загружена, и сборка System.Net.Http.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51 регистрируется как загруженный (подтверждая то, что уже указано в Process Monitor).
  • Просмотрел IL-код метода в пакете NuGet, чтобы узнать, какой метод на самом деле вызывается: вызов класса [System.Runtime]System.Threading.Tasks.Task`1 [System.Net.Http.Json]System.Net.Http.Json.HttpClientJsonExtensions::GetFromJsonAsync(класс [System.Net.Http]System.Net.Http.HttpClient, строка, класс [System.Text.Json]System.Text.Json.Serialization.Metadata.JsonTypeInfo`1, тип значения [System.Runtime]System.Threading.CancellationToken). Мне кажется, что он хочет вызвать метод из сборки System.Net.Http.Json, как и ожидалось.
Я использую Visual Studio версии 18.1.1 (последняя) и собираю из IDE, но при выполнении сборки с помощью MSBuild в командной строке также происходит сбой. Версия, о которой сообщает MSBuild:

Код: Выделить всё

MSBuild version 18.0.5+e22287bf1 for .NET Framework
18.0.5.56406
Можно ли что-нибудь попробовать? Что мне здесь не хватает?
ОБНОВЛЕНИЕ
Использование dotnet-trace Надеюсь, у меня есть дополнительная информация. Я запустил инструмент с помощью следующей командной строки: dotnet-tracecollect --clreventlevel 5 --clrevents Assemblyloader+loader+Exception+codesymbols --process-id
(это необходимо, поскольку задача выполняется вне процесса, поскольку она построена с использованием .NET10).
Это привело к следующим событиям непосредственно перед созданием исключения:

Код: Выделить всё

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]
Это показывает, что сначала загружается System.Net.Http.Json версии 10.0.0.0 (хотя запрашивается версия 9.0.0.0), а затем System.Text.Json версии 10.0.0.0. Согласно событиям Microsoft-Windows-DotNETRuntime/AssemblyLoader/Stop обе сборки загружаются корректно. И сразу после загрузки System.Text.Json выдается исключение MissingMethodException.
Пакет NuGet, вызывающий «отсутствующий метод», скомпилирован с использованием .NET9, но в своей локальной копии я также скомпилировал его для .NET10, и это не решило эту проблему, поэтому должно быть что-то, что я упускаю из виду. Может быть, мне нужны дополнительные события для регистрации с помощью dotnet-trace?
UPDATE 2
Путем отладки задачи и позволения отладчику прерываться при возникновении MissingMethodException мне удалось получить stacktrace:

Код: Выделить всё

System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start(ref NpmRegistry.Wrapper.NpmRegistryClient.d__3 stateMachine) Line 38    C#
System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start(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
... 
Переменная stateMachine генерируется компилятором, поскольку вызываемый метод является асинхронным. Я также проверил, есть ли внутреннее исключение в выброшенном исключении, но это свойство имеет значение NULL.
ОБНОВЛЕНИЕ 3
JsonTypeInfo генерируется с использованием следующего кода:

Код: Выделить всё

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
{
}
а затем перешел к вызову GetFromJsonAsync следующим образом: httpClient.GetFromJsonAsync(url, ModelsSerializerContext.Default.NpmPackage, cancelToken);
ОБНОВЛЕНИЕ 4
Мне удалось избавиться от MissingMethodException, исключив из сборки задачи код, который также использует JsonSerializationContext для сериализации и десериализации некоторых объектов, которые я специально использую в этой сборке. Я не думаю, что это конфликт версий для сборки System.Net.Http.Json, поскольку то же исключение выдается, когда я сам собираю пакет NuGet для .NET 10.0.
Теперь интересно, почему удаление моей сериализации/десериализации JSON в сборке задач приводит к внезапному успеху десериализации в пакете NuGet.
ОБНОВЛЕНИЕ 5
Немного подробнее о сценарии, в котором он прерывается с MissingMethodException (по-прежнему, только при запуске как задача MSBuild и НЕ при запуске как отдельное приложение).
Также для обзора краткое описание настройки (включая дополнительные сведения, необходимые для этой проблемы). У меня есть специальная задача MSBuild, реализованная на C#, и я создаю ее для .NET10. В своей задаче я также выполняю анализ JSON, используя сгенерированный JsonSerializerContext. Это делает сборку задачи также AOT-совместимой. Настраиваемая задача использует сторонний пакет NuGet (

Код: Выделить всё

Fiedler.NpmRegistry.Wrapper
), который также использует сгенерированный JsonSerializerContext (начиная с версии 1.2.1) для анализа результатов, полученных от реестра.npmjs.org, передавая сгенерированный JsonTypeInfo вызову метода расширения HttpClient GetFromJsonAsync (из сборки System.Net.Http.Json). В настоящее время этот пакет NuGet создан для .NET9, но та же проблема все еще существует, когда я локально собираю этот пакет для .NET10. В любом случае сборка System.Net.Http.Json .NET10 загружается в любом случае.
Как только какой-либо код в моей сборке задачи вызывает JsonSerializer.Deserialize (неважно, до или после вызова GetFromJsonAsync), MissingMethodException возникает в первом вызове GetFromJsonAsync. При использовании JsonSerializer.Deserialize где-нибудь в коде моих задач (и здесь не имеет значения, задействован ли сгенерированный код или нет!), выдается исключение.
Обратите также внимание, что версия 1.2.0 Fiedler.NpmRegistry.Wrapper не использовала предварительно скомпилированный JsonSerializerContext, но в моей настройке также не удалось назначить свойства классов из JSON неправильно использует отражение. Так что, вероятно, где-то в синтаксическом анализе JSON есть что-то фундаментально неправильное.
На мой взгляд, он становится все более и более странным.

Подробнее здесь: https://stackoverflow.com/questions/798 ... dexception
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»