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

119 lines
4.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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);
}
}
}
}