iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 22
1

路由主要負責將請求轉送到對應的處理程序中。當客戶端的請求符合設定中的 URL 規則時,就會自動執行指定的行為。今天會由簡單到複雜,介紹幾種設定路由的方式。

基本路由

在介紹中介層的時候,有使用到 app.Map("/ironman") 這樣的方法,就是最簡單設定路由的方式了。

private static void HandleMapIronman(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Ironman");
    });
}

public void Configure(IApplicationBuilder app)
{
    app.Map("/ironman", HandleMapIronman);
}

但當應用程式越來越複雜之後,要用這種方式一個一個指定會非常困難,所以 ASP.NET Core 有提供一個路由的中介層,讓開發人員可以彈性的定義路由。

路由中介層

開發人員也可以利用中介層來彈性的定義路由。要使用路由中介層 RouterMiddleware,需要搭配 RouteBuilder 來做設定。例如下列的 Startup 設定:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRouting();
    }
    public void Configure(IApplicationBuilder app)
    {
        var routeBuilder = new RouteBuilder(app);
        routeBuilder.DefaultHandler = new RouteHandler((context) =>
        {
            var routeValues = context.GetRouteData().Values;
            return context.Response.WriteAsync(
                $"Hello! Route values: {string.Join(", ", routeValues)}");
        });

        routeBuilder.MapRoute(
            name: "routing example",
            template: "dotnet/{type:regex(^core|mvc|webapi$)}/{available:bool}"
        );

        routeBuilder.MapGet("ithome/{title}", (context) =>
        {
            var title = context.GetRouteValue("title");

            return context.Response.WriteAsync($"Your Title: {title}");
        });

        app.UseRouter(routeBuilder.Build());
    }
}

這段程式碼做了幾件事情:

  • routeBuilder.DefaultHandler = new RouteHandler:設定一個處理程序,用來執行除了 Map{Verb} 這種有直接提供對應程序的請求。
  • routeBuilder.MapRoute:設定一組路由規則。第一個參數是路由名稱,第二個則是符合這組路由的 URL 定義。也可以針對每一個參數做限制,更多限制條件可以參可官方文件
  • routeBuilder.MapGet:設定符合 URL 規則而且是 HTTP GET 請求的對應處理程序。

需要特別注意,路由規則是有順序性的,如果客戶端的請求同時符合多組路由規則,會執行第一組加入的路由規則。

這段設定對應到的 URL 與輸出結果:

URL Output
/dotnet/core/true Hello! Route values: [type, core], [available, true]
/dotnet/webapi/false Hello! Route values: [type, webapi], [available, false]
/dotnet/signalr/true
/ithome/ironman2018 Your Title: ironman2018

MVC 路由

使用 MVC 路由的方式跟使用中介層有 87% 像,只是多了指定對應的 ControllerAction 的設定。設定 MapRoute 的方式也跟使用中介層時一樣。

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
    }
    public void Configure(IApplicationBuilder app)
    {
        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "mvc routing",
                template: "about",
                defaults: new { controller = "Home", action = "About" }
            );
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}"
            );
        });
    }
}

屬性路由

除了在 Startup.cs 中做全域的路由設定外,也可以在 ControllerAction 中用 RouteAttributeHttp{Verb} 來做個別的路由設定。

屬性路由的優先度比 Startup 中設定的路由規則還高,所以就算符合 Startup 中的路由規則也不會執行。

例如以下的屬性路由設定,可以做到跟 {controller=Home}/{action=Index} 類似的效果:

public class HomeController : Controller
{
   [Route("")]
   [Route("Home")]
   [Route("Home/Index")]
   public IActionResult Index()
   {
      return View();
   }
   [Route("Home/About")]
   public IActionResult About()
   {
      return View();
   }
   [Route("Home/Contact")]
   public IActionResult Contact()
   {
      return View();
   }
}

或者也可以把路由共用的邏輯往上拉一層,變成 Controllerattribute

[Route("Home")]
public class HomeController : Controller
{
   [Route("")]
   [Route("Index")]
   public IActionResult Index()
   {
      return View();
   }
   [Route("About")]
   public IActionResult About()
   {
      return View();
   }
   [Route("Contact")]
   public IActionResult Contact()
   {
      return View();
   }
}

也可以透過 Http{Verb} 屬性來對路由做 HTTP 動詞的限制,這類屬性的使用方式跟 RouteAttribute 差不多。

參考資料


上一篇
ASP.NET Core MVC
下一篇
Model Binding 模型繫結
系列文
.Net Core 網站開發 10131

尚未有邦友留言

立即登入留言