【.NET】屬性路由在不同 Controller 有同名 URI 不同 HttpMethod 時 API 會無法運作

  • 407
  • 0

  某次重構 API 的時候,因為自己偷懶加上不了解屬性路由的運作原理,於是就發生了這件好笑的錯誤,記錄下來避免以後再次出錯。

1、環境模擬

  建立兩個 ApiController,在每個 Controller 上各自建立一個方法;分別為這兩個方法掛上不同的 HttpMethod,並使用屬性路由掛上相同的 URI。

ValuesController.cs
public sealed class ValuesController : ApiController
{
    [HttpDelete, Route("values/{id:int}")]
    public string DeleteValue(int id)
    {
        return "delete value success !";
    }
}
NewValuesController.cs
public sealed class NewValuesController : ApiController
{
    [HttpGet, Route("values/{id:int}")]
    public string GetValue(int id)
    {
        return "value is " + id;
    }
}

2、執行結果

  使用 Postman 分別對兩隻 API 進行測試,出現 InvalidOperationException

  • Multiple controller types were found that match the URL. This can happen if attribute routes on multiple controllers match the requested URL.
  • 找到多個與 URL 相符的控制器。若多個控制器中的屬性路由符合要求的 URL 時會發生此情況。

Execute Error

3、錯誤原因

屬性路由的運作順序如下:
  • 先依照 Request 尋找所有符合格式的 URI。
  • 再依據 URI 尋找 Controller。
  • 最後找到符合的 HttpMethod 後執行。

  這次在第二步的時候,屬性路由找到了兩個不同的 Controller,此時被判定為系統設定有問題,所以就直接出 Exception 了。

4、如何修正

  把兩隻 API 放在同一個 Controller 內就正常了。

謎之聲:廢話,正常應該也不會有人像這樣放置 API。
NewValuesController.cs
public sealed class NewValuesController : ApiController
{
    [Route("values/{id:int}")]
    [HttpGet]
    public string GetValue(int id)
    {
        return "value is " + id;
    }

    [Route("values/{id:int}")]
    [HttpDelete]
    public string DeleteValue(int id)
    {
        return "delete value success !";
    }
}

Execute Success

5、發生原因與反思

5.1 對自己使用的工具不熟悉

  這點是最主要的部份!由於屬性路由實在是太好用了,導致只會用而沒有去了解運作原理。

5.2 重構應該要小範圍的進行

  重構的部分一次調整太多,因為怕新舊混雜自己會錯亂,所以才選擇建立新的 Controller 來進行,然後就出錯了。

5.3 Attribute 的撰寫習慣導致錯誤想法

  習慣先寫 HttpMethod 再寫 Route,導致發生了「我以為程式會按照我想的跑!」這項原罪,以後會改變撰寫順序。

5.4 測試的重要性與不要偷懶

  會使用同名的 URI 是因為偷懶不想改整合測試的部分,結果這次是被整合測試救了一次,所以該寫的測試還是要寫。

嘗試將自己的理解寫成文字紀錄,資料來源均來自於網路。

如有理解錯誤、引用錯誤或侵權,請多加指正與告知,讓我有更多的進步與改進的空間,謝謝!