ASP.NET MVC RouteLink 使い方
by 深夜連絡 ASP.NET MVC な Web アプリ Advent Calendar 2013 11 日目
ASP.NET MVC では、リンクを貼るための HTML ヘルパーメソッドとして @Html.ActionLink(...) の他に @Html.RouteLink(...) を使うことができます。今回は後者の RouteLink について、基本的な使い方を説明します。サンプルは 次回 にて。
- ActionLink と RouteLink の違い
- ルート名で
- ルート名とパラメーターで
- Root URL へのリンク "Default" でよくある間違い
ActionLink と RouteLink の違い
ActionLink は、コントローラー・アクション等を指定してリンクを生成するのに対し、RouteLink は、ルートを指定してリンクを生成します。
ルートを指定する、というのはルーティング設定(例:RouteConfig.cs)で定義されているルートを指定する、ということです。
ASP.NET MVC では、ActionLink だけでも十分に通用しますが、RouteLink を活用することで効率良く開発できる場合があります。活用方法については、次回で紹介します。
ルート名で
ルート名を指定してリンクを貼る方法です。
ルーティング設定が、↓のように定義されていたとします。
using System.Web.Mvc; using System.Web.Routing; namespace WebApplication1 { public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); //↓このルートへのリンクをはる routes.MapRoute( name: "RouteContactMe", url: "Contact/Me", defaults: new { controller = "Home", action = "Contact" } ); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } }
定義されている URL「Contact/Me」にリンクを貼るには、↓のようにルート名(ルーティング設定にて name で指定した値= RouteContactMe)を指定します。
@Html.RouteLink("Contact Me", "RouteContactMe")
生成される HTML:
<a href="/Contact/Me">Contact Me</a>
もし、属性ルーティングを使用している場合は↓のようにルート名の定義を追加することで、先ほどの RouteLink でリンクを貼ることができます。
public class HomeController : Controller { [Route("Contact/Me", Name = "RouteContactMe")] public ActionResult Contact(); }
ルート名とパラメーターで
↓のように、ルーティング設定にて URL「Contact/Me/{name}」というようにパラメーターを定義している場合は、
routes.MapRoute( name: "RouteContactMe", url: "Contact/Me/{name}", defaults: new { controller = "Home", action = "Contact", name = "defaultName" } );
↓のように、パラメーターを指定することができます。
@Html.RouteLink("Contact Me", "RouteContactMe", new { name = "taro" })
生成される HTML:
<a href="/Contact/Me/taro">Contact Me</a>
(ちなみに、このときパラメーターを指定しないで @Html.RouteLink("Contact Me", "RouteContactMe") とかくと、「/Contact/Me」という URL でリンクの HTML が生成されます。リンクの HTML 生成時は、ルーティング設定で定義した規定値「defaultName」は反映されません。)
Root URL へのリンク "Default" でよくある間違い
よくある間違いは、URL「http://localhost/」(Root URL)といったトップページへのリンクを RouteLink で貼ろうとしたときに起こります。
デフォルトの MVC プロジェクトでは、ルーティング設定は以下のように定義されており、URL「http://localhost/」でアクセスした場合は、コントローラーは「Home」アクションは「Index」にマッピングされるようになっています。
routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } );
そして必要があれば、このコントローラーとアクションの指定を、自分のアプリのトップページを表示するアクションに変更します。
次に、とある場所でトップページへのリンクを貼ります。↓のように RouteLink を使って。
@Html.RouteLink("トップへ戻る", "Default")
ですがこの場合、生成される URL は期待している URL「http://localhost/」ではありません。おそらく現在の URL が生成され、クリックしてもトップページに遷移することはできません。
(URL「~/Diary/Details」のビューにてリンクを貼った場合、「~/Diary/Details」のリンクが生成される)
対策
RouteLink を使ってトップページへリンクを貼る場合は、↓のようにルーティング設定に”新たに”ルートを追加し、
routes.MapRoute( name: "Root", url: "", defaults: new { controller = "Home", action = "Index" } );
ルート名を指定して RouteLink を使用します。
@Html.RouteLink("トップへ戻る", "Root")
(RouteLink にこだわらずとも、ActionLink や 独自のヘルパーを使う、という手段もありますが)
原因
ここからは基本ではなく Deep Dive な話になります。
正しくリンクが貼れなかった原因は、ルーティング設定の URL にて定義されている「{name}」といったパラメーターの値の解決方法(RouteLink メソッド内におけるロジック)にあります。
RouteLink は 対象ルートの URL にパラメーターが定義されている場合、
- 1. RouteLink メソッドの引数にて指定されたパラメーターの値
- 2. 現在のルートのパラメーターの値
の優先順番で値を解決します。(厳密にいうと、2. に 1. を上書きしてる)
"Defaullt"のルートの URL「{controller}/{action}/{id}」にはパラメーターが 3 つ定義されています。↓のようにリンクを貼った場合、
@Html.RouteLink("トップへ戻る", "Default")
RouteLink メソッドの引数に値が指定されていないので、現在のルートのパラメーター値が採用されます。なので、現在のコントローラー(controller)とアクション(action)が反映された URL のリンクが貼られてしまいます。(id の値はこの時は指定されません。アクセスされたときに UrlParameter.Optional というオプション指定が参照されます。)
ルーティングの設定にて default 引数に定義しているパラメーターの初期値というのは、URL でアクセスされた時に参照されるのであって、RouteLink での URL 生成時には参照されません。
他
以上の仕組みにより、Root URL へのリンクは↓のように書くこともできます。(あまり使いたくない感じですが)
@Html.RouteLink("トップへ戻る2", new { controller = "", action = "" })
他、現在のコントローラーで別のアクションに遷移するリンクを↓のように書くこともできます。
@Html.RouteLink("他のアクションへ", new { action = "Contact" }) //@Html.ActionLink("他のアクションへ", "Contact") と一緒。
こう見ると RouteLink は複雑そうですが、通常は意識することはないと思います。