Console App 正常的雙工呼叫,移植至 WinForms 後,點擊按鈕觸發服務呼叫,UI 凍結約 1 分鐘後拋出 TimeoutException,但回呼訊息 (MessageBox) 卻已正常顯示。


Add(x,y) Request → Service。DisplayResult Request → Client 回呼端點。回呼訊息之所以能顯示,是因 WCF 在不同 IO 執行緒處理傳入 Request,但 Reply 無法送出導致服務端超時。
將服務呼叫移至背景執行緒,UI 執行緒保持自由處理回呼:
private void buttonCalculate_Click(object sender, EventArgs e)
{
// ... 參數驗證 ...
var thread = new Thread(() => _calculator.Add(_op1, _op2));
thread.Start(); // 立即返回,UI 不阻塞
}
驗證通過:無 Timeout,回呼正常執行。
若業務不需同步回傳值,將雙向 Operation 全標記 IsOneWay=true,消除 Reply 等待:
[ServiceContract(CallbackContract = typeof(ICalculatorCallback))]
public interface IDuplexCalculator
{
[OperationContract(IsOneWay = true)] void Add(double x, double y);
}
public interface ICalculatorCallback
{
[OperationContract(IsOneWay = true)] void ShowResult(double x, double y, double result);
}
訊息流程變為單向火箭彈:

驗證通過:無 Timeout,效能最佳。
若 UI 執行緒確實阻塞,為何回呼 ShowResult 仍能執行並顯示 MessageBox?推測 WCF IO 執行緒池獨立處理傳入 Request,但無法發送 Reply 導致服務端超時。歡迎專家補充底層機制細節。
| 方案 | 適用場景 | 優點 | 缺點 |
|---|---|---|---|
| 背景執行緒 | 需保留 Request/Reply 語意、回呼需同步處理 | 改動最小、相容現有 Contract | 需注意跨執行緒 UI 更新 (Invoke) |
| 全 One-way | 純通知/事件模式、無同步回傳需求 | 零死鎖風險、效能最高、架構最清晰 | 失去同步回傳能力、需業務配合 |
WinForms/WPF 呼叫雙工服務 務必避免在 UI 執行緒同步等待,否則必遭死鎖。