<%@ Application Language="C#" %>
<%@ Import Namespace="System.Timers" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ Import Namespace="System.IO" %>
<script runat="server">
private static Timer _timer;
void Application_Start(object sender, EventArgs e)
{
// 應用程式啟動時啟動排程
_timer = new Timer(60_000); // 60 秒 = 1 分鐘
_timer.Elapsed += OnTimedEvent;
_timer.AutoReset = true; // 週期性觸發
_timer.Enabled = true; // 啟動
}
void Application_End(object sender, EventArgs e)
{
// 應用程式關閉時釋放資源
if (_timer != null)
{
_timer.Stop();
_timer.Dispose();
_timer = null;
}
}
void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
// 記錄未處理例外至 Log/資料庫/EventLog
// LogHelper.Error("Application_Error", ex);
}
void Session_Start(object sender, EventArgs e) { /* 可統計在線人數 */ }
void Session_End(object sender, EventArgs e) { /* 僅 InProc 模式有效 */ }
private void OnTimedEvent(object sender, ElapsedEventArgs e)
{
try
{
// ====== 這裡放入您的排程工作 ======
// 範例:清理 7 天前的暫存檔
string tempPath = Server.MapPath("~/TempFiles");
if (Directory.Exists(tempPath))
{
foreach (var file in Directory.GetFiles(tempPath))
{
FileInfo fi = new FileInfo(file);
if (fi.CreationTime < DateTime.Now.AddDays(-7))
fi.Delete();
}
}
// 範例:呼叫 Web API 同步資料
// using (var client = new HttpClient()) { await client.GetAsync("https://api.example.com/sync"); }
}
catch (Exception ex)
{
// 排程執行緒例外不會自動進入 Application_Error,必須自行捕捉記錄
// LogHelper.Error("Timer_Job_Failed", ex);
}
}
</script>
| 屬性/方法 | 說明 |
|---|---|
Interval | 毫秒單位。範例 60,000 = 1 分鐘。正式專案常設 3600000 (1小時) 或 86400000 (1天)。 |
AutoReset = true | true = 週期性;false = 單次觸發(需自行再次 Start)。 |
Elapsed 事件 | 在背景執行緒(ThreadPool)觸發,**非** ASP.NET 請求執行緒,無 HttpContext、Session、Request 等物件。 |
靜態 _timer | 防止被 GC 回收;Application_End 必須 Dispose() 釋放非受控資源。 |
HttpContext.Current 為 null。需透過 HostingEnvironment.MapPath("~/") 取得實體路徑,或建立獨立 DbContext 連線字串從 ConfigurationManager 讀取。Elapsed 內未 try-catch 會導致 Timer 靜默停止(.NET 4.0+ 預設行為)。務必在方法最外層包 try-catch 並記錄 Log。// Web.config
<add key="JobIntervalMinutes" value="30" />
<add key="JobEnabled" value="true" />
void Application_Start(object sender, EventArgs e)
{
bool enabled = Convert.ToBoolean(ConfigurationManager.AppSettings["JobEnabled"]);
if (!enabled) return;
int minutes = Convert.ToInt32(ConfigurationManager.AppSettings["JobIntervalMinutes"]);
_timer = new Timer(minutes * 60_000);
_timer.Elapsed += OnTimedEvent;
_timer.AutoReset = true;
_timer.Enabled = true;
}
Global.asax + Timer 是最輕量、零相依的 ASP.NET 排程方案,適合**低頻率、非關鍵、單機部署**的簡易背景工作。生產環境若需高可用性、排程視覺化、失敗重試、多節點協調,強烈建議改用 Hangfire(支援 SQL Server/Redis/PostgreSQL 儲存排程狀態、內建 Dashboard、Cron 運算式、延遲/週期/一次性任務),只需幾行程式碼即可平滑遷移。