WebService.instructions.md
從 Google Drive .github/instructions/WebService.instructions.md 匯入
共用指令內容
使用中---
applyTo: '**/*'
---
WebService (ASMX) 開發規範
1. 檔案結構 (File Structure)
- 標記檔案 (
.asmx):
- 位置: 應放置於專案根目錄下的 WS/ 資料夾 (例如: /WS/UserWS.asmx)。
- 內容: 只能包含一行 @ WebService 指示詞,用於連結後置程式碼。
- 程式碼後置檔案 (
.cs):
- 位置: 必須放置於 /App_Code/WS/ 資料夾 (例如: /App_Code/WS/UserWS.cs)。
- 內容: 包含 WebService 類別的完整 C# 實作。
2. 核心規則
CodeBehind路徑:.asmx檔案中的CodeBehind屬性必須正確指向App_Code/WS/中的對應.cs檔案 (例如~/App_Code/WS/UserWS.cs)。Class名稱:Class屬性必須與.cs檔案中的類別名稱完全相符。- 職責: WebService 作為 API 的進入點,其職責是接收前端請求、呼叫 BLL 處理業務邏輯,並將結果回傳。
- 無業務邏輯: WebService 不應包含任何業務邏輯,所有邏輯都應封裝在 BLL 層。
3. 程式碼範例
範例 A:標記檔案 (/WS/UserWS.asmx)
<%@ WebService Language="C#" CodeBehind="~/App_Code/WS/UserWS.cs" Class="UserWS" %>
範例 B:程式碼後置檔案 (/App_Code/WS/UserWS.cs)
using System.Collections.Generic;
using System.Web.Services;
[WebService(Namespace = "[http://tempuri.org/](http://tempuri.org/)")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class UserWS : WebService
{
[WebMethod(Description = "取得所有使用者")]
public List<DtoUser> GetAllUsers()
{
BizUser _bizUser = new BizUser();
return _bizUser.GetAllUsers();
}
}
---
4. ⚠️ EnableSession 強制規範
> 教訓來源:2026-04 實際踩坑
> 未加 EnableSession = true 時,Session 屬性回傳 null,導致 BaseWebService.CurrEmpInfo 拋出 NullReferenceException,整支 WebMethod 失效。
4.1 規則
所有存取 Session(包括透過 BaseWebService 的 Useright / UserightAlternative / CurrEmpInfo 屬性)的 [WebMethod],必須明確加上 EnableSession = true:
// ✅ 正確
[WebMethod(Description = "儲存資料", EnableSession = true)]
public String SaveData(...)
// ❌ 錯誤:遺漏 EnableSession,Session == null → NullReferenceException
[WebMethod(Description = "儲存資料")]
public String SaveData(...)
4.2 完整 WebMethod 範本
[WebMethod(Description = "儲存 XXX 資料", EnableSession = true)]
public String SaveXxx(Decimal id, String name, Int32 isActive)
{
try
{
// ✅ Useright 檢查必須在 try 區塊內,且為第一行
if (!Useright) return JsonConvert.SerializeObject(new { success = false, message = "無權限" });
DtoXxx dto = new DtoXxx
{
Id = id,
Name = name ?? String.Empty,
IsActive = isActive,
DataOp = CurrEmpInfo != null ? CurrEmpInfo.EmpID : String.Empty
};
BizXxx biz = new BizXxx();
Boolean ok = biz.Save(dto);
return JsonConvert.SerializeObject(new { success = ok });
}
catch (Exception ex)
{
CHMC.Log.WriteLog(ex);
return JsonConvert.SerializeObject(new { success = false, message = "系統發生錯誤,請稍後再試" });
}
}
---
5. ⚠️ Useright 實作規範
> 教訓來源:2026-04 實際踩坑
> Useright 原先呼叫 BizPermission.IsQuery(EmpID, "/Index.aspx"),查詢 PMS 資料庫中的 APUrl。
> 但若該 URL 未在 PMS 系統中登錄,IsQuery 永遠回傳 false → 所有 WebMethod 都回傳「無權限」。
5.1 規則
WS 層的 Useright 只驗證「Session 內有有效員工資訊」,不呼叫 BizPermission.IsQuery()。
原因:
1. BizPermission.IsQuery() 依賴 PMS 資料庫中登錄的 APUrl 紀錄,容易因設定不一致造成永遠 false
2. 頁面層級的細部權限已由 BasePage.CheckAuthorization 把關
3. 進入後台頁面本身就已完成 SSO 驗證,WebMethod 只需確認 Session 合法即可
5.2 正確的 BaseWebService.Useright 實作
// ✅ BaseWebService.cs 中正確的 Useright 實作
protected Boolean Useright
{
get
{
// 只驗證登入狀態,不查 PMS 資料庫
return (CurrEmpInfo != null && !String.IsNullOrEmpty(CurrEmpInfo.EmpID));
}
}
5.3 Useright 必須在 try 區塊內
// ✅ 正確:Useright 在 try 內,避免 BizPermission 例外逸出
public String SaveXxx(...)
{
try
{
if (!Useright) return JsonConvert.SerializeObject(new { success = false, message = "無權限" });
// ... 業務邏輯
}
catch (Exception ex) { ... }
}
// ❌ 錯誤:Useright 在 try 外,任何例外都會變成未捕獲例外
public String SaveXxx(...)
{
if (!Useright) return JsonConvert.SerializeObject(new { success = false, message = "無權限" });
try { ... }
catch (Exception ex) { ... }
}