HttpModule 是 ASP.NET 管線中的攔截器,可在請求生命週期的各個階段插入自訂邏輯。本文示範如何建立一個 HttpModule,在 BeginRequest 記錄開始時間、在 EndRequest 計算經過時間並輸出至頁面底部,達到全站監控頁面執行效能的目的。
using System;
using System.Web;
namespace TimerHttpModule
{
public class TimerModule : IHttpModule
{
private DateTime _startTime;
public void Init(HttpApplication application)
{
// 訂閱請求開始與結束事件
application.BeginRequest += OnBeginRequest;
application.EndRequest += OnEndRequest;
}
private void OnBeginRequest(object sender, EventArgs e)
{
_startTime = DateTime.Now;
}
private void OnEndRequest(object sender, EventArgs e)
{
var application = (HttpApplication)sender;
var context = application.Context;
var elapsed = DateTime.Now - _startTime;
// 將執行時間寫入回應串流
context.Response.Write($"頁面執行時間:{elapsed.TotalMilliseconds:F2} ms
");
}
public void Dispose() { }
}
}
IIS 6 / Classic 模式:
<configuration>
<system.web>
<httpModules>
<add name="TimerModule" type="TimerHttpModule.TimerModule" />
</httpModules>
</system.web>
</configuration>
IIS 7+ / Integrated 模式:
<configuration>
<system.webServer>
<modules>
<add name="TimerModule" type="TimerHttpModule.TimerModule" />
</modules>
</system.webServer>
</configuration>
直接在 Response.Write 輸出會影響所有回應,包括:
private void OnEndRequest(object sender, EventArgs e)
{
var app = (HttpApplication)sender;
var ctx = app.Context;
// 僅對 HTML 頁面輸出
if (ctx.Request.Path.EndsWith(".aspx", StringComparison.OrdinalIgnoreCase) &&
ctx.Response.ContentType.Equals("text/html", StringComparison.OrdinalIgnoreCase))
{
var elapsed = DateTime.Now - _startTime;
ctx.Response.Write($"頁面執行時間:{elapsed.TotalMilliseconds:F2} ms
");
}
}
private void OnEndRequest(object sender, EventArgs e)
{
var app = (HttpApplication)sender;
var ctx = app.Context;
var elapsed = DateTime.Now - _startTime;
// 不汙染回應內容,前端可透過 JS 讀取或開發者工具查看
ctx.Response.Headers["X-Page-Execution-Time"] = $"{elapsed.TotalMilliseconds:F2} ms";
}
MiniProfiler 或 Glimpse 進行更詳細的效能分析。