Razor 每次呼叫 Parse() 都會動態編譯產生一個組件。若解析量大(如迴圈 1000 次),將產生大量動態組件嚴重拖垮效能。
static void Main(string[] args)
{
string cshtml = File.ReadAllText(@"E:\... \HTMLPage1.cshtml");
for (int i = 0; i < 1000; i++)
{
string html = Razor.Parse(cshtml); // 無快取名稱,每次重新編譯
}
// 檢視載入組件數量
Assembly[] asms = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly asm in asms)
Console.WriteLine(asm.FullName + "\r\n");
}
結果:載入大量動態組件,編譯速度極慢。
for (int i = 0; i < 1000; i++)
{
// 使用固定快取名稱 "cc"
Razor.Parse(cshtml, null, "cc");
// 首次編譯後,後續呼叫直接使用快取,速度極快
// 除非 cshtml 內容變更,需變更 cacheName 觸發重新編譯
}
兩種主流做法確保檔案變更時重新編譯:
fullPath + File.GetLastWriteTime(fullPath)for (int i = 0; i < 10; i++)
{
string cshtml = File.ReadAllText(fullPath);
string cacheName = fullPath + File.GetLastWriteTime(fullPath);
string html = Razor.Parse(cshtml, null, cacheName);
Console.WriteLine(html);
Console.ReadKey();
}
測試驗證:修改 cshtml 3 次 → 產生 3 個組件;未修改 → 僅 1 個組件。
反編譯 TemplateService.GetTemplate 發現核心邏輯:
private ITemplate GetTemplate<T>(string razorTemplate, object model, string cacheName)
{
int hashCode = razorTemplate.GetHashCode();
CachedTemplateItem item;
// 第一層檢查:快取名稱是否存在
if (!this._cache.TryGetValue(cacheName, out item)
// 第二層檢查:內容雜湊碼是否一致
|| (item.CachedHashCode != hashCode))
{
// 重新編譯建立新模板類型
Type templateType = this.CreateTemplateType(razorTemplate, ...);
item = new CachedTemplateItem(hashCode, templateType);
this._cache.AddOrUpdate(cacheName, item, ...);
}
return this.CreateTemplate(null, item.TemplateType, model);
}
機制採用 雙重驗證:
即使 cacheName 固定,內容變更導致 HashCode 不同,仍會觸發重新編譯。
雖然不同字串 HashCode 相同機率極低,但理論上存在碰撞可能性:
A、B 兩字串內容不同,但 HashCode 相同 → Parse 執行舊邏輯
cacheName + HashCode 雙重保險 將風險降至理論最小。
public static string ParseRazor(HttpContext context, string virtualPath, object model)
{
string fullPath = context.Server.MapPath(virtualPath);
string cshtml = File.ReadAllText(fullPath);
// 採用「路徑 + 修改時間」策略,平衡效能與準確性
string cacheName = fullPath + File.GetLastWriteTimeUtc(fullPath).Ticks;
return Razor.Parse(cshtml, model, cacheName);
}
GetLastWriteTimeUtc 避免時區問題.Ticks 提供精確到 100 奈秒的時間戳記正確理解並應用 cacheName 機制,是 Razor 引擎高效能運行的關鍵所在。