預設路由 {controller}/{action}/{id} 會匹配 /Product/blah 這類非數字 ID,導致模型繫結失敗或例外。本文示範兩種路由約束寫法,確保 URL 參數符合預期格式。
routes.MapRoute("Product", "Product/{productId}",
new { controller="Product", action="Details" });
// Details(int productId) 會嘗試將 "blah" 轉 int → 拋出例外
routes.MapRoute("Product", "Product/{productId}",
new { controller="Product", action="Details" },
new { productId = @"\d+" }); // 僅匹配純數字
現在 /Product/blah 將不再匹配此路由,轉交給下一條路由或 404。
當約束涉及資料庫查詢、快取檢查等複雜邏輯時,實作介面:
public class ProductExistsConstraint : IRouteConstraint {
public bool Match(HttpContextBase httpContext, Route route,
string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {
if (!values.ContainsKey(parameterName)) return false;
string val = values[parameterName] as string;
if (string.IsNullOrEmpty(val)) return false;
// 例如:檢查產品是否存在於快取/資料庫
return ProductCache.Exists(val);
}
}
// 註冊
routes.MapRoute("Product", "Product/{productId}",
new { controller="Product", action="Details" },
new { productId = new ProductExistsConstraint() });
| 需求 | 正則 | 說明 |
|---|---|---|
| 純數字 ID | @"\d+" | 一個或多個數字 |
| GUID | @"^[\da-fA-F]{8}-([\da-fA-F]{4}-){3}[\da-fA-F]{12}$" | 標準 GUID 格式 |
| 英文+數字+底線 | @"^[\w-]+$" | Slug、使用者名稱 |
| 特定列舉值 | @"(red|green|blue)" | 僅允許列舉值 |
Match 中做重 IO 操作;必要時引入快取。RouteCollection + Mock<HttpContextBase> 驗證匹配/不匹配案例。