Skip to content

Make Azure.ResourceManager AOT-compatible #50129

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

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

agocke
Copy link

@agocke agocke commented May 16, 2025

There were only two places which were not AOT compatible:

  1. Use of non-source generated JSON.
  2. One method which uses non-generated configuration bindings, which I've simply marked incompatible for now.

Note: almost all of this code was generated by VS Code CoPilot w/ Agent Mode. If you're interested in the prompts I used and the chat session, contact me privately and I'd be happy to share the whole session.

@Copilot Copilot AI review requested due to automatic review settings May 16, 2025 21:42
@github-actions github-actions bot added Community Contribution Community members are working on the issue customer-reported Issues that are reported by GitHub users external to the Azure organization. Mgmt This issue is related to a management-plane library. labels May 16, 2025
Copy link

Thank you for your contribution @agocke! We will review the pull request and get back to you soon.

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR updates Azure.ResourceManager to be AOT-compatible by replacing non-source generated JSON with source-generated contexts and marking incompatible configuration bindings.

  • Added attributes in ArmClientBuilderExtensions to flag reflection and dynamic code usage.
  • Introduced new JSON context classes and updated serialization/deserialization calls to use them.
  • Updated the project file and ArmClientOptions to support AOT compatibility.

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
sdk/resourcemanager/Azure.ResourceManager/src/Extensions/ArmClientBuilderExtensions.cs Added AOT-related attributes to the AddArmClient method.
sdk/resourcemanager/Azure.ResourceManager/src/Common/Custom/Models/ManagedServiceIdentityJsonContext.cs Added a new JSON source generation context.
sdk/resourcemanager/Azure.ResourceManager/src/Common/Custom/Models/ManagedServiceIdentity.Serialization.cs Updated JSON serialization/deserialization to use the new context.
sdk/resourcemanager/Azure.ResourceManager/src/Azure.ResourceManager.csproj Added AOT compatibility property.
sdk/resourcemanager/Azure.ResourceManager/src/ArmEnvironmentJsonContext.cs Introduced a context for ArmEnvironment JSON serialization.
sdk/resourcemanager/Azure.ResourceManager/src/ArmEnvironment.cs Updated ToString to utilize the source-generated context.
sdk/resourcemanager/Azure.ResourceManager/src/ArmClientOptionsJsonContext.cs Added a JSON context for ArmClientOptions.
sdk/resourcemanager/Azure.ResourceManager/src/ArmClientOptions.cs Migrated deserialization to use the new JSON context.

@jsquire jsquire requested review from m-nash and m-redding May 16, 2025 23:31
@jsquire
Copy link
Member

jsquire commented May 16, 2025

@m-nash: Could you give this another pair of eyes from the management + MRW perspective?
@m-redding: Could you give this an AOT look?

@agocke
Copy link
Author

agocke commented May 16, 2025

FYI, still trying to repro those code generation failures locally. For some reason restore is taking forever

Copy link
Member

@jsquire jsquire left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, though I lack in-depth knowledge of the management packages. I've pulled a couple of others in for additional perspectives.

@jsquire
Copy link
Member

jsquire commented May 16, 2025

@agocke: The failures are:

  • The new attributes constitute a change in the API shape, so you'll need to export via: eng\scripts\Export-API.ps1 core
  • The serialization format for managed identity seems to have changed enough that the recording no longer matches. That may or may not be a concern.

@agocke
Copy link
Author

agocke commented May 19, 2025

I've fixed up all the formatting and added the attribute, so I think this is ready to go.

Copy link
Member

@m-redding m-redding left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This LGTM from my perspective although I also don't have much knowledge on the mgmt packages

@@ -23,6 +24,8 @@ public static IAzureClientBuilder<ArmClient, ArmClientOptions> AddArmClient<TBui
/// <summary>
/// Registers an <see cref="ArmClient"/> instance with connection options loaded from the provided <paramref name="configuration"/> instance.
/// </summary>
[RequiresUnreferencedCode("Uses reflection for registration")]
[RequiresDynamicCode("Uses code generation for registration")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit - The message could be more descriptive like what I have in this one here"This utilizes reflection-based JSON serialization and deserialization which is not compatible with trimming."
idk if there's an AOT safe alternative path here but if there is adding that would also be a plus

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jsquire
Copy link
Member

jsquire commented May 21, 2025

@ArthurMa1978, @ArcturusZhang, @live1206, @m-nash: Folks, can you please give this a quick look from the management ownership perspective? Since everything is green, I'm going to move forward with the merge tomorrow EOD if nobody registers any objections or questions.

@m-nash
Copy link
Member

m-nash commented May 22, 2025

I think we want to switch this to SCM SG to stay in line with the other core libraries. Spoke with @agocke today offline and we will come up with a overarching plan to fix the cross library JsonSerializer calls

@@ -23,6 +24,8 @@ public static IAzureClientBuilder<ArmClient, ArmClientOptions> AddArmClient<TBui
/// <summary>
/// Registers an <see cref="ArmClient"/> instance with connection options loaded from the provided <paramref name="configuration"/> instance.
/// </summary>
[RequiresUnreferencedCode("Uses reflection for registration")]
[RequiresDynamicCode("Uses code generation for registration")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[JsonSerializable(typeof(ManagedServiceIdentity))]
[JsonSerializable(typeof(ManagedServiceIdentityType))]
[JsonSerializable(typeof(UserAssignedIdentity))]
internal partial class ManagedServiceIdentityJsonContext : JsonSerializerContext
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets drop this context file and use MRWContext instead which is already created https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/resourcemanager/Azure.ResourceManager/src/Common/Generated/Models/AzureResourceManagerContext.cs.

I think the other JsonSerializerContext files you created above (https://github.com/Azure/azure-sdk-for-net/pull/50129/files#diff-db2b8de102500dff3ce1b4cca617984a46fc86d3b50072de5dd2982af021a09a, https://github.com/Azure/azure-sdk-for-net/pull/50129/files#diff-ac7d79bf6d6b455a3e36744cfa1bc766421ac11e520f80cd6b667c53625764a3) are fine since those are not IJsonModel's and aren't intended to be used in service communication. The serialization there is for utility only.

@@ -45,7 +50,7 @@ internal void Write(Utf8JsonWriter writer, ModelReaderWriterOptions options, Jso
foreach (var item in UserAssignedIdentities)
{
writer.WritePropertyName(item.Key);
JsonSerializer.Serialize(writer, item.Value);
JsonSerializer.Serialize(writer, item.Value, jsonContext.UserAssignedIdentity);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets swap the serialize calls to a cast to IJsonModel and call the write method on there passing in the MRWOptions and MRWContext

@@ -202,7 +211,7 @@ internal static ManagedServiceIdentity DeserializeManagedServiceIdentity(JsonEle
}
if (property.NameEquals("type"u8))
{
type = JsonSerializer.Deserialize<ManagedServiceIdentityType>($"{{{property}}}", jOptions);
type = JsonSerializer.Deserialize<ManagedServiceIdentityType>($"{{{property}}}", jsonContext.ManagedServiceIdentityType);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deserialize here I believe is an internal static we should have access to.

@@ -214,7 +223,7 @@ internal static ManagedServiceIdentity DeserializeManagedServiceIdentity(JsonEle
Dictionary<ResourceIdentifier, UserAssignedIdentity> dictionary = new Dictionary<ResourceIdentifier, UserAssignedIdentity>();
foreach (var property0 in property.Value.EnumerateObject())
{
dictionary.Add(new ResourceIdentifier(property0.Name), JsonSerializer.Deserialize<UserAssignedIdentity>(property0.Value.GetRawText()));
dictionary.Add(new ResourceIdentifier(property0.Name), JsonSerializer.Deserialize<UserAssignedIdentity>(property0.Value.GetRawText(), ManagedServiceIdentityJsonContext.Default.UserAssignedIdentity));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deserialize here I believe is an internal static we should have access to.

@@ -27,7 +28,7 @@ internal void Write(Utf8JsonWriter writer, ModelReaderWriterOptions options, Jso
}

writer.WriteStartObject();
JsonSerializer.Serialize(writer, ManagedServiceIdentityType, jOptions);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@m-nash the problem here is that ManagedServiceIdentityType doesn’t implement IJsonModel. What’s the appropriate fix? Implement manually?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ManagedServiceIdentityType doesn't need to because its an extensible enum. ToString() is the "serialization" and ctor(string) is the "deserialization".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Community Contribution Community members are working on the issue customer-reported Issues that are reported by GitHub users external to the Azure organization. Mgmt This issue is related to a management-plane library.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants