Files
sryang 577060bc78 chore: 首次簽入 Thinkyu ASP.NET 專案
- 加入 Visual Studio / ASP.NET .gitignore
- 排除建置輸出、IDE 設定、NuGet packages、大型 MSI 安裝檔
2026-09-10 09:42:37 +08:00

329 lines
10 KiB
C#

using Newtonsoft.Json;
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using 報到系統客戶端.Models;
namespace 報到系統客戶端.Services
{
/// <summary>
/// API 服務基礎類別
/// 處理 HTTP 請求、Session cookie、錯誤處理
/// </summary>
public class ApiService
{
private static ApiService _instance;
private static readonly object _lockObject = new object();
private string _baseUrl;
private CookieContainer _cookieContainer;
// 用於儲存 cookie 的檔案路徑
private string _cookiePath;
public static JsonSerializerSettings jsonConvertSettings = new JsonSerializerSettings { DateTimeZoneHandling = DateTimeZoneHandling.Local };
public static object DeserializeObject(string value)
{
return JsonConvert.DeserializeObject(value, jsonConvertSettings);
}
public static T DeserializeObject<T>(string value)
{
return (T)JsonConvert.DeserializeObject(value, typeof(T), jsonConvertSettings);
}
/// <summary>
/// 取得單例實例
/// </summary>
public static ApiService Instance
{
get
{
if (_instance == null)
{
lock (_lockObject)
{
if (_instance == null)
{
_instance = new ApiService();
}
}
}
return _instance;
}
}
private ApiService()
{
// 從設定檔讀取基底 URL
_baseUrl = ConfigService.Instance.GetApiBaseUrl();
if (string.IsNullOrWhiteSpace(_baseUrl))
{
_baseUrl = "http://localhost:58792";
}
// 初始化 Cookie 容器
_cookieContainer = new CookieContainer();
_cookiePath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"報到系統客戶端",
"cookies.txt"
);
// 嘗試載入已儲存的 Cookie
LoadCookies();
}
/// <summary>
/// 設定基底 URL
/// </summary>
public string BaseUrl
{
set
{
_baseUrl = value;
}
get
{
return _baseUrl;
}
}
/// <summary>
/// 執行 POST 請求
/// </summary>
public async Task<BaseResponse> PostAsync(string servicePath, string methodName, object parameters)
{
try
{
string url = $"{_baseUrl}{servicePath}/{methodName}";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "application/json; charset=utf-8";
request.CookieContainer = _cookieContainer;
request.KeepAlive = true;
// 序列化參數
string jsonData = JsonConvert.SerializeObject(parameters ?? new { });
// 寫入請求體
byte[] data = Encoding.UTF8.GetBytes(jsonData);
request.ContentLength = data.Length;
using (Stream requestStream = request.GetRequestStream())
{
await requestStream.WriteAsync(data, 0, data.Length);
}
// 取得回應
using (HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync())
{
// 更新 Cookie(用於 Session 管理)
_cookieContainer.Add(response.ResponseUri, response.Cookies);
SaveCookies();
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
string responseJson = await reader.ReadToEndAsync();
// 解析回應
dynamic result = DeserializeObject(responseJson);
// ASP.NET Web Service 會將結果包在 "d" 屬性中
if (result.d != null)
{
string dataJson = JsonConvert.SerializeObject(result.d);
return DeserializeObject<BaseResponse>(dataJson);
}
else
{
return DeserializeObject<BaseResponse>(responseJson);
}
}
}
}
catch (WebException ex)
{
return new BaseResponse
{
Success = false,
Message = $"網路錯誤: {ex.Message}"
};
}
catch (Exception ex)
{
return new BaseResponse
{
Success = false,
Message = $"錯誤: {ex.Message}"
};
}
}
/// <summary>
/// 同步版本的 POST 請求(用於向後相容)
/// </summary>
public BaseResponse Post(string servicePath, string methodName, object parameters)
{
try
{
string url = $"{_baseUrl}{servicePath}/{methodName}";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "application/json; charset=utf-8";
request.CookieContainer = _cookieContainer;
request.KeepAlive = true;
// 序列化參數
string jsonData = JsonConvert.SerializeObject(parameters ?? new { });
// 寫入請求體
byte[] data = Encoding.UTF8.GetBytes(jsonData);
request.ContentLength = data.Length;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(data, 0, data.Length);
}
// 取得回應
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
// 更新 Cookie(用於 Session 管理)
_cookieContainer.Add(response.ResponseUri, response.Cookies);
SaveCookies();
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
string responseJson = reader.ReadToEnd();
// 解析回應
dynamic result = DeserializeObject(responseJson);
// ASP.NET Web Service 會將結果包在 "d" 屬性中
if (result.d != null)
{
string dataJson = JsonConvert.SerializeObject(result.d);
return DeserializeObject<BaseResponse>(dataJson);
}
else
{
return DeserializeObject<BaseResponse>(responseJson);
}
}
}
}
catch (WebException ex)
{
return new BaseResponse
{
Success = false,
Message = $"網路錯誤: {ex.Message}"
};
}
catch (Exception ex)
{
return new BaseResponse
{
Success = false,
Message = $"錯誤: {ex.Message}"
};
}
}
/// <summary>
/// 清除所有 Session cookie
/// </summary>
public void ClearSession()
{
_cookieContainer = new CookieContainer();
DeleteCookies();
}
/// <summary>
/// 儲存 Cookie 到檔案
/// </summary>
private void SaveCookies()
{
try
{
string directory = Path.GetDirectoryName(_cookiePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
using (StreamWriter sw = new StreamWriter(_cookiePath, false, Encoding.UTF8))
{
foreach (Cookie cookie in _cookieContainer.GetCookies(new Uri(_baseUrl)))
{
sw.WriteLine($"{cookie.Name}={cookie.Value}");
}
}
}
catch
{
// 忽略儲存錯誤
}
}
/// <summary>
/// 從檔案載入 Cookie
/// </summary>
private void LoadCookies()
{
try
{
if (File.Exists(_cookiePath))
{
using (StreamReader sr = new StreamReader(_cookiePath, Encoding.UTF8))
{
string line;
while ((line = sr.ReadLine()) != null)
{
if (string.IsNullOrWhiteSpace(line)) continue;
string[] parts = line.Split(new[] { '=' }, 2);
if (parts.Length == 2)
{
Cookie cookie = new Cookie(parts[0], parts[1])
{
Path = "/",
HttpOnly = true
};
_cookieContainer.Add(new Uri(_baseUrl), cookie);
}
}
}
}
}
catch
{
// 忽略載入錯誤
}
}
/// <summary>
/// 刪除儲存的 Cookie 檔案
/// </summary>
private void DeleteCookies()
{
try
{
if (File.Exists(_cookiePath))
{
File.Delete(_cookiePath);
}
}
catch
{
// 忽略刪除錯誤
}
}
}
}