同步 Handler 每請求佔用一執行緒。高併發、長時間 I/O (資料庫、Web Service、檔案) 會耗盡執行緒池。非同步 Handler 釋放執行緒等待 I/O 完成,再由完成通知繼續處理,大幅提升併發吞吐量。
using System;
using System.Web;
using System.Threading;
public class AsyncHttpHandler : IHttpAsyncHandler
{
public bool IsReusable => false;
// 同步方法不會被呼叫,但必須實作
public void ProcessRequest(HttpContext context)
{
throw new InvalidOperationException("Use async version");
}
// 開始非同步處理
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
context.Response.Write("AsyncHttpHandler Started
");
// 建立實作 IAsyncResult 的狀態物件
var asyncOp = new AsyncOperation(context, cb, extraData);
asyncOp.StartAsyncWork(); // 啟動背景工作
return asyncOp; // 立即回傳,釋放執行緒
}
// 非同步完成時呼叫
public void EndProcessRequest(IAsyncResult result)
{
// 這裡通常不需要寫入回應,因背景工作已寫入
// 若需最終處理可在這裡進行
}
}
using System;
using System.Web;
using System.Threading;
public class AsyncOperation : IAsyncResult
{
private readonly HttpContext _context;
private readonly AsyncCallback _callback;
private readonly object _state;
private bool _completed;
public AsyncOperation(HttpContext context, AsyncCallback callback, object state)
{
_context = context;
_callback = callback;
_state = state;
_completed = false;
}
// IAsyncResult 介面實作
public object AsyncState => _state;
public WaitHandle AsyncWaitHandle => null; // 簡易實作回傳 null
public bool CompletedSynchronously => false;
public bool IsCompleted => _completed;
// 啟動背景工作 (使用 ThreadPool)
public void StartAsyncWork()
{
ThreadPool.QueueUserWorkItem(StartAsyncTask);
}
private void StartAsyncTask(object state)
{
// 模擬耗時 I/O (如資料庫查詢、Web API 呼叫)
Thread.Sleep(2000);
// 直接向 Response 寫入結果 (注意:此時已非原始請求執行緒)
_context.Response.Write($"Completed on ThreadPool: {Thread.CurrentThread.IsThreadPoolThread}
");
_completed = true;
_callback(this); // 通知 ASP.NET 非同步完成,觸發 EndProcessRequest
}
}
<httpHandlers>
<add verb="*" path="*.async" type="AsyncHttpHandler" />
</httpHandlers>
處理常式對應 -> 加入指令碼對應 -> 路徑 *.async -> 執行檔 aspnet_isapi.dll。
瀏覽 https://localhost/YourApp/test.async,頁面先顯示「Started」,2 秒後顯示「Completed on ThreadPool: True」,且期間不阻塞執行緒。
| 概念 | 說明 |
|---|---|
| BeginProcessRequest | 快速啟動非同步工作,立即回傳 IAsyncResult,釋放 IIS 執行緒。 |
| ThreadPool.QueueUserWorkItem | 將工作排入執行緒池,由背景執行緒執行耗時邏輯。 |
| AsyncCallback | 工作完成時呼叫,通知 ASP.NET 執行管線喚醒請求繼續。 |
| EndProcessRequest | 管線喚醒後呼叫,可做最後收尾 (如釋放資源),回應通常已在背景寫入。 |
| IAsyncResult.IsCompleted | 供輪詢查詢進度 (少用),主要靠 Callback 驅動。 |
背景執行緒存取共用資料 (快取、靜態變數) 需加鎖 (lock, Monitor, ConcurrentDictionary) 或使用 WaitHandle (如 ManualResetEvent) 協調。簡易範例中 AsyncWaitHandle 回傳 null,生產環境建議實作完整 WaitHandle 以支援 WaitOne 等待。
ASP.NET Core 內建支援 async/await,Controller Action 直接 public async Task,無需手動實作 IHttpAsyncHandler。若維護舊版 Web Forms,非同步 Handler 仍是提升併發的有效手段。
非同步 HTTP Handler 實作 IHttpAsyncHandler + IAsyncResult,利用 ThreadPool 執行耗時工作,釋放 IIS 執行緒。核心流程:BeginProcessRequest 啟動 -> 背景工作 -> AsyncCallback 通知 -> EndProcessRequest 收尾。適合 I/O 密集型高併發場景。