ASP.NET Core 中使用UseRouting()UseEndpoints()這兩個Middleware來比對傳入請求的URL,並將這些請求對應到Controller中的Action。

若想要自定義Middleware的順序,我們可以在Program.cs中明確定義這兩個Middleware。如果沒有定義也沒關係,ASP.NET Core預設會在Pipeline(管線)中自動加入這兩個Middleware。

ASP.NET Core中的路由可以分為慣例路由(Conventional routing)和屬性路由(Attribute routing),慣例路由通常用在Controller和View,屬性路由通常用在REST API,這篇筆記記錄屬性路由的相關設定。

屬性路由 Attribute routing

要讓屬性路由可以順利運作,首先必須在Program.cs中加入MapControllers()方法,MapControllers用於對映所有使用屬性路由的Action。

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();//使用AddControllers讓屬性路由可以運作

var app = builder.Build();
app.MapControllers();//使用MapControllers讓屬性路由可以運作
app.Run();

屬性路由聽名字就知道跟屬性(Attribute,也就是常常會看到掛在方法或類別上方用中括號包起來的那個東西)肯定脫不了關係。

我們在開API時,會需要指定這支API的HTTP動詞及路由,ASP.NET Core 提供以下這幾個Attribute讓我們可以直接把這個屬性掛在類別或方法上方,指定其HTTP動詞或路由。

HTTP動詞Attribute
  • [HttpGet]
  • [HttpPost]
  • [HttpPut]
  • [HttpDelete]
  • [HttpHead]
  • [HttpPatch]
HTTP路由Attribute
  • [Route]
[ApiController]
public class BarController : ControllerBase
{
    [HttpGet]
    [Route("/api/Bar/List")]
    public IActionResult GetBarList()
    {
        return Ok();
    }
}

在上述範例中,GetBarList()方法上方掛了兩個Attribute,分別是[HttpGet][Route]。當我們對這個應用程式發出方法為GET且Endpoint為/api/Bar/List時就會執行GetBarList()這個方法。我們可以針對不同需求使用不同的HTTP動詞搭配不同的路由建立自己需要的API。

提取重複的路由

在同一個Controller中,如果有多個Action都有使用到部分相同的路由時,可以把相同的部分提取出來,一樣使用[Route]attribute掛到class上。

[ApiController]
[Route("/api/Bar")]
public class BarController : ControllerBase
{
    //HTTP動詞與路由為:GET /api/Bar/List
    [HttpGet]
    [Route("List")]
    public IActionResult GetBarList()
    {
        return Ok();
    }

    //HTTP動詞與路由為:GET /api/Bar/:barId
    [HttpGet]
    [Route("{barId}")]
    public IActionResult GetBar(Guid barId)
    {
        return Ok();
    }

    //HTTP動詞與路由為:POST /api/Bar
    [HttpPost]
    public IActionResult PostBar()
    {
        return Ok();
    }
}

語彙基元取代 Token replacement

這個正著唸或倒著唸都不明所以的東東在路由中可是很有用的。通常我們的路由跟Controller的類別名稱有很大的關係,如果想要直接把Controller名稱加入到路由中,我們可以在路由中使用[controller]作為替代Controller名稱的符號。

[ApiController]
[Route("/api/[controller]")]//使用[controller]作為代替Controller名稱的符號,[controller]將會被替換為Bar(Controller的類別名稱)
public class BarController : ControllerBase
{
    //HTTP動詞與路由為:GET /api/Bar/List
    [HttpGet]
    [Route("List")]
    public IActionResult GetBarList()
    {
        return Ok();
    }

    //HTTP動詞與路由為:GET /api/Bar/:barId
    [HttpGet]
    [Route("{barId}")]
    public IActionResult GetBar(Guid barId)
    {
        return Ok();
    }

    //HTTP動詞與路由為:POST /api/Bar
    [HttpPost]
    public IActionResult PostBar()
    {
        return Ok();
    }
}

除了[controller],ASP.NET Core還提供另外兩個token,分別是[area][action][area]會被自動替換為Area的名稱,而[action]則會被替換為controller內action的名稱。

多個屬性路由

我們可以使用多個屬性路由指向同一個Controller或Action,常見的用法是用在「預設慣例路由」,也可以用在任何想要把一個以上的路由對應到同一個Controller或Action時。

[ApiController]
[Route("/api/Foo")]
[Route("/api/[controller]")]
// 「/api/Foo」和「/api/Bar」都會指向這個Controller
public class BarController : ControllerBase
{
    [HttpGet]
    [Route("")]
    [Route("List")]
    // 「/api/Foo」、「/api/Bar」、「/api/Foo/List」、「/api/Bar/List」都會指向這個Action
    public IActionResult GetBarList()
    {
        return Ok();
    }
}

多個HTTP動詞Attribute

除了可以在掛上多個屬性路由,還可以掛多個HTTP動詞Attribute,不過非必要通常不建議這樣做,除非為了支援舊版API之類的非必要情況,否則可能會難以維護。

參考資料