Enable AOT compatibility analyzers and fix issues - #52865
#52865Merged
Merged
Enable AOT compatibility analyzers and fix issues#52865
Conversation
Member
Author
|
Still in draft; checking test results and working through a few issues. |
Contributor
|
/azp run sdk-unified-build |
|
Azure Pipelines successfully started running 1 pipeline(s). |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR aims to make the CLI codebase more Native AOT-friendly by enabling AOT compatibility analyzers across multiple projects and replacing reflection- or runtime-codegen-based patterns (JSON/XML serialization, assembly path discovery, logging registration) with AOT-compatible alternatives.
Changes:
- Switch various JSON serialization/deserialization call sites to source-generated
JsonSerializerContexttype metadata. - Replace
Assembly.Locationusage withAppContext.BaseDirectory/Environment.ProcessPathin multiple components to support single-file/AOT scenarios. - Enable AOT compatibility analyzers via
<IsAotCompatible>true</IsAotCompatible>in several project files and add targeted suppressions where needed.
Reviewed changes
Copilot reviewed 52 out of 52 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| test/dotnet.Tests/CommandTests/Workload/Repair/GivenDotnetWorkloadRepair.cs | Updates test JSON serialization of PackInfo to use source-generated type info. |
| test/dotnet.Tests/CommandTests/Workload/Install/WorkloadGarbageCollectionTests.cs | Updates test JSON serialization to use source-generated type info; minor whitespace cleanup. |
| test/dotnet.Tests/CommandTests/Workload/Install/GivenFileBasedWorkloadInstall.cs | Updates test JSON serialization to use source-generated type info. |
| test/dotnet.Tests/CommandTests/Workload/Clean/GivenDotnetWorkloadClean.cs | Updates test JSON serialization to use source-generated type info. |
| start-code.cmd | Adds a helper script to launch VS Code with repo-local dotnet environment variables. |
| src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadSetJsonSerializerContext.cs | Adds source-generated JSON context for WorkloadSet dictionary serialization. |
| src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadSet.cs | Switches WorkloadSet JSON (de)serialization to the generated context. |
| src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadResolver.cs | Adjusts PackInfo JSON converter usage (removes attribute on Id). |
| src/Resolvers/Microsoft.DotNet.SdkResolver/Microsoft.DotNet.SdkResolver.csproj | Enables AOT compatibility analyzers (conditional for non-net472). |
| src/Microsoft.Win32.Msi/Microsoft.Win32.Msi.csproj | Enables AOT compatibility analyzers (conditional for non-NETFX TFM). |
| src/Microsoft.DotNet.TemplateLocator/Microsoft.DotNet.TemplateLocator.csproj | Enables AOT compatibility analyzers (conditional for non-NETFX TFM). |
| src/Microsoft.DotNet.ProjectTools/Microsoft.DotNet.ProjectTools.csproj | Enables AOT compatibility analyzers. |
| src/Microsoft.DotNet.ProjectTools/LaunchSettings/ProjectLaunchProfileParser.cs | Switches JSON deserialization to a generated context. |
| src/Microsoft.DotNet.ProjectTools/LaunchSettings/LaunchProfileJsonSerializerContext.cs | Adds generated JSON context for launch profile types. |
| src/Microsoft.DotNet.ProjectTools/LaunchSettings/LaunchProfile.cs | Makes EnvironmentVariables init resilient to null values during deserialization. |
| src/Microsoft.DotNet.ProjectTools/LaunchSettings/ExecutableLaunchProfileParser.cs | Switches JSON deserialization to a generated context. |
| src/Common/WorkloadFileBasedInstall.cs | Switches JSON deserialization to a generated context for workload history. |
| src/Cli/dotnet/dotnet.csproj | Enables AOT compatibility analyzers (conditional for non-NETFX TFM). |
| src/Cli/dotnet/ToolPackage/ToolPackageDownloaderBase.cs | Replaces Assembly.Location-based path resolution with AppContext.BaseDirectory. |
| src/Cli/dotnet/ToolPackage/ToolConfigurationDeserializer.cs | Replaces XmlSerializer with LINQ-to-XML parsing for tool config. |
| src/Cli/dotnet/ToolPackage/LocalToolsResolverCache.cs | Switches cache JSON (de)serialization to a source-generated context. |
| src/Cli/dotnet/NugetSearch/NugetSearchApiResultDeserializer.cs | Switches NuGet search JSON deserialization to a source-generated context. |
| src/Cli/dotnet/NugetPackageDownloader/WorkloadUnixFilePermissionsFileList.cs | Replaces XmlSerializer with streaming XmlReader parsing for file permissions list. |
| src/Cli/dotnet/Installer/Windows/InstallerBase.cs | Replaces SDK directory detection logic to use AppContext.BaseDirectory. |
| src/Cli/dotnet/Installer/Windows/InstallClientElevationContext.cs | Replaces elevated process invocation arguments to avoid Assembly.Location. |
| src/Cli/dotnet/Commands/Workload/WorkloadJsonSerializerContext.cs | Adds generated JSON contexts and a local WorkloadPackId converter for source-gen. |
| src/Cli/dotnet/Commands/Workload/Update/WorkloadUpdateCommand.cs | Switches JSON output to a generated context. |
| src/Cli/dotnet/Commands/Workload/SignCheck_Windows.cs | Replaces Assembly.Location with Environment.ProcessPath for signature checks. |
| src/Cli/dotnet/Commands/Workload/Search/WorkloadSearchVersionsCommand.cs | Switches JSON outputs to a generated context and adds a local context type. |
| src/Cli/dotnet/Commands/Workload/List/WorkloadListCommand.cs | Switches JSON output to a generated context and adds a local context type. |
| src/Cli/dotnet/Commands/Workload/InstallStateContents.cs | Switches install-state JSON (de)serialization to a generated context. |
| src/Cli/dotnet/Commands/Workload/Install/WorkloadManifestUpdater.cs | Switches JSON (de)serialization of advertised workloads to a generated context. |
| src/Cli/dotnet/Commands/Workload/Install/WorkloadInstallCommand.cs | Switches JSON output to a generated context and adds a local context type. |
| src/Cli/dotnet/Commands/Workload/Install/NetSdkMsiInstallerClient.PackGroup.cs | Switches pack group JSON deserialization to a generated context; null-safe collection setter. |
| src/Cli/dotnet/Commands/Workload/Install/MsiInstallerBase.cs | Switches workload history JSON serialization to a generated context. |
| src/Cli/dotnet/Commands/Workload/Install/FileBasedInstaller.cs | Switches PackInfo (de)serialization and history JSON serialization to generated contexts. |
| src/Cli/dotnet/Commands/Workload/GlobalJsonWorkloadSetFile.cs | Switches global-json workload set JSON (de)serialization to a generated context. |
| src/Cli/dotnet/Commands/Tool/List/ToolListLocalCommand.cs | Switches tool list JSON output to source-generated type info. |
| src/Cli/dotnet/Commands/Tool/List/ToolListJsonHelper.cs | Introduces a JsonSerializerContext (with unsafe encoder) for tool list contracts. |
| src/Cli/dotnet/Commands/Tool/List/ToolListGlobalOrToolPathCommand.cs | Switches tool list JSON output to source-generated type info. |
| src/Cli/dotnet/Commands/Test/TestCommandDefinition.cs | Switches global.json parsing to a generated context. |
| src/Cli/dotnet/Commands/Sdk/Check/SdkCheckCommand.cs | Switches SDK-check config JSON parsing to a generated context. |
| src/Cli/dotnet/Commands/Run/CSharpCompilerCommand.cs | Uses source-generated JSON metadata for string serialization within generated JSON output; preserves editorconfig trailing spaces. |
| src/Cli/dotnet/Commands/New/OptionalWorkloadProvider.cs | Adds IL3000 suppression around unavoidable Assembly.Location usage. |
| src/Cli/dotnet/Commands/New/BuiltInTemplatePackageProvider.cs | Adds IL3000 suppression around unavoidable Assembly.Location usage. |
| src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs | Adds IL3000 suppression around unavoidable Assembly.Location usage. |
| src/Cli/dotnet/CliSchema.cs | Switches CLI schema serialization and schema generation to use a source-generated context/options. |
| src/Cli/dotnet/BuildServer/VBCSCompilerServer.cs | Replaces Assembly.Location-based path resolution with AppContext.BaseDirectory. |
| src/Cli/Microsoft.TemplateEngine.Cli/Microsoft.TemplateEngine.Cli.csproj | Enables AOT compatibility analyzers. |
| src/Cli/Microsoft.TemplateEngine.Cli/CliTemplateEngineHost.cs | Adjusts console formatter registration to avoid reflection-heavy generic registration. |
| src/Cli/Microsoft.DotNet.InternalAbstractions/Microsoft.DotNet.InternalAbstractions.csproj | Enables AOT compatibility analyzers (conditional for non-net472). |
| src/Cli/Microsoft.DotNet.Configurer/Microsoft.DotNet.Configurer.csproj | Enables AOT compatibility analyzers and normalizes PublicSign condition formatting. |
…ross the CLI codebase: - **Source-generated JSON serialization**: Replace `JsonSerializer.Serialize<T>`/`Deserialize<T>` calls with source-generated `JsonSerializerContext` types throughout workload, tool list, SDK check, template, and manifest commands. This eliminates reliance on reflection-based `DefaultJsonTypeInfoResolver`. - **Replace `Assembly.GetExecutingAssembly().Location`** with `AppContext.BaseDirectory` or `Environment.ProcessPath` in `VBCSCompilerServer`, `InstallerBase`, `InstallClientElevationContext`, `SignCheck`, and `ToolPackageDownloaderBase`, since `Assembly.Location` returns empty in single-file/AOT deployments. - **Replace `XmlSerializer` with manual XML parsing**: Use `XDocument`/`XmlReader` in `ToolConfigurationDeserializer` and `WorkloadUnixFilePermissionsFileList` to avoid runtime code generation. - **AOT-compatible logging registration**: Change `CliTemplateEngineHost` to use `Services.TryAddEnumerable` instead of the generic `AddConsoleFormatter<T>` overload that relies on `MakeGenericType`. - **Enable AOT compatibility analyzers**: Add `<IsAotCompatible>true</IsAotCompatible>` to `dotnet.csproj`, `Microsoft.DotNet.Configurer`, `Microsoft.DotNet.InternalAbstractions`, `Microsoft.TemplateEngine.Cli`, `Microsoft.DotNet.ProjectTools`, `Microsoft.DotNet.TemplateLocator`, `Microsoft.Win32.Msi`, and `Microsoft.DotNet.SdkResolver` project files. - **Suppress IL3000 warnings** with `#pragma` in locations where `Assembly.Location` is unavoidable (`MSBuildForwardingApp`, `BuiltInTemplatePackageProvider`, `OptionalWorkloadProvider`).
…nd make converter public
The PR removed [JsonConverter(typeof(PackIdJsonConverter))] from the
PackInfo.Id property in WorkloadResolver.cs to enable source-generated
JSON serialization. However, WorkloadPackId is a struct with only a
private field (_id), so default System.Text.Json serialization emits {}
instead of the string value. This breaks JSON round-tripping for any
consumer of the public PackInfo type that doesn't use the CLI's
source-generated context.
Fix by placing [JsonConverter] on the WorkloadPackId struct itself. This
is the lowest-precedence converter location in STJ's resolution order,
so explicit converters specified in source-gen context options (e.g.
WorkloadPackIdJsonConverter in PackInfoJsonSerializerContext.Converters)
still take priority. But for default/reflection-based serialization, the
type-level attribute ensures correct string round-tripping without
requiring any per-property annotation.
PackIdJsonConverter is also changed from internal to public. Previously,
the internal visibility was fine because [JsonConverter] attributes on
properties are resolved at runtime via reflection, which bypasses access
modifiers. With source generation, the compile-time generator validates
the converter type referenced in the attribute is accessible, and an
internal type in another assembly causes SYSLIB1220. Making it public is
consistent with WorkloadPackId itself already being public.
… remove unused references
MiYanni
approved these changes
Feb 10, 2026
This was referenced Mar 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replace reflection-based patterns with AOT-compatible alternatives across the CLI codebase:
Source-generated JSON serialization: Replace
JsonSerializer.Serialize<T>/Deserialize<T>calls with source-generatedJsonSerializerContexttypes throughout workload, tool list, SDK check, template, and manifest commands. This eliminates reliance on reflection-basedDefaultJsonTypeInfoResolver.Replace
Assembly.GetExecutingAssembly().LocationwithAppContext.BaseDirectoryorEnvironment.ProcessPathinVBCSCompilerServer,InstallerBase,InstallClientElevationContext,SignCheck, andToolPackageDownloaderBase, sinceAssembly.Locationreturns empty in single-file/AOT deployments.Replace
XmlSerializerwith manual XML parsing: UseXDocument/XmlReaderinToolConfigurationDeserializerandWorkloadUnixFilePermissionsFileListto avoid runtime code generation.AOT-compatible logging registration: Change
CliTemplateEngineHostto useServices.TryAddEnumerableinstead of the genericAddConsoleFormatter<T>overload that relies onMakeGenericType.Enable AOT compatibility analyzers: Add
<IsAotCompatible>true</IsAotCompatible>todotnet.csproj,Microsoft.DotNet.Configurer,Microsoft.DotNet.InternalAbstractions,Microsoft.TemplateEngine.Cli,Microsoft.DotNet.ProjectTools,Microsoft.DotNet.TemplateLocator,Microsoft.Win32.Msi, andMicrosoft.DotNet.SdkResolverproject files.Suppress IL3000 warnings with
#pragmain locations whereAssembly.Locationis unavoidable (MSBuildForwardingApp,BuiltInTemplatePackageProvider,OptionalWorkloadProvider).