namespace SHH.CameraDashboard; public partial class CameraRepository { #region GetListByAddressAsync 获取摄像头列表 /// /// [新增] 动态检测方法。 /// 专门用于向导界面,根据临时输入的 IP 地址和端口号来获取摄像头列表。 /// /// 目标服务器的 IP 地址。 /// 目标服务器的端口号。 /// 调用此方法的页面或步骤名称,用于日志记录。 /// /// 一个异步任务,其结果包含一个 对象的列表。 /// - 如果成功获取到列表,返回该列表(可能为空)。 /// - 如果获取过程中发生任何异常(如网络错误、服务器无响应等),返回 null。 /// public async Task?> GetListByAddressAsync(string ipAddress, string port, string pageName) { // 1. 统一管理并拼接请求 URL // 在这里将基础地址与 API 路径组合,ViewModel 无需关心具体的路由细节。 // WebApiRoutes.Cameras.Root 是一个假设的常量,例如 "/api/Cameras"。 string requestUrl = $"http://{ipAddress}:{port}{WebApiRoutes.Cameras.Root}"; try { // 2. 调用底层的 WebApiService 发送 GET 请求 // 传入 "Wizard" 相关的模块名,便于在日志中区分请求来源。 string jsonResponse = await WebApiService.Instance.GetAsync(requestUrl, moduleName: $"摄像头列表-{pageName}", default, true); // 3. 使用 JsonHelper 进行反序列化 // 利用 JsonHelper 的防御性实现,即使 JSON 格式错误或内容为 "null",也不会抛出异常。 var cameraList = JsonHelper.Deserialize>(jsonResponse); // 4. 确保返回的列表不为 null // 如果反序列化结果为 null(例如,API 返回 "null"),则返回一个空列表, // 这样调用方可以安全地遍历,而无需进行 null 检查。 return cameraList ?? new List(); } catch (Exception) { // 5. 捕获所有异常 // 在动态检测阶段,网络不通、服务器宕机等都是预期内的情况。 // 返回 null 作为明确的失败信号,ViewModel 可以据此向用户显示“连接失败”等提示。 return null; } } #endregion #region ControlPowerAsync 摄像头启停 /// /// 调用服务端的接口来控制指定摄像头的启停状态(开机/关机)。 /// /// 目标服务器的 IP 地址。 /// 目标服务器的端口号。 /// 要控制的摄像头的唯一ID。 /// true 表示开机,false 表示关机。 /// 调用此方法的页面或功能名称,用于日志记录。 /// /// 一个异步任务,其结果为一个布尔值: /// - true:表示操作成功(HTTP 响应为 200 OK)。 /// - false:表示操作失败(如网络错误、服务器返回 4xx/5xx 错误等)。 /// public async Task ControlPowerAsync(long cameraId, bool enable, string pageName) { var useServiceNode = AppGlobal.UseServiceNode; if (useServiceNode == null) return false; var ipAddress = useServiceNode.ServiceNodeIp; var port = useServiceNode.ServiceNodePort; // 1. 拼接请求 URL // 将控制参数(cameraId 和 enable)作为 URL 的一部分发送。 string requestUrl = $"http://{ipAddress}:{port}/api/Cameras/{cameraId}/power?enabled={enable}"; try { // 2. 调用底层服务发送 POST 请求 // 关键点: // a. 即使服务端不关心请求体(Body),`PostAsync` 方法也要求一个非 null 的 JSON 字符串。 // 因此,我们传入一个空的 JSON 对象 "{}" 作为占位符。 // b. 我们不检查响应内容,因为如果请求失败(例如,服务器返回 404 Not Found 或 500 Internal Server Error), // `WebApiService` 会抛出异常。 await WebApiService.Instance.PostAsync(requestUrl, "{}", moduleName: $"设备启停-{pageName}"); // 3. 如果代码执行到这里,说明请求成功且没有抛出异常。 return true; } catch (Exception ex) { // 4. 捕获所有可能发生的异常 // 这包括网络连接问题、DNS解析失败、服务器无响应或返回错误状态码等。 // 记录异常信息到调试输出,以便于排查问题。 System.Diagnostics.Debug.WriteLine($"控制摄像头电源失败 [IP: {ipAddress}, CameraId: {cameraId}]: {ex.Message}"); // 返回 false 通知调用方操作已失败。 return false; } } #endregion }