首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> .NET 實例教學

ASP.NET MVC 路由偵錯神器 RouteMonitor.dll 原理碼深度剖析

     編輯:.NET 實例教學

背景:為什麼需要路由偵錯?

ASP.NET MVC 專案啟動時在 Application_Start 註冊路由規則:

protected void Application_Start() {
    RegisterRoutes(RouteTable.Routes);
}

隨著規則增多,URL 與 Controller/Action 的對應關係難以直觀掌握。RouteMonitor.dll 提供一個視覺化頁面,輸入任意 URL 即可即時顯示匹配結果、路由資料、所有已註冊路由的匹配狀態。

接入方式

protected void Application_Start() {
    RegisterRoutes(RouteTable.Routes);
    RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes); // 關鍵一行
}

核心類別架構

RouteMonitor.dll 類別圖

  • RouteDebugger:靜態進入點,重寫路由集合
  • DebugRoute:捕獲所有未匹配 URL 的單例路由
  • DebugRouteHandler:自定義 IRouteHandler,轉交給 DebugHttpHandler
  • DebugHttpHandler:實作 IHttpHandler,產出偵錯頁面 HTML

關鍵流程逐步解析

1. RouteDebugger.RewriteRoutesForTesting()

public static void RewriteRoutesForTesting(RouteCollection routes) {
    using (routes.GetReadLock()) { // 多執行緒安全讀取鎖
        bool hasDebugRoute = false;
        foreach (RouteBase baseRoute in routes) {
            Route route = baseRoute as Route;
            if (route != null) {
                // 將所有現有路由的 Handler 替換為 DebugRouteHandler
                route.RouteHandler = new DebugRouteHandler();
            }
            if (route == DebugRoute.Singleton) hasDebugRoute = true;
        }
        // 確保 DebugRoute 位於集合末尾(捕獲所有落網之魚)
        if (!hasDebugRoute) routes.Add(DebugRoute.Singleton);
    }
}
  • routes.GetReadLock() 使用 ReaderWriterLock 實現多執行緒同步,讀取時允許並發,寫入時獨佔。
  • 替換 RouteHandler 使所有路由最終都交由 DebugHttpHandler 處理。
  • DebugRoute 以 {*catchall} 模式匹配任意 URL,確保無匹配時也能進入偵錯頁面。

2. DebugRouteHandler → DebugHttpHandler

public class DebugRouteHandler : IRouteHandler {
    public IHttpHandler GetHttpHandler(RequestContext requestContext) {
        var handler = new DebugHttpHandler();
        handler.RequestContext = requestContext;
        return handler;
    }
}

將 RequestContext 傳遞給 Handler,保留完整路由上下文。

3. DebugHttpHandler.ProcessRequest() 核心邏輯

  1. 取得當前匹配路由資料:RequestContext.RouteData 包含 Values (URL 參數)、DataTokens、Route 物件。
  2. 遍歷所有已註冊路由:呼叫 RouteBase.GetRouteData() 判斷每條路由是否匹配當前請求。
  3. 收集顯示資訊:
    • 匹配狀態 (True/False)
    • URL 模式
    • Defaults、Constraints、DataTokens 字典內容
  4. 判斷是否為 DebugRoute 捕獲:若 RouteData.Route is DebugRoute → 顯示 NO MATCH!。
  5. 輸出 HTML 表格:使用字串格式化組合完整偵錯頁面。
// 核心片段
foreach (RouteBase baseRoute in RouteTable.Routes) {
    bool matched = baseRoute.GetRouteData(RequestContext.HttpContext) != null;
    string statusHtml = $"{matched}";
    // ... 格式化各屬性 ...
    allRoutesHtml += $"{statusHtml}{url}{defaults}{constraints}{dataTokens}";
}
// 最後 Response.Write 完整 HTML

4. 輔助方法:FormatRouteValueDictionary

private static string FormatRouteValueDictionary(RouteValueDictionary dict) {
    if (dict == null) return "(null)";
    var sb = new StringBuilder();
    foreach (var key in dict.Keys) {
        sb.AppendFormat("{0} = {1}, ", key, dict[key]);
    }
    if (sb.Length > 2) sb.Length -= 2; // 移除尾隨逗號
    return sb.ToString();
}

偵錯頁面呈現資訊

區塊說明
Route Data 當前請求匹配路由的參數鍵值對 (controller, action, id 等)
Data Tokens 路由附加資料 (命名空間、自定義 Token 等)
All Routes 所有已註冊路由的匹配狀態、URL 模式、Defaults、Constraints、DataTokens
AppRelativeCurrentExecutionFilePath 原始請求相對路徑

路由偵錯頁面截圖

設計精妙之處

  1. 非侵入式:不修改業務路由邏輯,僅替換 Handler。
  2. 單例 DebugRoute:確保記憶體佔用極低,且永遠在最後匹配。
  3. 利用 GetRouteData 判斷匹配:複用框架原生匹配邏輯,零誤差。
  4. ReaderWriterLock 保護:路由集合在高併發環境下安全遍歷。

現代化替代方案

  • ASP.NET Core 內建 app.UseRouting() + app.UseEndpoints(),可用 dotnet-route 工具或中介軟體列印路由表。
  • Glimpse、RouteDebugger (NuGet) 等套件提供更豐富的 UI 與整合。

理解 RouteMonitor 內部機制,有助於掌握 ASP.NET Routing 管線運作,並能自行擴展客製化偵錯工具。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved