-
Notifications
You must be signed in to change notification settings - Fork 1
Add AOT serialization support via configurable JsonSerializerOptions #2
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
base: dev
Are you sure you want to change the base?
Changes from all commits
fef1fd4
fa087bc
6723775
76c7b3a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| # AOT (Ahead-of-Time) 编译支持 | ||
|
|
||
| ## 概述 | ||
|
|
||
| 从版本 2.0.8 开始,XFEExtension.NetCore.AutoConfig 支持 .NET Native AOT 编译。 | ||
|
|
||
| ## 问题背景 | ||
|
|
||
| 在使用 Native AOT 编译时,默认情况下 .NET 会禁用基于反射的 JSON 序列化,这会导致以下错误: | ||
|
|
||
| ``` | ||
| System.InvalidOperationException: Reflection-based serialization has been disabled for this application. | ||
| Either use the source generator APIs or explicitly configure the 'JsonSerializerOptions.TypeInfoResolver' property. | ||
| ``` | ||
|
|
||
| ## 解决方案 | ||
|
|
||
| ### 1. 创建 JsonSerializerContext | ||
|
|
||
| 为您的应用程序创建一个 `JsonSerializerContext`,包含所有需要序列化的类型: | ||
|
|
||
| ```csharp | ||
| using System.Text.Json.Serialization; | ||
| using XFEExtension.NetCore.AutoConfig; | ||
|
|
||
| namespace YourApp; | ||
|
|
||
| [JsonSerializable(typeof(YourDataType))] | ||
| [JsonSerializable(typeof(ProfileList<YourDataType>))] | ||
| [JsonSerializable(typeof(string))] | ||
| [JsonSerializable(typeof(int))] | ||
| [JsonSerializable(typeof(bool))] | ||
| [JsonSerializable(typeof(DateTime))] | ||
| // 添加其他您需要序列化的类型 | ||
| public partial class AppJsonContext : JsonSerializerContext | ||
| { | ||
| } | ||
| ``` | ||
|
|
||
| ### 2. 配置 JsonSerializerOptions | ||
|
|
||
| 在程序启动时配置 `XFEProfile.JsonOptions`: | ||
|
|
||
| ```csharp | ||
| using System.Text.Json; | ||
| using XFEExtension.NetCore.AutoConfig; | ||
|
|
||
| // 在 Main 方法或启动代码中 | ||
| XFEProfile.JsonOptions = new JsonSerializerOptions | ||
| { | ||
| TypeInfoResolver = AppJsonContext.Default | ||
| }; | ||
| ``` | ||
|
|
||
| ### 3. 项目配置 | ||
|
|
||
| 在您的 `.csproj` 文件中启用 AOT: | ||
|
|
||
| ```xml | ||
| <PropertyGroup> | ||
| <PublishAot>true</PublishAot> | ||
| </PropertyGroup> | ||
| ``` | ||
|
|
||
| **注意**:不再需要 `<JsonSerializerIsReflectionEnabledByDefault>true</JsonSerializerIsReflectionEnabledByDefault>` 设置。 | ||
|
|
||
| ## 完整示例 | ||
|
|
||
| 参考 `AutoConfig.Analyzer.Test` 项目中的示例: | ||
|
|
||
| 1. `ProfileJsonContext.cs` - JsonSerializerContext 定义 | ||
| 2. `Program.cs` - JsonOptions 配置示例 | ||
|
|
||
| ## 常见问题 | ||
|
|
||
| ### Q: 我需要为每个类型都添加 JsonSerializable 属性吗? | ||
|
|
||
| A: 是的,所有在配置文件中使用的类型都需要添加。包括: | ||
| - 配置文件中的数据类型 | ||
| - 泛型类型(如 `ProfileList<T>`) | ||
| - 基础类型(string, int, bool, DateTime 等) | ||
|
|
||
| ### Q: 如果我不使用 AOT 编译,还需要配置 JsonOptions 吗? | ||
|
|
||
| A: 不需要。如果不使用 AOT,库会使用默认的反射序列化,无需额外配置。 | ||
|
|
||
| ### Q: 我可以在运行时更改 JsonOptions 吗? | ||
|
|
||
| A: 可以,但建议在应用程序启动时配置一次,避免在使用过程中修改。 | ||
|
|
||
| ## 技术细节 | ||
|
|
||
| - `XFEProfile.JsonOptions` 是一个静态属性,所有配置文件实例共享 | ||
| - 所有 JSON 序列化操作(`JsonSerializer.Serialize` 和 `JsonSerializer.Deserialize`)都使用此选项 | ||
| - 支持的序列化模式:XFEDictionary(默认)、JSON、XML | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| using System.Text.Json.Serialization; | ||
| using XFEExtension.NetCore.AutoConfig; | ||
|
|
||
| namespace XFEExtension.NetCore.XUnit.Test; | ||
|
|
||
| /// <summary> | ||
| /// JSON序列化上下文,用于AOT编译支持 | ||
| /// </summary> | ||
| [JsonSerializable(typeof(UserInfo))] | ||
| [JsonSerializable(typeof(ProfileList<UserInfo>))] | ||
| [JsonSerializable(typeof(List<UserInfo>))] | ||
| [JsonSerializable(typeof(string))] | ||
| [JsonSerializable(typeof(int))] | ||
| [JsonSerializable(typeof(bool))] | ||
| [JsonSerializable(typeof(DateTime))] | ||
| [JsonSerializable(typeof(Guid))] | ||
| public partial class ProfileJsonContext : JsonSerializerContext | ||
| { | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -13,6 +13,10 @@ public abstract class XFEProfile | |||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| private string id = Guid.NewGuid().ToString(); | ||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||
| /// JSON序列化选项,用于配置序列化行为(支持AOT) | ||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||
| public static JsonSerializerOptions JsonOptions { get; set; } = new JsonSerializerOptions(); | ||||||||||||||||||||||||||||
|
Comment on lines
15
to
+18
|
||||||||||||||||||||||||||||
| /// <summary> | |
| /// JSON序列化选项,用于配置序列化行为(支持AOT) | |
| /// </summary> | |
| public static JsonSerializerOptions JsonOptions { get; set; } = new JsonSerializerOptions(); | |
| private static JsonSerializerOptions jsonOptions = new JsonSerializerOptions(); | |
| /// <summary> | |
| /// JSON序列化选项,用于配置序列化行为(支持AOT) | |
| /// </summary> | |
| public static JsonSerializerOptions JsonOptions | |
| { | |
| get => jsonOptions; | |
| set => jsonOptions = value ?? throw new ArgumentNullException(nameof(value)); | |
| } |
Copilot
AI
Apr 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
XFEDictionarySaveProfileOperation currently serializes values via JsonSerializer.Serialize(property.Value(), JsonOptions). Because property.Value() is object?, this calls the Serialize<object> overload and uses metadata for object, which will not pick up source-generated metadata for the actual runtime type—breaking AOT even when JsonOptions.TypeInfoResolver is configured. Use the overload that supplies the declared type (e.g., look up propertyInfoDictionary[property.Key] and call Serialize(value, declaredType, JsonOptions)), with a safe fallback if the type is missing.
| saveProfileDictionary.Add(property.Key, JsonSerializer.Serialize(property.Value(), JsonOptions)); | |
| { | |
| var value = property.Value(); | |
| if (propertyInfoDictionary.TryGetValue(property.Key, out var declaredType)) | |
| saveProfileDictionary.Add(property.Key, JsonSerializer.Serialize(value, declaredType, JsonOptions)); | |
| else | |
| saveProfileDictionary.Add(property.Key, JsonSerializer.Serialize(value, JsonOptions)); | |
| } |
Copilot
AI
Apr 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The obsolete SaveProfilesFunc still serializes using JsonSerializer.Serialize(fieldInfo.GetValue(i), JsonOptions) / Serialize(propertyInfo.GetValue(i), JsonOptions), which again routes through the Serialize<object> overload and won’t use source-generated metadata for the member’s declared type in AOT. Prefer the overload that provides the member type (e.g., Serialize(value, fieldInfo.FieldType, JsonOptions) / Serialize(value, propertyInfo.PropertyType, JsonOptions)).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The doc claims AOT support is available “从版本 2.0.8 开始”, but the library project currently declares
<Version>2.0.7</Version>inXFEExtension.NetCore.AutoConfig.csproj. Please align the documented version with the actual release/versioning plan (or bump the package version accordingly).