329 lines
10 KiB
C#
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
|
|
{
|
|
// 忽略刪除錯誤
|
|
}
|
|
}
|
|
}
|
|
}
|