更新框架
This commit is contained in:
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);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user