更新框架

This commit is contained in:
chfei committed 2026-10-27 14:35:03 +08:00
1 parent ef50fa0620
commit 84b28f9672
72 files changed
+2222 -282

No files matched your search

@@ -0,0 +1,99 @@
using System.IO;
using Newtonsoft.Json;
using Prism.Mvvm;
using Store.Management.Framework.Configs;
namespace Store.Management.Framework.Services;
public interface ISettingsServiceBase<T> where T : class
{
T Model { get; }
string FilePath { get; }
T GetDefaultModel();
void LoadSettings();
Task LoadSettingsAsync();
void SaveSettings();
Task SaveSettingsAsync();
}
/// <summary>
/// JSON 配置服务。缺失文件保留当前配置,加载失败保留旧模型并抛出异常。
/// 保存通过同目录临时文件替换目标;模型变更应在所属 UI 线程调用。
/// </summary>
public abstract class JsonSettingsServiceBase<T> : BindableBase, ISettingsServiceBase<T> where T : class
{
private readonly SemaphoreSlim _gate = new(1, 1);
private T? _model;
/// <summary>默认按模型类型名保存到用户配置目录,派生类可覆盖文件名或完整路径。</summary>
public virtual string FilePath => FolderConfig.GetSettingsFilePath(typeof(T).Name + ".json");
public abstract T GetDefaultModel();
public T Model
{
get => _model ??= GetDefaultModel() ?? throw new InvalidOperationException("默认配置不能为空。");
protected set
{
ArgumentNullException.ThrowIfNull(value);
SetProperty(ref _model, value);
}
}
public void LoadSettings()
{
T? loaded = LoadModelAsync().GetAwaiter().GetResult();
if (loaded is not null) Model = loaded;
}
public void SaveSettings() => SaveSettingsAsync().GetAwaiter().GetResult();
public async Task LoadSettingsAsync()
{
T? loaded = await LoadModelAsync();
if (loaded is not null) Model = loaded;
}
private async Task<T?> LoadModelAsync()
{
T? loaded = null;
await _gate.WaitAsync().ConfigureAwait(false);
try
{
string path = GetFullPath();
try
{
string json = await File.ReadAllTextAsync(path).ConfigureAwait(false);
loaded = JsonConvert.DeserializeObject<T>(json)
?? throw new JsonSerializationException($"配置文件不能为 null:{path}");
}
catch (FileNotFoundException) { }
catch (DirectoryNotFoundException) { }
}
finally { _gate.Release(); }
return loaded;
}
public async Task SaveSettingsAsync()
{
// 在首次等待前读取模型,避免在后台线程初始化默认模型。
string json = JsonConvert.SerializeObject(Model, Formatting.Indented);
await _gate.WaitAsync().ConfigureAwait(false);
string? temporaryPath = null;
try
{
string path = GetFullPath();
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
temporaryPath = path + "." + Guid.NewGuid().ToString("N") + ".tmp";
await File.WriteAllTextAsync(temporaryPath, json).ConfigureAwait(false);
File.Move(temporaryPath, path, overwrite: true);
}
finally
{
try { if (temporaryPath is not null && File.Exists(temporaryPath)) File.Delete(temporaryPath); }
finally { _gate.Release(); }
}
}
private string GetFullPath()
{
ArgumentException.ThrowIfNullOrWhiteSpace(FilePath);
return Path.GetFullPath(FilePath);
}
}