Files
Ayay/SHH.CameraDashboard/Services/HttpService.cs

119 lines
4.0 KiB
C#
Raw Normal View History

2025-12-30 10:53:02 +08:00
using Newtonsoft.Json;
using System.Diagnostics;
using System.Net.Http;
using System.Text;
namespace SHH.CameraDashboard
{
public static class HttpService
{
// 单例 HttpClient避免端口耗尽
private static readonly HttpClient _client;
// 【关键】日志事件UI层订阅这个事件来显示日志
public static event Action<ApiLogEntry> OnApiLog;
static HttpService()
{
_client = new HttpClient();
// 设置一个合理的超时,避免界面卡死
_client.Timeout = TimeSpan.FromSeconds(5);
}
/// <summary>
/// 泛型 GET 方法
/// </summary>
public static async Task<T> GetAsync<T>(string url)
{
return await ExecuteRequestAsync<T>(new HttpRequestMessage(HttpMethod.Get, url));
}
/// <summary>
/// 泛型 POST 方法
/// </summary>
public static async Task<T> PostAsync<T>(string url, object data)
{
var request = new HttpRequestMessage(HttpMethod.Post, url);
string json = JsonConvert.SerializeObject(data);
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
return await ExecuteRequestAsync<T>(request, json);
}
/// <summary>
/// 专门用于【连通性测试】的方法 (不关心返回值内容,只关心通不通)
/// </summary>
public static async Task<bool> TestConnectionAsync(string url)
{
// 复用核心逻辑,但泛型传 string (忽略结果) 或 object
try
{
await ExecuteRequestAsync<string>(new HttpRequestMessage(HttpMethod.Get, url));
return true;
}
catch
{
return false;
}
}
// --- 核心执行逻辑 ---
private static async Task<T> ExecuteRequestAsync<T>(HttpRequestMessage request, string requestBody = "")
{
// 1. 准备日志对象
var log = new ApiLogEntry
{
Method = request.Method.ToString(),
Url = request.RequestUri.ToString(),
RequestBody = requestBody
};
var sw = Stopwatch.StartNew(); // 开始计时
try
{
// 2. 发起网络请求
var response = await _client.SendAsync(request);
sw.Stop(); // 停止计时
log.DurationMs = sw.ElapsedMilliseconds;
log.StatusCode = (int)response.StatusCode;
// 3. 读取响应内容
string content = await response.Content.ReadAsStringAsync();
log.ResponseBody = content;
if (response.IsSuccessStatusCode)
{
// 如果 T 是 string直接返回内容不反序列化
if (typeof(T) == typeof(string))
return (T)(object)content;
// 反序列化 JSON
return JsonConvert.DeserializeObject<T>(content);
}
else
{
log.ErrorMessage = $"HTTP {response.StatusCode}: {response.ReasonPhrase}";
throw new HttpRequestException(log.ErrorMessage);
}
}
catch (Exception ex)
{
sw.Stop();
if (log.DurationMs == 0) log.DurationMs = sw.ElapsedMilliseconds;
log.StatusCode = 0; // 0 代表网络层面的失败(如断网)
log.ErrorMessage = ex.Message;
log.ResponseBody = ex.ToString(); // 记录堆栈以便排查
throw; // 抛出异常供调用方 UI 处理
}
finally
{
// 4. 【广播日志】无论成功失败,都触发事件
// 使用 Invoke 确保 UI 订阅者能收到
OnApiLog?.Invoke(log);
}
}
}
}