筆記目錄

Skip to content

ASP.NET Core Web API 入門心得 - 淺談 non-RESTful 的 Route 覆寫

TLDR

  • 透過繼承 BasicController 並設定 [Route("[controller]/[action]")],可統一管理 non-RESTful 架構下的 API 路由。
  • 若需覆寫 Controller 層級的路由,直接在 Controller 上使用 [Route] 屬性即可。
  • 若 Action 需要完全忽略 Controller 層級的路由設定,需在 Action 的 [Route] 前綴加上 /~ 符號。
  • 避免在 Controller 與 Action 同時使用 [Route],否則會導致路由路徑串接(Concatenation),產生非預期的 URL。
  • 若僅需修改 Action 的 URL 名稱,建議使用 [ActionName] 屬性而非 [Route]

統一路由管理與基礎設定

在 non-RESTful 風格的 Web API 中,為了避免重複定義路由,可以建立一個抽象的 BasicController 來統一設定路由規則。

什麼情況下會遇到這個問題: 當專案採用 Controller/Action 格式,且希望減少每個 Controller 重複撰寫路由屬性的維護成本時。

csharp
[ApiController]
[Route("[controller]/[action]")]
public abstract class BasicController : ControllerBase {
}

public class TestRouteController : BasicController {
    // URL: /TestRoute/TestAction
    [HttpPost]
    public void TestAction() {
    }
}

路由覆寫與路徑串接問題

當現有 API 架構需要調整,或個別 Action 需要特殊路徑時,必須理解 [Route] 屬性在不同層級的行為差異。

什麼情況下會遇到這個問題: 當需要針對特定 Controller 或 Action 進行路徑客製化,卻不希望影響全域設定,或是不小心觸發了預設的路由串接行為時。

路由行為分析

  • Controller 層級覆寫:在 Controller 上使用 [Route] 會直接取代 BasicController 的設定。
  • Action 層級串接:若 Controller 與 Action 同時定義 [Route],ASP.NET Core 會將兩者路徑進行串接。
  • 強制覆寫(忽略前綴):在 Action 的 [Route] 前綴加上 /~,可強制忽略 Controller 層級的路由設定。
csharp
[Route("Override/[action]")]
public class TestRouteController : BasicController {
    // 情境:Controller 覆寫 Route,Action 不處理
    // URL:/Override/OverrideController
    [HttpPost]
    public void OverrideController() {
    }

    // 常見誤用:Controller 和 Action 都覆寫,導致路徑串接
    // URL:/Override/OverrideAction/Action/OverrideAction
    [HttpPost]
    [Route("Action/[action]")]
    public void OverrideAction() {
    }

    // 情境:Action 強制忽略 Controller 設定,使用 "/"
    // URL:/Action/OnlyAction
    [HttpPost]
    [Route("/Action/[action]")]
    public void OnlyAction() {
    }

    // 情境:Action 強制忽略 Controller 設定,使用 "~"
    // URL:/Action/OnlyAction2
    [HttpPost]
    [Route("~/Action/[action]")]
    public void OnlyAction2() {
    }

    // 情境:單純修改 Action 名稱,不影響路由結構
    // URL:/Override/Rename
    [HttpPost]
    [ActionName("Rename")]
    public void RenameAction() {
    }
}

結論與建議

  • 若要統一 API 命名風格,請優先使用 BasicController 進行全域路由定義。
  • 若需針對特定 Action 調整路徑,優先考慮使用 [ActionName] 屬性,這能避免路由串接帶來的複雜度。
  • 若必須使用 [Route] 覆寫 Action 路徑,務必加上 /~ 前綴,以確保路徑符合預期,避免產生冗長的巢狀 URL。

異動歷程

  • 2024-04-16 初版文件建立。