アプリケーションのルート演算子 (~) について紹介します。
概要
ASP.NETアプリケーションで、複数のアプリケーションが配置され、Webアプリケーションの配置される階層が異なる場合、アプリケーションのルートからの相対パスでパスを指定したいことがあります。この記事では、アプリケーションのルート演算子(~)を用いて、アプリケーションルートからの相対パスで指定するコードを紹介します。
プログラム例
ファイル配置
下図のファイル配置とします。アプリケーションルートに"img"ディレクトリを作成し "image1.png" ファイルを配置します。また、アプリケーションルートに "page" ディレクトリを作成し、"page1.aspx" ファイルを配置します。
実行URL
アプリケーションのプロパティを表示し[Web]カテゴリの[サーバー]セクションの[プロジェクトのURL]のURLの末尾に"app/demo/"を追記し、サーバーのルートディレクトリでの動作でない設定に変更します。
コード
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="page1.aspx.cs" Inherits="RootOperatorDemo.page.page1" %>
<!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:Image ID="Image1" runat="server" ImageUrl="~/img/image1.png" />
</div>
</form>
</body>
</html>
」
解説
"~" 演算子により、アプリケーションルートからの相対パスでの指定となります。この場合はアプリケーションルートのimgディレクトリのimage1.png ファイルを参照します。
実行結果
プロジェクトを実行します。画像が表示されます。
正しく動作しない例
このアプリケーションがサーバーのルートディレクトリに配置される前提でImageコントロールのパスに
/img/image1.png
を設定すると正しく動作しません。これは、アプリケーションの配置場所がサーバールートの
/app/demo/
の場所に変更されているため、サーバールートからの絶対パスでの指定をすると位置がずれてしまうためです。
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="page1.aspx.cs" Inherits="RootOperatorDemo.page.page1" %>
<!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:Image ID="Image1" runat="server" ImageUrl="/img/image1.png" />
</div>
</form>
</body>
</html>
」
対処法としては、下記のコードのように
/app/demo/img/image1.png
とサーバールートからの絶対パスで指定すると動作しますが、この場合、配置されるディレクトリが変更された場合はソースコードも合わせて変更する必要があるため、変化に弱いアプリケーションになってしまいます。
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="page1.aspx.cs" Inherits="RootOperatorDemo.page.page1" %>
<!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:Image ID="Image1" runat="server" ImageUrl="/app/demo/img/image1.png" />
</div>
</form>
</body>
</html>
相対ディレクトリの記述で動作する例
先の例でルート演算子で記述するコードを紹介しましたが、多くの場合ルート演算子を利用せずに、相対パスで記述しても問題なく動作します。
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="page1.aspx.cs" Inherits="RootOperatorDemo.page.page1" %>
<!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>
<p>画像です。</p>
<asp:Image ID="Image1" runat="server" ImageUrl="../img/image1.png" />
</div>
</form>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<p>画像です</p>
<img src="../img/image1.png" />
</body>
</html>
上記の例ではページのある位置から、一つ上のディレクトリに上がり、そのディレクトリにある"img"ディレクトリの"image1.png"を指定することでアプリケーションルートの位置が変更されても正しい画像の位置を参照できる記述方法になっています。
ルート演算子が必要になる場合
先の例で紹介した通り、相対パスでの記述によりアプリケーションが配置されたディレクトリの位置にかかわらずファイルへの参照が問題なくできることを紹介しました。相対パスに記述を利用すれば、ルート演算子が不要に思えますが、下記の場合にはルート演算子を利用した記述が必要になります。
ファイルの配置
以下のファイル配置とします。マスターページを利用しMasterファイルをアプリケーションのルートディレクトリに配置します。マスターファイルを利用するコンテンツページ page1.aspx をアプリケーションルートディレクトリに、page2.aspx をpagesディレクトリに配置します。
コード
Masterファイルを変更します。
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="RootOperatorDemoMasterPage.Site" %>
<!DOCTYPE html>
<html>
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
<asp:ContentPlaceHolder ID="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body>
<form id="form1" runat="server">
<asp:Image ID="Image1" runat="server" ImageURL="img/logo.png"/>
<div>
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</div>
<a href="about.aspx">このサイトについて</a>
</form>
</body>
</html>
page1.aspx, page2.aspx, about.aspx ファイルを準備します。
<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="page1.aspx.cs" Inherits="RootOperatorDemoMasterPage.page1" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<p>Page1のコンテンツです。</p>
</asp:Content>
<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="page2.aspx.cs" Inherits="RootOperatorDemoMasterPage.pages.page2" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<p>Page2のコンテンツです。</p>
</asp:Content>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="about.aspx.cs" Inherits="RootOperatorDemoMasterPage.about" %>
<!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>
このサイトについての説明です。
</div>
</form>
</body>
</html>
実行結果
プロジェクトを実行して、page1.aspxを表示します。下図のページが表示されます。マスターページの先頭の画像への参照は相対パスによる記述ですが、正しく参照できており、画像が表示されます。
ページ下部の[このサイトについて]のリンクをクリックします。about.aspxのページに遷移しページが表示されます。
続いて、pages ディクトリのpage2.aspxを表示します。下図のページが表示されます。ディレクトリの階層がpage1と異なりますが、マスターページの先頭の画像への参照は正しくできており、画像が表示されています。
ページ下部の[このサイトについて]のリンクをクリックします。しかしページは表示されず、正しいリンク先に遷移できません。page2.aspxはpage1.aspx の階層と異なるため、相対パスの指定ではリンク先に正しくリンクできません。
ページ | URL(今回のデモの場合) | リンク先記述 | リンク先のURL |
page1.aspx | http://localhost:63688/app/demo/master/page1.aspx | about.aspx | http://localhost:63688/app/demo/master/about.aspx |
page2.aspx | http://localhost:63688/app/demo/master/pages/page2.aspx | about.aspx | http://localhost:63688/app/demo/master/pages/about.aspx |
対処法
リンク先を現在のページ位置からの相対URLではなく、"~"を利用したアプリケーションルートからの相対URLを記述することで対処できます。
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="RootOperatorDemoMasterPage.Site" %>
<!DOCTYPE html>
<html>
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
<asp:ContentPlaceHolder ID="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body>
<form id="form1" runat="server">
<asp:Image ID="Image1" runat="server" ImageURL="img/logo.png"/>
<div>
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</div>
<asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl="~/about.aspx">このサイトについて</asp:HyperLink>
</form>
</body>
</html>
解説
"~"演算子を利用するため、Aタグのリンクではなく HyperLink コントロールを利用します。パスはアプリケーションルートからの相対パスで記述します。
ページ | URL(今回のデモの場合) | リンク先記述 | リンク先のURL |
page1.aspx | http://localhost:63688/app/demo/master/page1.aspx | ~/about.aspx | http://localhost:63688/app/demo/master/about.aspx |
page2.aspx | http://localhost:63688/app/demo/master/pages/page2.aspx | ~/about.aspx | http://localhost:63688/app/demo/master/about.aspx |
ルート演算子 (~) が使える場所
以下のセクションで、ルート演算子が使えます。
逆に下記の場所ではルート演算子は了できません。
- CSSファイル
- imgタグ、aタグなどのサーバーサイドコントロールでないHTMLタグ
著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2024-01-06
作成日: 2018-01-31