手邊ASP.NET MVC專案有個隱藏需求,預計上線不久要推出新版,有一段時間新舊版本並存。有幾個供AJAX呼叫的API性質Controller,希望未來出新版時名稱能沿用,不要弄出BooV1Controller、BooV2Controller這種名字,最好在URL路徑加上v1/v2等就能搞定,例如:
第一版: ~/api/v1/boo/action
第二版: ~/api/v2/boo/action
在ASP.NET MVC專案處理此類路徑問題,我想到兩個選擇: 一個是利用Area機制、另一個則是直接用Route對應。考量Area切割範圍涵蓋Controller、Model及View,我只想區分Controller版本,搬出Area有點殺雞用牛刀,就用路由解決吧!
構想如下,ASP.NET MVC專案在Controllers下新增V1及V2兩個資料夾,其中各放入一個Controller類別,由於Namespace不同(Mvc4Lab.Controllers.V1 vs Mvc4Lab.Controllers.V2),兩個Controller可使用相同命名,都叫BooController。
我們都知道ASP.NET MVC是"以習慣取代配置"(Convention over Configuration),會試圖從URL中找出Controller名稱,主動尋找專案中同名的"***Controller類別"處理該URL請求。當同一專案中出現相同名稱Controller,得額外提供路由線索,ASP.NET MVC才能正確解析。
原以為得費點手腳,沒想到MapRoute()設想很周到,只需在設定路徑時額外傳入Namespace參數(支援字串陣列,限定只在指定命名空間尋找Controller),便能做到不同URL格式使用同名Controller的效果。
在App_Strat/RouteConfig.cs中加兩ApiV1, ApiV2兩則額外路徑,大功告成,就這麼簡單。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace Mvc4Lab
{
publicclass RouteConfig
{
publicstaticvoid RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "ApiV1",
url: "api/v1/{controller}/{action}",
namespaces: newstring[] { "Mvc4Lab.Controllers.V1" }
);
routes.MapRoute(
name: "ApiV2",
url: "api/v2/{controller}/{action}",
namespaces: newstring[] { "Mvc4Lab.Controllers.V2" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index",
id = UrlParameter.Optional }
);
}
}
}
不過要提醒,由於ASP.NET MVC下所有的Request都要先進行路由解析再決定處理方式,切忌把路徑設定規則搞得太多太複雜,以免拖累系統效能。