chore: 首次簽入 Thinkyu ASP.NET 專案
- 加入 Visual Studio / ASP.NET .gitignore - 排除建置輸出、IDE 設定、NuGet packages、大型 MSI 安裝檔
This commit is contained in:
@@ -0,0 +1,328 @@
|
||||
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
|
||||
{
|
||||
// 忽略刪除錯誤
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user