如何依.NET應用程式建置組態產生對應的Prefix前綴路由
在將一個 ASP.NET Web API 應用程式進行容器化(Containerization)發現一個問題,原先的 Web API 部署至 IIS 應用程式之下,我們會區分開發區(Develop)、測試區(Staging)、正式區(Production),而原始的請求因為 IIS 應用程式的關係,路由都會被加上應用程式的前綴(Route Prefix),例如:
- Org:/api/value
- Dev:/develop/api/value
- Stg:/staging/api/value
- Prd:/production/api/value
如同 git 的分支 /{Branch}
/api/value,這些路由前綴是 IIS 加上去的,並非 Web API 的路由系統加上去的。也就是說,當我們把 Web API 專案完成容器化成為映像檔之中,路由系統都是固定的預設值:
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
如果不能產生對應的 /{Branch}/
路由,也就是說,當初接此 Web API 的所有用戶端都必須重新修改程式端點接口,這可怎麼辦?或是說,現在我們想依不同的建置組態來產生對應的 Prefix 前綴路由,我想希望把對用戶端的影響減至最小。你或許會想,那從 routeTemplate
下手呢?routeTemplate: "/develop/api/{controller}/{id}"
這就不好了。這在開發區是對的,但怎麼在 merge (pull request, PR) 時自動把 /develop
換成 /staging
呢?
很快就把腦筋動到屬性路由身上,屬性路由的 RoutePrefix 雖然好用,但面臨和 routeTemplate
的一樣的問題。
不過我知道,不論是 ASP.NET MVC 或 ASP.NET Web API 都留下了一個非常好的習慣,那就是擴充點。如果需要客製化屬性路由,那麼可以繼承 DefaultDirectRouteProvider 類別來實作:
public class DefaultDirectRouteProvider : IDirectRouteProvider
DefaultDirectRouteProvider 本身提供許多取得路由條件的方案,這些方法都是設計成可覆寫的,裡面的 GetRoutePrefix
看起來合乎我們的需求,我們參考 strathweb 的版本快速完成我們需所的 CentralizedPrefixProvider
擴充,
public class CentralizedPrefixProvider : DefaultDirectRouteProvider
{
private readonly string _centralizedPrefix;
public CentralizedPrefixProvider(string centralizedPrefix)
{
_centralizedPrefix = centralizedPrefix;
}
protected override string GetRoutePrefix(HttpControllerDescriptor controllerDescriptor)
{
var existingPrefix = base.GetRoutePrefix(controllerDescriptor);
if (existingPrefix == null)
return _centralizedPrefix;
return $"{_centralizedPrefix}/{existingPrefix}";
}
}
我們將 _centralizedPrefix
設置抽離主程式之外,在 WebApiConfig.cs 注冊時在動態注入:
private static readonly string _routeprefix = WebConfigurationManager.AppSettings["RoutePrefix"];
config.MapHttpAttributeRoutes(new CentralizedPrefixProvider(_routeprefix));
現在我們的 Web API 就能依不同建置組態從 Web.config 裡去讀出對應的 Prefix 期望值,就能進行正確的路由組態。但立即延伸一個問題,其中有個 Controller 是拿來進行 Docker 的健康檢查的,例如:/api/healthy
,在導入動態指定 Prefix 路由規則後,反而無法正常運作!還好這用個 ~
就能解決:
[Route("~/api/healthy")]
透過 ~
覆寫規則就能讓特定路由規則不受其他規則影響。其實相同的問題,我們在 .NET Core 也碰過也處理完成,只不過,因為不是舊應用程式的轉移,所以影響較小。而舊應用程式的轉移,必須考慮的點就比較多些。還好 ASP.NET MVC / ASP.NET Web API 的擴充點真的是個非常好的設計,沒有的就留給開發者自己動手做。
Coding for fun. Docker for everyweher.
沒有留言:
張貼留言
感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。