次の方法で共有


Web の移行

Web アプリケーションを WebMatrix から ASP.NET MVC 3 に移行する

Brandon Satrom

コード サンプルのダウンロード

今年の 1 月、マイクロソフトは、Microsoft .NET Framework による Web 開発の新しいプログラミング モデルとして "ASP.NET Web ページ" を導入しました。現在、WebMatrix (web.ms/WebMatrix) の既定でサポートされる Web ページは、ページ中心のプログラミング モデルで、動作は PHP に非常に近く、各ページには独自のビジネス ロジック、データ アクセス、および HTML をブラウザーに表示するための動的コンテンツを含みます。

WebMatrix を使用して Web サイトを構築する理由はさまざまです。しかし、将来のある時点で Visual Studio に移行することがわかっていたらどうでしょう。最終的に ASP.NET MVC 3 を使用する場合、移行すべきときが来たら、サイトを開発し直す必要があるでしょうか。WebMatrix と Web ページを使用することで、拡張性や柔軟性に不安をお感じであれば、心配は無用です。

中核となる ASP.NET Framework のコンポーネントの 1 つである Web ページは、柔軟性を念頭において構築されています。Web ページには ASP.NET MVC に移行せざるを得なくする技術上の制限はありません。ただし、チーム、製品、または会社にとって、ASP.NET MVC への移行が理にかなう場合はあります。

この記事では、移行する理由 (および移行しない理由) について説明します。また、Web ページ サイトを ASP.NET MVC に移行する際の方針についても説明します。ページからビューに移行する方法、ビジネス ロジックとヘルパー コードを処理する方法、およびモデルをアプリケーションに導入する方法を取り上げます。最後に、ルーティングによって既存のサイトの URL を保持し、必要に応じて永続的なリダイレクトをサポートする方法について説明し、その手順を紹介します。

移行のタイミング

Web ページから ASP.NET MVC に移行する理由を説明する前に、移行を行わない理由をいくつか見て行きましょう。まず、アプリケーションのスケーラビリティが不十分になるのではないかと考えて、Web ページを ASP.NET MVC に移行する必要はありません。Web ページは ASP.NET を基盤に構築されているため、ASP.NET MVC や Web フォーム用に作成されたアプリケーションと同じパフォーマンス上の特徴を多く備えています。たしかに、アプリケーションの種類ごとに実行モデルにはわずかな違いがありますが、Web ページ アプリケーションと比べて本質的にスケーラビリティに違いが出るような特徴は ASP.NET MVC にはありません。スケーラビリティとパフォーマンスは、基盤に採用するフレームワークと同様、サイトを構築する際の設計に左右されます。

また、ASP.NET MVC が小粋で、皆がそうしているという噂のために、または Visual Studio で作業したいがためだけに、Web ページから ASP.NET MVC にサイトを移行するのも、よい考えではありません。このようなことは、Web ページ サイトでも既に実現できています。ASP.NET MVC は、Web アプリケーション アーキテクチャの 1 つの選択肢であり、サイトを即座に改善できる魔法の杖ではありません。Web ページから ASP.NET MVC への移行は、任意であり、必須ではありません。マイクロソフトは、実に見事にこの移行を実現し、ストレスなく移行できるようにしていますが、どの移行でもそうであるように、時間、リソース、および資金がかかります。このような理由から、正しい理由で ASP.NET MVC に移行することを確認することが重要です。

有効な理由の 1 つとしては、自身と自身のチームにとって単体テストが重要であることが考えられます。Web ページ モデルはページ中心であるため、Web ページ サイトには、既存の単体テスト ツールを使用できません。それでも (WatiN や Selenium などのツールを使用して) Web UI テストは実行できますが、NUnit や MsTest などのツールを使用したコード レベルでの単体テストは実行できません。サイトが複雑になり、単体テストが重要な場合は、ASP.NET MVC への移行が理にかなっています。

コードの単体テストを実行する場合、おそらく、アプリケーションでの懸案事項の分離もある程度必要になるでしょう。Web ページ モデルでもヘルパーおよびコード ファイルを使用して、適宜分離コードを作成することはできますが、このモデルでは、ASP.NET MVC ほど自然にこのような分離がしやすいわけではありません。懸案事項の分離が重要で、このような分離を実現しやすいアプリケーション アーキテクチャが必要な場合、移行は有効な選択肢です。

この 2 つ以外には、サイトや組織の状況に応じて、その他の理由から移行を決める可能性があります。チームが拡大を続けていて、サイトが複雑さを増し、より充実した業務機能がサイトでますます必要とされる場合、移行は賢明です。また、ソース管理やロード テストなどの作業に、より充実した機能性の高い開発エコシステムを活用する場合も、移行が必要な可能性があります。

移行を準備する

この記事では、WebMatrix に付属しているフォト ギャラリー テンプレート サイトを取り上げ、このサイトを ASP.NET MVC に移行します。移行プロセスの中心になるのは、ページからモデル、コントローラー、およびビューへの移行です。ただし、その前に、少し事前の作業が必要です。

この短い記事で手動での移行に必要な手順を説明するため、1 つ 1 つの手順に同程度の注意を向けることはできません。この記事の目標は、主要手順を説明することと、細かい注意点については少なくとも言及することです。また、データ アクセスのベスト プラクティスや、考えられるアセンブリ構造、依存関係の注入など、記事全体の中心的な話題とは関係のない項目も省略します。このような項目は重要ですが、これらの多くは開発文化や個人の好みに帰着しますし、移行後のリファクタリングですべて対応できます。

また、現在のサイトを Web サイト プロジェクトとして Visual Studio で開く、WebMatrix の [Open in Visual Studio] (Visual Studio で開く) 機能は使用しないことにも注意してください。ASP.NET MVC に移行しない場合でも、このオプションを使用してかまいませんが、ここでは、ASP.NET MVC に Visual Studio Web アプリケーション プロジェクトを使用して、空のサイトを基に、手動で移行を実施します。

したがって、[ファイル]、[新規作成]、[プロジェクト] を順にクリックし、[ASP.NET MVC 3 Web アプリケーション] を選択して、既定のビュー エンジンに Razor を使用する空のテンプレートを基に、移行を開始します。

ターゲット アプリケーションの準備ができたら、移行の初期作業を実行する必要があります。移行の初期作業の内訳を以下に示します。

  1. NuGet (nuget.org、英語) を利用して、Web ページ サイトで使用しているパッケージを ASP.NET MVC サイトに追加します。
  2. System.Web.Helpers、WebMatrix.Data、および WebMatrix.WebData への参照を追加します。プロパティ ペインで、各参照の "ローカル コピー" を true に設定します。
  3. _AppStart.cshtml のコンテンツを Global.asax の Application_Start メソッドに移動します。_AppStart をそのまま移動して使用することもできますが、既存の ASP.NET MVC スタートアップ コードがある Global.asax にロジックを集約することをお勧めします。
  4. <roleManager enabled=true /> をルートの web.config の <system.web> セクションに追加します。フォト ギャラリー アプリケーションでは、WebMatrix.WebData にある新しい WebSecurity メンバーシップ プロバイダーが使用されるため、サイトが機能するには、構成にこのエントリが必要です。
  5. アプリケーションの Content または Scripts フォルダーにスタイルシート、スクリプト ファイル、およびイメージを移動します。これらのファイルのリソース リンクを新しいパスに更新します。
  6. ギャラリーのコントローラーと既定のアクションをポイントするように、Global.asax の既定のルートを変更します。
  7. App_Data フォルダーにある SQL Compact データベースを、サイトの App_Data フォルダーにコピーします。サイトに別のデータベースを使用している場合は、その接続文字列をアプリケーションの Web.Config ファイルに追加します。

ページからビューへの移行

ASP.NET MVC サイトの初期設定が完了したら、既存のサイトの中核であるページの移行に取り掛かることができます。Web ページでは、ページ (.[cs/vb]html) に、マークアップ、ビジネス ロジック、およびそのページに必要なデータ アクセスが含まれます。ASP.NET MVC への移行中に実行する主な作業は、各ページを分解して、コンテンツをコントローラー アクション (ビジネス ロジック)、データ アクセス クラス (データ アクセス)、およびビュー (マークアップ) に分けることです。

まず、サイトのレイアウトを移行する必要があります。Web フォームと ASP.NET MVC のマスター ページと同様に、レイアウト ページは、サイトのレイアウト構造を指定するファイルです。Web ページと ASP.NET MVC 3 (Razor ビュー エンジンで使用する場合) は、同じレイアウト サブシステムを使用するため、移行のこの部分は簡単です。フォト ギャラリー サイトでは、root _SiteLayout.cshtml ファイルにサイト構造が含まれています。コンテンツをコピーし、ASP.NET MVC サイトに移動します。Views/Shared/_Layout.cshtml にある Layout ファイルを開き、_SiteLayout.cshtml のコンテンツを貼り付けます。

それが済んだら、_Layout.cshtml を少し変更する必要があります。まず、スタイルシートへのリンクを ASP.NET MVC アプリケーションでの新しい場所 (~/Content/Site.css instead of ~/Styles/Site.css) に変更します。次に、@Page.Title を @ViewBag.Title に変更する必要があります。どちらも、サイトのページの display などのデータを保持できる動的なオブジェクトです。予想されたかもしれませんが、Page は Web ページに、ViewBag は ASP.NET MVC に使用されます。

_Layout.cshtml で変更が必要な最後の要素は、ASP.NET MVC に移行するすべてのページで心に留めておく必要があります。_Layout.cshtml では @Href 呼び出しを使用して URL をページに挿入していることに注意してください。静的コンテンツ (スクリプト、CSS など) を参照する呼び出しの場合、これらは変更しないでおくことができます。ただし、サイトのページをポイントする @Href 呼び出しは、すべて変更が必要になります。これらの呼び出しもそのままで移行後も機能しますが、静的な URL を指します。ASP.NET MVC では、ビューを表示する場合、ASP.NET ルーティングを使用して URL を作成する方がよいと考えられています。この場合、サイト上でハードコーディングするのではなく、より明確で扱いやすいリンクをルート テーブルの定義に関連付けます。

したがって、次のようなリンクはすべて変更することをお勧めします。

<div id="banner">
  <p class="site-title">
    <a href="@Href("~/")">Photo Gallery</a>
  </p>
...
</div>

上記の代わりに、次のように @Url.RouteUrl または @Url.Action を使用します。

<div id="banner">
  <p class="site-title">
    <a href="@Url.Action("Default", "Gallery")">Photo Gallery</a>
  </p>
...
</div>

サイトのレイアウトを移動できたら、ページからビューへの移行を開始できます。Web ページ アプリケーションに RenderPage 呼び出しによって実行される .cshtml ページがある場合、それがサイト全体のページの場合は Views/Shared 以下に移動し、コントローラーによって共有されるページの場合は Views 以下の該当するフォルダー (Account など) に移動します。このような部分ページの 1 つを呼び出す各ページは、新しい場所に合わせて更新する必要があります。

残りのページはすべて、コントローラー別にフォルダーにまとめて、Views に移動します。Web ページ サイトにはコントローラーの概念がないため、移行時にコントローラーを導入する必要があります。さいわい、フォト ギャラリー アプリケーションでは、コントローラー構造の形式は明確で、実際のサイトの作業での手本になります。

たとえば、フォト ギャラリー テンプレート サイトでは、Account、Gallery、Photo、Tag、User の各フォルダーを使用して、ページをグループ化します。各フォルダーには、そのグループ分けに関連する機能を実現するページが含まれています。たとえば、Account フォルダーには、サイトへのログインおよびログアウトのページや、ユーザー登録のページが含まれています。Gallery フォルダーには、ギャラリーの一覧ページ、新しいギャラリーを追加するためのページ、およびギャラリーの写真を表示するためのページがあります。他のフォルダーも同様にまとめられています。このような構造は、Web ページ サイトでは必要ありませんが、ASP.NET MVC へのより容易な移行を可能にします。この場合、各フォルダーはコントローラーに適切にマップされ、各 .cshtml ファイルは Action および View にマップされます。

Account フォルダーとその 3 つのページ (Login、Logout、および Register) を ASP.NET MVC アプリケーションの Views ディレクトリに移行することから始めましょう。ASP.NET MVC では、アプリケーション内でそれぞれ保持されている場所の性質に従って、ページはすぐにビューになります。ただし、それで終わりではありません。これらのビューが要求されたときにユーザーに提供できるようにするには、コントローラーとアクションがアプリケーションに必要です。

コントローラーを導入する

MVC の原則として、Account フォルダーが Views にある場合は、AccountController というコントローラーが必要になります。したがって、次は、Controllers フォルダーの下に、このコントローラーを作成します。右クリックして、[追加] をクリックし、[コントローラー] をクリックします。この空のコントローラーを基に、現在は、アプリケーションに移動した各 .cshtml ページの先頭にあるロジックを保持するアクション メソッドを作成できます。

まず、Login.cshtml を処理します。このファイルには、図 1 のコードが含まれています。

図 1 Login.cshtml にあるビジネス ロジック

Page.Title = "Login";
if (IsPost) {
  var email = Request["email"];
  if (email.IsEmpty()) {
    ModelState.AddError(
      "email", "You must specify an email address.");
  }
  var password = Request["password"];
  if (password.IsEmpty()) {
    ModelState.AddError(
      "password", "You must specify a password.");
  }

  if (ModelState.IsValid) {
    var rememberMe = Request["rememberMe"].AsBool();
    if (WebSecurity.Login(email, password, rememberMe)) { 
      string returnUrl = Request["returnUrl"];        
      if (!returnUrl.IsEmpty()) {
        Context.RedirectLocal(returnUrl);
      } else{
        Response.Redirect("~/");
      }
    } else {
      ModelState.AddFormError(
        "The email or password provided is incorrect.");
    }
  }
}

ここでは、2 つのシナリオが処理されていることに注目します。1 つは、ユーザーがログイン ページを始めて読み込んだときに使用されるシナリオです。このシナリオでは、直接、ページによってタイトルと切り替えがマークアップに設定されています。2 つ目のシナリオは、IsPost 条件内にあり、ユーザーがログイン フォームに入力して、[ログイン] ボタンをクリックしたときに実行されるロジックを表しています。

ASP.NET MVC では、コントローラーに 2 つのアクション メソッド (空のフォーム用と送信処理用) を作成することで、空のフォームを提供し、フォームの送信を受け付けるプロセスを処理します。1 つ目のアクションでは、ページ タイトルを設定してログイン ビューを返し、2 つ目のアクションでは、IsPost 条件内にロジックを設定します。図 2 に、これらのアクションを示します。この 2 つのアクションを追加したら、Login.cshtml からヘッダー コードを削除します。

図 2 ログイン コントローラー アクション

public ActionResult Login() {
  ViewBag.Title = "Login";
  return View();
}

[HttpPost]
public ActionResult Login(string email, string password, 
  bool? rememberMe, string returnUrl) {
  if (email.IsEmpty())
    ModelState.AddModelError("email", 
      "You must specify an email address.");
  if (password.IsEmpty())
    ModelState.AddModelError("password", 
      "You must specify a password.");
  if (!ModelState.IsValid)
    return View();
  if (WebSecurity.Login(email, password, 
    rememberMe.HasValue ? rememberMe.Value : false)) {
    if (!string.IsNullOrEmpty(returnUrl))
      return Redirect(returnUrl);
    return RedirectToAction("Default", "Gallery");
  }

  ModelState.AddModelError("_FORM", 
    "The email or password provided is incorrect");
  return View();
}

元のページと作成したアクション メソッド間には、注意すべき重要な違いが多数あります。まず、IsPost 条件が必要ないことにお気付きになるでしょう。ASP.NET MVC では、2 つ目のログイン アクション メソッドを作成し、これに [HttpPost] 属性を設定することで、ログイン ページのポスト アクションを作成します。1 つ目のログイン メソッドで実行する処理は、ViewBag.Title プロパティを設定し、ViewResult を返すだけになりました。ViewResult が返されると、Views/Account 内で Login.cshtml という名前のビュー ページが検索されます。

2 つ目に気付くのは、このポスト アクションには、いくつかパラメータがあり、元のページで使用されていた Request 呼び出しがすべてなくなっていることです。ログイン フォームのフィールド名に対応するパラメーター (email、password、および rememberMe) をメソッドに設定することで、ASP.NET MVC の既定のモデル バインダーを使用して、これらの項目をアクションのパラメーターとして渡しています。これにより、明示的に Request オブジェクトを呼び出す手間を省き、アクション ロジックをさらに簡潔にしています。

また、検証の処理方法とリダイレクトの実行方法についても、Web ページと ASP.NET MVC アプリケーション間でわずかな違いがいくつかあります。この記事の Web ページ サイトでは、ModelState.AddError と .AddFormError を使用して、無効なフォーム データが見つかったことをページに通知しています。ASP.NET MVC アプリケーションでは、ModelState.AddModelError を使用します。これはわずかな違いですが、すべてのページで必要な変更の 1 つです。リダイレクトについては、Web ページ サイトでは、ユーザーの再ルーティング時に Response.Redirect を呼び出します。ASP.NET MVC では、コントローラー アクションから ActionResult が返されるため、return RedirectToAction(“Default”) を呼び出します。これは、同じ結果を返します。

ログイン ページを移行できたら、Logout.cshtml も簡単に処理できます。Web ページでは、Logout.cshtml のように、アクションを実行し、ユーザーをリダイレクトすることが目的である一部のページでは、ページにロジックが含まれ、マークアップはない場合があります。

@{
  WebSecurity.Logout();
  Response.Redirect("~/");
}

ASP.NET MVC では、この作業を自動的に実行するログアウト アクションを追加します。

public ActionResult Logout() {
  WebSecurity.Logout();
  return RedirectToAction("Default", "Gallery");
}

ビューは、ページのビジュアル要素のみを表し、機能は表さず、また、ここではユーザーのログアウトとリダイレクトを処理するアクションを作成しているため、アプリケーションから Logout.cshtml ビューを削除できます。

ここまでで、Account ページを Views/Account フォルダーにコピーすることでビューに変更し、Account ページに対する要求を処理する AccountController を作成し、ログインおよびログアウトのシナリオを処理するアクション メソッドを実行しました。この時点で、サイトをビルドして実行し、Account/Login をブラウザーのアドレス バーに追加できます (既定のホームページは Gallery/Default をポイントしていますが、これはまだ実装されていないため、表示されません)。

この時点で処理をお勧めするもう 1 つのサイト機能は、Web ページ サイトの App_Code ディレクトリ内に保持されているコードとヘルパーです。移行プロセスの最初に、このディレクトリ全体を ASP.NET MVC アプリケーションに移動して、プロジェクトに含めることができます。このディレクトリにコード ファイル (.cs または .vb) が含まれている場合は、App_Code にコード ファイルを保持したままにすることも、別の場所に移動することもできます。どちらの場合も、各ファイルの "ビルド アクション" プロパティを "コンテンツ" ではなく "コンパイル" に変更する必要があります。このディレクトリに @helper メソッド宣言がある .cshtml ファイルが含まれている場合、.cshtml ファイルはそのまま、ASP.NET MVC アプリケーションで使用できます。

Web ページ サイトの残りの部分については、各 Views フォルダーに対してコントローラーを作成したのと同様のサイクルに従い、ページごとにアクションを作成し、ヘッダー コードを各ページから 1 つ以上のアクションに移動します。すぐに、すべてのページをコントローラー アクションとビューに整然と分類できるでしょう。ただし、ここで説明していない MVC パターンがまだ 1 つあります。それは、"モデル" です。

データ アクセスをリポジトリ クラスに移行する

各ページからビジネス ロジックを取り出して、そのロジックを 1 つ以上のコントローラー アクションに移動するプロセスは、データ アクセスを除けば、非常にシンプルです。一部のページは、ログインおよびログアウト ページと似ていて、ロジックが多少含まれていてもデータ アクセスがない可能性がありますが、おそらく Web ページ サイトでは多くの部分でデータベースが使用されます。

一例として、Account/Register.cshtml ページがあります。ユーザーが登録フォームに入力し、[登録] をクリックすると、ページは 2 つのデータベース呼び出しを実行します (図 3 参照)。

図 3 Register.cshtml のデータベース ロジック

var db = Database.Open("PhotoGallery");
      
var user = db.QuerySingle("SELECT Email FROM 
UserProfiles WHERE LOWER(Email) = LOWER(@0)", email);
       
if (user == null) {      
  db.Execute(
    "INSERT INTO UserProfiles (Email, DisplayName, Bio) 
    VALUES (@0, @1, @2)", email, email, "");

  try {
    WebSecurity.CreateAccount(email, password);
    WebSecurity.Login(email, password);
    Response.Redirect("~/");
  } catch (System.Web.Security.MembershipCreateUserException e) {
    ModelState.AddFormError(e.ToString());
  }
} else {
  ModelState.AddFormError("Email address is already in use.");
}

まず、登録ページによって PhotoGallery データベースが開かれ、データベースを表す WebMatrix.Data.Database オブジェクトが返されます。次に、このオブジェクトを使用して、ユーザーが指定した値を基に、既存の電子メール アドレスが検索されます。アドレスが存在しなければ、新しい UserProfile レコードが作成され、WebSecurity メンバーシップ プロバイダーを使用して、ユーザーのためにアカウントが作成されます。

WebMatrix.Data への参照を追加し、"ローカル コピー" プロパティを true に設定する限り、変更なしでこのデータベース ロジックを使用でき、サイトは正常に稼働します。移行の最中は、サイトを稼働した状態で保つ戦略的手順として、この方法を採用してもよいでしょう。

しかし、ここでは、さらに一歩進めて、ASP.NET MVC アプリケーションを最初から作成する場合と同様に、データ アクセスを保持する追加のオブジェクトを作成します。コントローラーとデータ アクセス ロジックを分離するために、自由に使用できるパターンが多数あります。ここでは、フォト ギャラリーにリポジトリ パターンを使用します。データ アクセスをリポジトリ クラスに抽象化することで、このロジックをカプセル化し、将来、正規のモデル オブジェクトや、Entity Framework などのオブジェクト リレーショナル マッピング (ORM) システムを追加することになったときに影響を最小限に抑えることができます。

まず、アプリケーションに Repositories フォルダーと、AccountRepository.cs という簡単なクラスを作成します。これで、Register アクションの各データベース呼び出しをステップ実行して、そのロジックをリポジトリに移動できます (図 4 参照)。

図 4 AccountRepository

public class AccountRepository {
  readonly Database _database;
  public AccountRepository() {
    database = Database.Open("PhotoGallery");
  }

  public dynamic GetAccountEmail(string email) { 
    return _database.QuerySingle(
      "SELECT Email FROM UserProfiles 
      WHERE LOWER(Email) = LOWER(@0)", email);
  }
 
  public void CreateAccount(string email) {
    _database.Execute(
      "INSERT INTO UserProfiles 
      (Email, DisplayName, Bio) VALUES (@0, @1, @2)", 
      email, email, "");
  }
}

リポジトリのコンストラクターに Database.Open への呼び出しを追加し、アカウントの電子メールを検索するメソッドと、アカウントを作成するメソッドの 2 つのメソッドを作成しました。

GetAccountEmail の戻り値の型が dynamic であることに注意してください。WebMatrix.Data では、クエリ メソッドの多くが dynamic または IEnumerable<dynamic> を返します。この方法が持続可能な限り、皆さんのリポジトリでも使用できない理由はありません。

AccountRespository を使用する新しい Register メソッドを図 5 に示します。

図 5 AccountRepository を使用する Register アクション

[HttpPost]
public ActionResult Register(string email, string password, 
  string confirmPassword) {

  // Check Parameters (omitted)

  if (!ModelState.IsValid)
    return View();
 
  var db = new AccountRepository();
  var user = db.GetAccountEmail(email);
 
  if (user == null) {
    db.CreateAccount(email);
 
    try {
      WebSecurity.CreateAccount(email, password);
      WebSecurity.Login(email, password);
      return RedirectToAction("Default", "Gallery");
    }
    catch (System.Web.Security.MembershipCreateUserException e) {
      ModelState.AddModelError("_FORM", e.ToString());
    }
  }
  else {
    ModelState.AddModelError("_FORM", 
      "Email address is already in use.");
  }
 
  return View();
}

動的な型の戻り値を使用するのはまったく問題ありません。むしろ、完成した ASP.NET MVC アプリケーションとして、サイトを構築して実行するので、移行中はこれが賢明な方法である可能性があります。ASP.NET MVC アプリケーションでは、厳密に型指定されたモデルを使用する必要がないため、データ モデルのコード駆動型定義が必要でない限り、この方法を使用できます。動的モデルの ASP.NET MVC アプリケーションのコントローラー ロジックとビューは、正常に稼働しますが、1 つだけ例外があります。

Web ページ アプリケーションでは、フォーム フィールドを標準のマークアップを使用して明示的に定義します。

<input type="text" />
<input type="submit" />
...

ASP.NET MVC で推奨されるフォーム コントロールの使用方法は、Html.TextBox や Html.TextBoxFor などの Html ヘルパー メソッドを使用することです。これらのメソッドでは、ビューに渡されたモデルを使用して現在の値を設定し、フォーム検証が処理されるためです。これらのヘルパー メソッドを移行後のビューで使用する場合、これらのヘルパー メソッドは動的なモデルに対応できないため、厳密に型指定されたモデル オブジェクトを導入して、リポジトリで動的な型を使用しないようにする必要があります。

サイト URL を保持する

サイトの URL は重要です。サイトがどのような状態であっても、検索エンジン、ドキュメント、通信、テスト スクリプトなど、多くの外部リソースが既存の URL に依存しています。このような依存関係があるため、移行する場合でも、URL は任意に変更しなでください。

既存の URL を保持するため、ASP.NET ルーティングを使用することを検討します。ASP.NET ルーティングは、要求がスムーズに送られるようにし、正しいリソース (この場合はコントローラーとアクション) に対応付けます。Web ページでは ASP.NET MVC とは異なるルーティング システムが使用されるので、時間を取り、既存の URL が保持されていることを確認する必要があります。

Web ページアプリケーションは、拡張子があってもなくても、URL を処理できます。たとえば、次の URL は両方とも同じページに解決されます。

http://mysite/Gallery/Default.cshtml

http://mysite/Gallery/Default

一方、ASP.NET MVC アプリケーションでは、最初の URL は .cshtml 拡張子を使用して処理されません。サイト全体で拡張子を付けない URL を使用することで、検索エンジンや依存関係のある他のサイトの動作を同じにでき、サイトに対する移行の影響を最小限に抑えられます。ただし、拡張子が設定されている既存の URL を処理する必要がある場合は、ASP.NET MVC アプリケーションで経路を作成して、既存の URL が使えなくなることがないようにします。

たとえば、ここでのフォト ギャラリー アプリケーションの既定の経路について考えて見ましょう。

routes.MapRoute(
  "Default", 
  "{controller}/{action}/{id}", 
  new { controller = "Home", 
    action = "Index", id = "" } 
);

このシステムの従来の URL をサポートするには、Global.asax ファイルで、この定義の上にある経路のテーブルに、追加の経路を設定する必要があります。この定義の例を次に示します。

routes.MapRoute(
  "LegacyUrl",
  "{controller}/{action}.cshtml/{id}",
  new { controller = "Gallery", 
    action = "Default", id = "" }
);

既存の Web ページ サイトの構造が、コントローラーとアクションの構造に間違いなくマッピングされていることが前提になりますが、この経路のエントリでは、拡張子 .cshtml を含む URL が処理され、適切なコントローラーとアクションに送られます。

移行を計画する場合、アプリケーションの既定の経路を変更するか、経路を追加して既存の URL を変更する必要が生じる可能性があることを心に留めておいてください。ただし、既存の URL を放棄する場合は、ユーザーのために、永続的にリダイレクトを処理するアクションを必ず含めるようにします。

まとめ

Web ページから ASP.NET MVC への移行の影響を明確にするため、移行前と移行後のフォト ギャラリー サイトの構造の違いを確認してみましょう。図 6 の左側が、WebMatrix を使用した Web ページ サイトの構造です。右側は、ASP.NET MVC への移行が完了した後のこのサイトの構造です。構造に違いはあっても、移行後の内容の多くは、違和感を感じないと思います。

Application Layout Before and After

図 6 移行前と後のアプリケーションのレイアウト

現在、ASP.NET 開発者はフレームワークを Web フォーム、Web ページ、および ASP.NET MVC の 3 種類から選ぶことができます。それぞれに長所がありますが、どれか 1 つを選択しても、別のフレームワークを利用できなくないわけでも、さらには、将来、まったく移行ができないわけでもありません。また、この 3 つのフレームワークはいずれも、ASP.NET を基盤に構築されているため、技術的な理由で、フレームワーク間の移行が妨げられることはありません。実際に移行する場合、Web ページと ASP.NET MVC は似ているため、変更なしで NuGet、Razor、Web 配置、IIS Express、SQL Compact などのテクノロジを継続して使用できます。

Web ページを使用してアプリケーションを構築し、移行が得策であると判断した場合、機能別のフォルダーを使用してページをグループ分けする、すべてのリソースに 相対 URL を使用する、各ページの先頭にすべてのビジネス ロジックを配置するなど、特に、Web ページ サイトで事前の設計をしている場合は、Web ページから ASP.NET MVC への移行が最も問題の少ないパスです。このような準備をしておくと、実際に移行する段階では、意図したとおり、滞りなく、シンプルに、Web ページから ASP.NET MVC に移行できます。

ここで使用したものを含め、さまざまな手法やテクノロジへのリンクについては、bit.ly/WebMatrixToMVC を参照してください。

Brandon Satrom は、テキサス州オースティン郊外でマイクロソフトの開発者エバンジェリストとして活躍しています。彼のブログは userInexperience.com (英語) で、ポッドキャストは DeveloperSmackdown.com (英語) で公開されており、Twitter は twitter.com/BrandonSatrom (英語) でフォローすることができます。

Clark Sell は、シカゴ郊外でマイクロソフトのシニア開発者エバンジェリストとして活躍しています。彼のブログは csell.net (英語) で、ポッドキャストは DeveloperSmackdown.com (英語) で公開されており、Twitter は twitter.com/csell5 (英語) でフォローすることができます。

この記事のレビューに協力してくれた技術スタッフの Phil Haack および Erik Porter に心より感謝いたします。