using System.Text.Json; namespace SHH.CameraSdk { public class FileStorageService : IStorageService { public int ProcessId { get; } private readonly string _baseDir; private readonly string _devicesPath; private readonly SemaphoreSlim _fileLock = new SemaphoreSlim(1, 1); // [关键修复] 配置序列化选项,解决“只存属性不存字段”的问题 private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions { WriteIndented = true, // 格式化 JSON,让人眼可读 IncludeFields = true, // [核心] 允许序列化 public int Id; 这种字段 PropertyNameCaseInsensitive = true, // 忽略大小写差异 NumberHandling = JsonNumberHandling.AllowReadingFromString // 允许 "8000" 读为 int 8000 }; public FileStorageService(int processId) { ProcessId = processId; _baseDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "App_Data", $"Process_{processId}"); _devicesPath = Path.Combine(_baseDir, "devices.json"); if (!Directory.Exists(_baseDir)) Directory.CreateDirectory(_baseDir); Console.WriteLine($"[Storage] 路径: {_devicesPath}"); } public async Task SaveDevicesAsync(IEnumerable configs) { await _fileLock.WaitAsync(); try { // [调试] 打印正在保存的数量,确保 Manager 传过来的数据是对的 // Console.WriteLine($"[Debug] 正在保存 {configs.Count()} 台设备..."); var json = JsonSerializer.Serialize(configs, _jsonOptions); await File.WriteAllTextAsync(_devicesPath, json); // [调试] 打印部分 JSON 内容,验证是否为空对象 "{}" // if (json.Length < 200) Console.WriteLine($"[Debug] JSON 内容: {json}"); } catch (Exception ex) { Console.WriteLine($"[Storage] ❌ 保存配置失败: {ex.Message}"); } finally { _fileLock.Release(); } } public async Task> LoadDevicesAsync() { if (!File.Exists(_devicesPath)) { Console.WriteLine("[Storage] ⚠️ 配置文件不存在,将使用空列表"); return new List(); } await _fileLock.WaitAsync(); try { var json = await File.ReadAllTextAsync(_devicesPath); if (string.IsNullOrWhiteSpace(json)) return new List(); // [调试] 打印读取到的原始 JSON // Console.WriteLine($"[Debug] 读取文件内容: {json.Substring(0, Math.Min(json.Length, 100))}..."); var list = JsonSerializer.Deserialize>(json, _jsonOptions); // 二次校验:如果读出来列表不为空,但 ID 全是 0,说明序列化还是没对上 if (list != null && list.Count > 0 && list[0].Id == 0 && list[0].Port == 0) { Console.WriteLine("[Storage] ⚠️ 警告:读取到设备,但字段似乎为空。请检查 VideoSourceConfig 是否使用了 private 属性?"); } return list ?? new List(); } catch (Exception ex) { Console.WriteLine($"[Storage] ❌ 读取配置失败: {ex.Message}"); // 出错时返回空列表,不要抛出异常,否则 StartAsync 会崩溃 return new List(); } finally { _fileLock.Release(); } } // ================================================================== // 日志部分 (保持空实现以免干扰) // ================================================================== public Task AppendSystemLogAsync(string action, string ip, string path) => Task.CompletedTask; public Task> GetSystemLogsAsync(int count) => Task.FromResult(new List()); public Task AppendDeviceLogAsync(int deviceId, string message) => Task.CompletedTask; public Task> GetDeviceLogsAsync(int deviceId, int count) => Task.FromResult(new List()); } }