mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-04 18:26:39 +02:00
[AOT] Refactor SettingsLib/SettingsUI for Native AOT compatibility (#42644)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Key Changes: 1. Settings.UI.Library: - Added SettingsSerializationContext.cs with comprehensive JsonSerializable attributes for all settings types - Updated BasePTModuleSettings.ToJsonString() to use AOT-compatible serialization - Updated SettingsUtils.GetFile<T>() to use AOT-compatible deserialization - Modified all ToString() methods in Properties classes to use SettingsSerializationContext - Converted struct fields to properties in SunTimes and MouseWithoutBordersProperties for serialization compatibility 2. Settings.UI: - Fixed namespace alias in SourceGenerationContextContext.cs to avoid conflicts For any future developers who discover incorrect settings resolution, please follow up my changes to add your setting type into JsonSerilizerContext. <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [ ] Closes: #xxx - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed, or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Co-authored-by: Yu Leng <yuleng@microsoft.com>
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
@@ -18,27 +20,28 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
private const string DefaultModuleName = "";
|
||||
private readonly IFile _file;
|
||||
private readonly ISettingsPath _settingsPath;
|
||||
|
||||
private static readonly JsonSerializerOptions _serializerOptions = new JsonSerializerOptions
|
||||
{
|
||||
MaxDepth = 0,
|
||||
IncludeFields = true,
|
||||
};
|
||||
private readonly JsonSerializerOptions _serializerOptions;
|
||||
|
||||
public SettingsUtils()
|
||||
: this(new FileSystem())
|
||||
{
|
||||
}
|
||||
|
||||
public SettingsUtils(IFileSystem fileSystem)
|
||||
: this(fileSystem?.File, new SettingPath(fileSystem?.Directory, fileSystem?.Path))
|
||||
public SettingsUtils(IFileSystem? fileSystem, JsonSerializerOptions? serializerOptions = null)
|
||||
: this(fileSystem?.File!, new SettingPath(fileSystem?.Directory, fileSystem?.Path), serializerOptions)
|
||||
{
|
||||
}
|
||||
|
||||
public SettingsUtils(IFile file, ISettingsPath settingPath)
|
||||
public SettingsUtils(IFile file, ISettingsPath settingPath, JsonSerializerOptions? serializerOptions = null)
|
||||
{
|
||||
_file = file ?? throw new ArgumentNullException(nameof(file));
|
||||
_settingsPath = settingPath;
|
||||
_serializerOptions = serializerOptions ?? new JsonSerializerOptions
|
||||
{
|
||||
MaxDepth = 0,
|
||||
IncludeFields = true,
|
||||
TypeInfoResolver = SettingsSerializationContext.Default,
|
||||
};
|
||||
}
|
||||
|
||||
public bool SettingsExists(string powertoy = DefaultModuleName, string fileName = DefaultFileName)
|
||||
@@ -108,7 +111,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
/// This function creates a file in the powertoy folder if it does not exist and returns an object with default properties.
|
||||
/// </summary>
|
||||
/// <returns>Deserialized json settings object.</returns>
|
||||
public T GetSettingsOrDefault<T, T2>(string powertoy = DefaultModuleName, string fileName = DefaultFileName, Func<object, object> settingsUpgrader = null)
|
||||
public T GetSettingsOrDefault<T, T2>(string powertoy = DefaultModuleName, string fileName = DefaultFileName, Func<object, object>? settingsUpgrader = null)
|
||||
where T : ISettingsConfig, new()
|
||||
where T2 : ISettingsConfig, new()
|
||||
{
|
||||
@@ -128,7 +131,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
try
|
||||
{
|
||||
T2 oldSettings = GetSettings<T2>(powertoy, fileName);
|
||||
T newSettings = (T)settingsUpgrader(oldSettings);
|
||||
T newSettings = (T)settingsUpgrader!(oldSettings);
|
||||
Logger.LogInfo($"Settings file {fileName} for {powertoy} was read successfully in the old format.");
|
||||
|
||||
// If the file needs to be modified, to save the new configurations accordingly.
|
||||
@@ -156,7 +159,22 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
return newSettingsItem;
|
||||
}
|
||||
|
||||
// Given the powerToy folder name and filename to be accessed, this function deserializes and returns the file.
|
||||
/// <summary>
|
||||
/// Deserializes settings from a JSON file.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The settings type to deserialize. Must be registered in <see cref="SettingsSerializationContext"/>.</typeparam>
|
||||
/// <param name="powertoyFolderName">The PowerToy module folder name.</param>
|
||||
/// <param name="fileName">The settings file name.</param>
|
||||
/// <returns>Deserialized settings object of type T.</returns>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown when type T is not registered in <see cref="SettingsSerializationContext"/>.
|
||||
/// All settings types must be registered with <c>[JsonSerializable(typeof(T))]</c> attribute
|
||||
/// for Native AOT compatibility.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// This method uses Native AOT-compatible JSON deserialization. Type T must be registered
|
||||
/// in <see cref="SettingsSerializationContext"/> before calling this method.
|
||||
/// </remarks>
|
||||
private T GetFile<T>(string powertoyFolderName = DefaultModuleName, string fileName = DefaultFileName)
|
||||
{
|
||||
// Adding Trim('\0') to overcome possible NTFS file corruption.
|
||||
@@ -165,8 +183,16 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
// The file itself did write the content correctly but something is off with the actual end of the file, hence the 0x00 bug
|
||||
var jsonSettingsString = _file.ReadAllText(_settingsPath.GetSettingsPath(powertoyFolderName, fileName)).Trim('\0');
|
||||
|
||||
var options = _serializerOptions;
|
||||
return JsonSerializer.Deserialize<T>(jsonSettingsString, options);
|
||||
// For Native AOT compatibility, get JsonTypeInfo from the TypeInfoResolver
|
||||
var typeInfo = _serializerOptions.TypeInfoResolver?.GetTypeInfo(typeof(T), _serializerOptions);
|
||||
|
||||
if (typeInfo == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Type {typeof(T).FullName} is not registered in SettingsSerializationContext. Please add it to the [JsonSerializable] attributes.");
|
||||
}
|
||||
|
||||
// Use AOT-friendly deserialization
|
||||
return (T)JsonSerializer.Deserialize(jsonSettingsString, typeInfo)!;
|
||||
}
|
||||
|
||||
// Save settings to a json file.
|
||||
|
||||
Reference in New Issue
Block a user