URLルーティングでリンクのURLを生成する - ASP.NET

URLルーティングでリンクのURLを生成する方法について紹介します。

概要

URLルーティングを利用してあるページから別のページへのリンクを生成する場合、通常のハードコーディングでは不具合が出ることがあります。この記事では、ハードコーディングではない方法でURLルーティングのページ遷移先URLを生成するコードを紹介します。

うまく動作しない例

うまく動作しない一つの例として、アプリケーションディレクトリがドメイン直下に存在しない場合があります。

コード

ASP.NETプロジェクトで下記のコードを作成します。
Global.asax
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using System.Web.Routing;

namespace AspNetRoutingCreateLink
{
  public class Global : System.Web.HttpApplication
  {

    protected void Application_Start(object sender, EventArgs e)
    {
      RouteValueDictionary default_dic = new RouteValueDictionary();
      default_dic.Add("action", "run");
      default_dic.Add("target", "duck");

      RouteTable.Routes.MapPageRoute("MyRoute01", "{action}/{target}", "~/HandleProto.aspx", true, default_dic);
    }

    protected void Session_Start(object sender, EventArgs e)
    {

    }

    protected void Application_BeginRequest(object sender, EventArgs e)
    {

    }

    protected void Application_AuthenticateRequest(object sender, EventArgs e)
    {

    }

    protected void Application_Error(object sender, EventArgs e)
    {

    }

    protected void Session_End(object sender, EventArgs e)
    {

    }

    protected void Application_End(object sender, EventArgs e)
    {

    }
  }
}
HandlerProto.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="HandleProto.aspx.cs" Inherits="AspNetRoutingCreateLink.HandleProto" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
          <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label><br />
          <asp:Label ID="Label2" runat="server" Text="Label"></asp:Label><br />
          <asp:Literal ID="Literal1" runat="server"></asp:Literal>
        </div>
    </form>
</body>
</html>
デザイナ画面では下図となります。


HandlerProto.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace AspNetRoutingCreateLink
{
  public partial class HandleProto : System.Web.UI.Page
  {
    protected void Page_Load(object sender, EventArgs e)
    {
      string act = (string)Page.RouteData.Values["action"];
      string tgt = (string)Page.RouteData.Values["target"];
      Label1.Text = act;
      Label2.Text = tgt;

      Literal1.Text = string.Format("<a href=\"{0}\">Link</a>", "/swim/penguin");
    }
  }
}

プロジェクト設定

プロジェクトのURLを変更し、アプリケーションがドメインの直下のディレクトリにならない状態とします。下図の例では"MyApp"ディレクトリ内に配置される状態です。

解説

http://localhost:51998/MyApps/(アクション名)/(ターゲット名)
のURLにアクセスすると、HandleProto.aspxへのリライトが実行され、HandleProto.aspx アクセスへ変わります。HandleProto.aspxではアクセスURLの(アクション名),(ターゲット名) を取り出しLabelに表示します。また、
http://localhost:51998/MyApps/swim/penguin
へのリンクを生成します。

実行結果

上記のプロジェクトを実行します。Webブラウザが起動しますので、
http://localhost:51998/MyApps/swim/penguin
にアクセスします。下図の画面が表示されます。Labelにアクション名とターゲット名が表示されています。リンクも表示されています。


しかし、リンクを確認すると
http://localhost:51998/swim/penguin
のURLへのリンクとなっており、期待している
http://localhost:51998/MyApps/swim/penguin
へのリンクではないことがわかります。URL指定の際に先頭に"/"を含めているため、アプリケーションディレクトリが、ルートディレクトリに存在するものとして処理しているためです。


そこで、HandlerProto.aspxのURL生成部分を相対ディレクトリにすればよいだろうと考え下記のコードに変更します。URLの生成文字列部分を"/swim/penguin"から"swim/penguin"に変更します。
    protected void Page_Load(object sender, EventArgs e)
    {
      string act = (string)Page.RouteData.Values["action"];
      string tgt = (string)Page.RouteData.Values["target"];
      Label1.Text = act;
      Label2.Text = tgt;

      Literal1.Text = string.Format("<a href=\"{0}\">Link</a>", "swim/penguin");
    }

上記に変更後プロジェクトを再度実行します。今度はURLが
http://localhost:51998/MyApps/swim/swim/penguin
となってしまいます。これは、アクセスURL
http://localhost:51998/MyApps/swim/penguin
に対し、相対パスのディレクトリURLは
http://localhost:51998/MyApps/swim/
であるため、その位置に対して"swim/penguin"を付加するため、上記のURLへのリンクとなってしまいます。



さらにアクセスURLの末尾に"/"のトレイリングスラッシュ(trailing slash)がある場合には、URL全体がディレクトリと判断されるため、下記のアクセスURL
http://localhost:51998/MyApps/walk/camel/
に対し、リンクのURLは
http://localhost:51998/MyApps/walk/camel/swim/penguin
となってしまいます。

対処法

上記の現象から、単純に文字列を埋め込むリンクはあまり望ましくないことがわかります。対処法としていくつかの方法がありますので紹介します。

対処法1: "~"を利用する (ASP.NET コントロールの場合)

"~"を利用する手順の詳細についてはこちらの記事を参照してください。

対処法2: "$RouteUrl"を利用する (ASP.NET コントロールの場合)

"$RouteUrl"を利用する手順の詳細についてはこちらの記事を参照してください。

対処法3: VirtualPathDataオブジェクトを利用する

先の方法でトレイイングスラッシュの有無やアプリケーションディレクトリの位置によらず、正しい遷移先URLを生成することができます。しかし、ASP.NETコントロールの利用が必要であり、LiteralへのURLの埋め込みや、json, xmlなどの出力には利用できません。VirtualPathDataオブジェクトを利用すると、ロジックでコードを生成し、生成したURLの文字列を取得できます。 VirtualPathDataオブジェクトを利用するコードの詳細についてはこちらの記事を参照してください。
著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2024-01-06
作成日: 2018-02-21
iPentec all rights reserverd.