WebSurfer's Home

トップ > Blog 1   |   Login
Filter by APML

コレクションのデータアノテーション検証

by WebSurfer 1. September 2014 18:25

ASP.NET MVC Web アプリケーションでユーザー入力の検証を行う場合、MVC2 以降ではデータアノテーション検証を標準で使用することができます。

データアノテーション検証

データアノテーション検証とは、簡単に言えば、入力モデルのクラスの public プロパティにアノテーション属性を付与することによって、クライアントから送信されてきたデータをアクションメソッドのパラメータにバインド(モデルバインディング)する際に、付与した属性に従って検証を実行し、その結果を ModelStateDictionary(Controller.ModelState プロパティで取得できます)に格納することです。

記事としてはちょっと古いのですが、Microsoft が提供するチュートリアルの [C#] #21. データ アノテーション検証コントロールでの検証 がまとまっていて理解しやすいと思います。← このチュートリアルはリンク切れになってしまいました。別の記事「データ注釈検証コントロールに (c#) を使用した検証」を紹介しておきます。

上記のサーバーサイドの検証に加えて、MVC3 以降ではクライアントサイドでの jQuery ライブラリによる検証もデフォルトで実装されるようになっています。

モデルに付与したアノテーション属性と EditorFor などの Html ヘルパーが連動して、レンダリングされる html 要素(例: <input type="text" ... />)に jQuery ライブラリによる検証機能が働くように必要な属性(例: data-val="true" など)を追加します。

クライアントサイドで検証結果 NG になるとエラーメッセージを表示し、submit はキャンセルされます。それゆえ、検証結果 NG のときはクライアントとサーバーの間の無駄なやりとりは起こりません。

さて、ちょっと前置きが長くなりましたが、ここでの本題、入力モデルが複合型のコレクションで入れ子になっているような複雑な場合、モデルバインディングとデータアノテーション検証(クライアントサイドを含む)をどう実装できるかという話を以下に書きます。

まずコレクションのモデルバインディングですが、それがうまく行われるようにするには、レンダリングされる html 要素の name 属性が連番のインデックスを含むようにします。

具体的には、name="prefix[index].Property" というパターンにします。prefix の部分にはアクションメソッドのパラメータ(仮引数)名が入ります。index は 0 から始まる連番です。数字の連続が途切れた場合は解析が停止し、0 から途切れる前までのデータが返されます。

マイクロソフト公式解説書の「プログラミング ASP.NET MVC」という本の 3.2.2 章に例がありますが、そこではビューで以下のようなコードで name 属性に連番のインデックスを持つ名前を設定しています。

var index = 0;
foreach (var country in Model.CountryList)
{
  <fieldset>
    <div> 
      <b>Name</b>
      <br />
      <input type="text" 
        name="countries[@index].Name" 
        value="@country.Name" />
      <br />
      <b>Capital</b>
      <br />
      <input type="text" 
        name="countries[@index].Details.Capital" 
        value="@country.Details.Capital" />
      <br />
      <b>Continent</b>
      <br />
      @{
        var id = String.Format(
                "countries[{0}].Details.Continent", 
                index++);
       }
       @Html.TextBox(id, country.Details.Continent)
       <br />
     </div>
   </fieldset>
}

上記のコードで countries はコントローラーの当該アクションメソッドの IList<Country> 型の仮引数の名前と一致させています。そうすることにより、クライアントから送信されてきたデータが正しくモデルバインディングされ、アクションメソッドに引き渡されます。

次に、これにデータアノテーション検証(クライアントサイドを含む)を追加するにはどうすればいいでしょう?

必要なアノテーション属性を入力モデルに追加するだけでもサーバーサイドでの検証は可能になります。しかし、それだけではクライアントサイドでの検証は動きません。

なぜなら、ASP.NET がレンダリングする html 要素には、クライアントサイドでの jQuery ライブラリによる検証に必要な属性(例: data-val="true" など)は追加されないからです。

検証に必要な属性が追加されるようにするにはビューに EditorFor のような Html ヘルパーを使うことです。これにより name 属性に設定する連番のインデックスも ASP.NET が自動的に追加してくれます。

モデル、コントローラー、ビューのコード例は以下の通りです。これを動かした結果が上の画像です。

(1) Model

モデルには普通に RequiredAttribute 他必要なアノテーション属性を追加すれば良いです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;

namespace Mvc4App.Models
{
  public class Country
  {
    public Country()
    {
      Details = new CountryInfo();
    }

    [Required(ErrorMessage = "{0} は必須")]
    [StringLength(15, ErrorMessage = "{0} は {1} 文字以内")]
    [Display(Name = "国名")]
    public String Name { get; set; }

    public CountryInfo Details { get; set; }
  }

  public class CountryInfo
  {
    [Required(ErrorMessage = "{0} は必須")]
    [StringLength(15, ErrorMessage = "{0} は {1} 文字以内")]
    [Display(Name = "首都")]
    public String Capital { get; set; }

    [Required(ErrorMessage = "{0} は必須")]
    [StringLength(15, ErrorMessage = "{0} は {1} 文字以内")]
    [Display(Name = "大陸")]
    public String Continent { get; set; }
  }

  public class ListCountriesViewModel
  {
    public ListCountriesViewModel()
    {
      CountryList = new List<Country>();
      SelectedCountries = new List<Country>();
    }
    public IList<Country> CountryList { get; set; }
    public IList<Country> SelectedCountries { get; set; }
  }
}

(2) Controller

アクションメソッドの仮引数の名前は、本にあったコード例の countries から countrylist に変更しています。これは、モデルの ListCountriesViewModel クラスのプロパティ名 CountryList と合わせる必要があるためです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Mvc4App.Models;

namespace Mvc4App.Controllers
{
  public class ComplexController : Controller
  {
    [ActionName("Countries")]
    public ActionResult ListCountriesForGet()
    {
      var defaultCountries = GetDefaultCountries();
      var model = new ListCountriesViewModel { 
                CountryList = defaultCountries };
      return View(model);
    }

    [HttpPost]
    [ActionName("Countries")]
    public ActionResult ListCountriesForPost(
            IList<Country> countrylist)
    {
      if (!ModelState.IsValid)
      {
        var model = new ListCountriesViewModel
        {
          CountryList = countrylist
        };

        return View(model);
      }
      else
      {
        var defaultCountries = GetDefaultCountries();

        var model = new ListCountriesViewModel
        {
          CountryList = defaultCountries,
          SelectedCountries = countrylist
        };

        return View(model);
      }            
    }

    private static IList<Country> GetDefaultCountries()
    {
      var countries = new List<Country>();
      countries.Add(new Country() { 
                Name = "Italy", 
                Details = new CountryInfo { 
                    Capital = "Rome", 
                    Continent = "Europe" } });
      countries.Add(new Country() { 
                Name = "Spain", 
                Details = new CountryInfo { 
                    Capital = "Madrid", 
                    Continent = "Europe" } });
      countries.Add(new Country() { 
                Name = "USA", 
                Details = new CountryInfo { 
                    Capital = "Washington", 
                    Continent = "NorthAmerica" } });
      return countries;
    }
  }
}

(3) View

EditorFor(m => m.CountryList[0].Name) からは name="CountryList[0].Name" という name 属性が生成されます。それゆえ、コントローラーのアクションメソッドの仮引数の名前を countrylist にしています。(注:モデルバインディングでは大文字小文字は区別されません)

@model Mvc4App.Models.ListCountriesViewModel

@{
  ViewBag.Title = "Countries";
  Layout = "~/Views/Shared/_Layout.cshtml";
}

@using (Html.BeginForm())
{
  <h2>Select your favorite countries</h2>

  for (int i = 0; i < Model.CountryList.Count; i++)
  {
    <fieldset>
    <div> 
      @Html.LabelFor(m => m.CountryList[i].Name)
      @Html.EditorFor(m => m.CountryList[i].Name)
      @Html.ValidationMessageFor(m => m.CountryList[i].Name)
      <br />
      @Html.LabelFor(m => m.CountryList[i].Details.Capital)
      @Html.EditorFor(m => m.CountryList[i].Details.Capital)
      @Html.ValidationMessageFor(m => m.CountryList[i].Details.Capital)
      <br />
      @Html.LabelFor(m => m.CountryList[i].Details.Continent)
      @Html.EditorFor(m => m.CountryList[i].Details.Continent)
      @Html.ValidationMessageFor(m => m.CountryList[i].Details.Continent)
      <hr />
    </div>
    </fieldset>
  }
    
  <input type="submit" value="Send" />
} 
  <hr />
    
  <h2>Countries submitted</h2>
  <ul>
  @foreach (var country in Model.SelectedCountries)
  {
    <li>@country.Name</li>
  }
  </ul>

@section Scripts {
  @Scripts.Render("~/bundles/jqueryval")
}

Tags: ,

MVC

MVC4 インターネットアプリケーション

by WebSurfer 23. July 2014 17:11

世の中はすでに VS2013 + MVC5 の時代で、今さら VS2010 + MVC4 の話でもなさそうですが、せっかく先日自分の開発環境の VS2010 で MVC4 を使えるようしましたので、手始めに「インターネットアプリケーション」テンプレートを使って MVC4 Web アプリを作ってみました。下の画像がその初期画面 (Home/Index ページ) です。

ASP.NET MVC 4 インターネットアプリケーション

テンプレートメニューの「インターネットアプリケーション」というのは、フォーム認証を使用するインターネット向け ASP.NET MVC4 プロジェクトの骨格を自動生成するためのものです。

先の 記事 で書きましたように、MVC4 にはいろいろ新機能が追加されていますが、「インターネットアプリケーション」テンプレートで作る Web アプリはあまり関係なさそうです。

ただし、ASP.NET MVC 4 リリースノート に書かれている New Features の内、以下の 2 つの新機能は「インターネットアプリケーション」にも取り入れられてます。

その内、後者のフォーム認証関係についていろいろ調べて分かったことがありますので備忘録として書いておきます。前者の Bundling and Minification についてはまだ勉強中なので、後日改めて書く予定です。調べる気力が無くならなければですが・・・(笑)

なお、VS2013 + MVC5 では ASP.NET Identity という新しいシステムに変更になっており、それと Simple Membership を含む従来のメンバーシッププロバイダは互換性がないようです。

ということは、MVC4 で Simple Membership を使ったのは一時しのぎ的な処置で、この記事を書くために一生懸命(?)調べた以下のことは、あまり今後の役には立たないのかもしれません。(泣)

(1) ユーザー情報のストア

フォーム認証用のユーザー情報のストアとして使用されるデータベースは、Simple Membership(ローカルアカウント用)と OAuth / OpenID(Facebook, Google などの外部アカウント用)が共用できるものに変わりました。SQL Server Management Studio でそのデータベース見ると、以下のようになってます。

自動生成されたデータベース

MVC3 までは、VS2010 のメニューバー[プロジェクト(P)]⇒[ASP.NET 構成(T)]で起動できる[ASP.NET Web サイト管理ツール]を使用して、アプリケーションルート直下の App_Data フォルダに ASPNETDB.MDF という名前の SQL Server 用データベースファイルを作り、これに SQL Server Express の ユーザーインスタンス を利用して接続し、SqlMemberShipProvider 経由でアクセスしていました。(注:あくまで開発環境でのデフォルトの話です)

MVC4 では、データベースは Entity Framework Code First の機能と、WebSecurity クラスの機能を利用して自動生成されます。なので、MVC4 のデフォルトのフォーム認証システムを使う限り[ASP.NET Web サイト管理ツール]は使いません。(使うことは可能ですが)

自分の開発環境(Vista SP2, VS2010 Professional, ASP.NET 開発サーバー, SQL Server 2008 Express。 LocalDB は利用不可)で試してみました。

まず、VS2010 の「インターネットアプリケーション」テンプレートで MVC4 Web アプリを作った時点で、以下のような接続文字列がアプリケーションルート直下の web.config に自動的に設定されます。ちなみに、データベース名 (Initial Catalog) は aspnet-<アプリケーション名>-<作成日時> となるようです。

<connectionStrings>
  <add name="DefaultConnection" 
    connectionString="Data Source=.\SQLEXPRESS;
        Initial Catalog=aspnet-Mvc4App-20140609121802;
        Integrated Security=SSPI" 
    providerName="System.Data.SqlClient" />
</connectionStrings>

この時点では接続文字列が作られるだけで、まだデータベース本体は作られていません。

その後、Web アプリを ASP.NET 開発サーバー上で立ち上げてブラウザに表示し、画面の右上にある[登録]または[ログイン]ボタンをクリックすると、Web アプリが上記の接続文字列をベースに SQL Server Express のインスタンスに接続し、Instid\MSSQL\DATA フォルダにデータベースを作成してアタッチします。(上の接続文字列の通り、ユーザーインスタンスではなく、名前つきインスタンス .\SQLEXPRESS に接続して利用できるようになります)

データベースの自動生成のメカニズムは以下の通りです。

データベースの生成のためのコードは Filters フォルダの中の InitializeSimpleMembershipAttribute.cs クラスファイルに含まれています。そこにはアクションフィルターとして InitializeSimpleMembershipAttribute クラスが定義されいて、それがコントローラーの AccountController クラスの属性として付与されています。

そのアクションフィルターにより、AccountController クラスのアクションメソッドの実行前に LazyInitializer.EnsureInitialized メソッド が呼び出され、それによって以下の SimpleMembershipInitializer クラスが初期化されるようになっています。

private class SimpleMembershipInitializer
{
  public SimpleMembershipInitializer()
  {
    Database.SetInitializer<UsersContext>(null);

    try
    {
      using (var context = new UsersContext())
      {
        if (!context.Database.Exists())
        {
          // Create the SimpleMembership database without Entity 
          // Framework migration schema
          ((IObjectContextAdapter)context).ObjectContext.
              CreateDatabase();
        }
      }

      WebSecurity.InitializeDatabaseConnection(
                        "DefaultConnection", 
                        "UserProfile", 
                        "UserId", 
                        "UserName", 
                        autoCreateTables: true);
    }
    catch (Exception ex)
    {
      throw new InvalidOperationException("The ASP.NET ...", ex);
    }
  }
}

従って、ブラウザの画面で[登録]や[ログイン」がクリックされると、この時点で SimpleMembershipInitializer がまだ初期化されていなければ、上記コードのコンストラクタを使って初期化を行います。

その際、接続文字列で指定される SQL Server のインスタンスにデータベースやテーブルが存在しない場合は必要に応じて作成します。まず ObjectContext.CreateDatabase メソッドがデータベースと UserProfile テーブルを、次に WebSecurity.InitializeDatabaseConnection メソッド が webpages_Membership, webpages_OAuthMembership, webpages_Roles, webpages_UsersInRoles テーブルを作成します。(実際に動かしてその順序で生成されることを確認しました)

Microsoft のチュートリアル Entity Framework での新しいデータベース向けの Code First によると、"ローカルの SQL Server Express インスタンスを使用できる場合、Code First ではそのインスタンス上にデータベースが作成されます。SQL Server Express を使用できない場合、Code First では LocalDb の使用を試みます。" とのことです。

ということは、VS2010 が開発環境における SQL Server Express インスタンスの有無を判定して、そのインスタンス上にデータベースを作成できるように接続文字列を生成したということのようです。

開発環境に SQL Server Express がなく、LocalDB が使用できる場合は、LocalDB 用に .mdf ファイルが自動生成されて既定のフォルダに置かれ、接続文字列も LocalDB 用の設定になるそうです・・・が、自分は検証できる環境を持ってないので、その確認はできていませんけど。

(2) Simple Membership

ローカルアカウント(FaceBook, Google などの外部アカウントでない方)のフォーム認証に使用するメンバーシッププロバイダには、MVC3 まででデフォルトで使用されていた SqlMembershipProvider ではなく、SimpleMembershipProvider が使用されます。

想像ですが、Simple Membership を使った理由は、OAuth / OpenId による認証と併用するのに、シンプルな分相性が良いためではないかと思います。

もともと、SimpleMembershipProvider は、WebMatrix という開発環境を利用して作る Web Pages アプリに用いられるフォーム認証用のメンバーシッププロバイダで、SqlMembershipProvider など従来のメンバーシッププロバイダの簡易版ということのようです。

従来のメンバーシッププロバイダと同様に MembershipProvider 抽象クラス を継承しており、Membership クラス 経由でアクセスできますが、MembershipProvider クラスに定義されている全てのプロパティ、メソッドが実装されているわけではなく、実装されていないメンバーにアクセスすると例外がスローされるそうです。

なので、Web アプリでは直接 SimpleMembershipProvider を操作する(実際には Membership クラス経由の操作になりますが)のではなく、WebSecurity ヘルパークラスを使用することが推奨されています。

実際、テンプレートで自動生成されるコードでは WebSecurity ヘルパークラスを使用して、ユーザーの登録、ログイン、ログオフに必要なアクションメソッドとビューが実装されています。

(3) ロール

ロール(例:マネージャー、ゲスト、管理者、メンバーなどのグループ分け)による承認・アクセスコントロールも、もちろん利用できます。

ただし、テンプレートで作成する Web アプリには、ロールの作成・削除、ユーザーのロールへの割当・削除を行うためのアクションメソッドやビューは実装されていません。なので、ロールを利用するためには必要なコードを自力で書いて、Web アプリに追加する必要があります。

上に書いた WebSecurity クラス、SimpleMembershipProvider にはロールを操作する機能は含まれません。

ロールの操作は、SimpleRoleProvider クラス を利用してデータベースにアクセスして行います。ただし、SimpleRoleProvider に直接アクセスするのではなく、Roles クラス を使用します。

具体的なコード例は Working with Roles in ASP.NET MVC 4+ が参考になると思います。

そこには、Roles.GetAllRoles, Roles.CreateRole, Roles.DeleteRole, Roles.IsUserInRole, Roles.AddUserToRole, Roles.GetRolesForUser, Roles.RemoveUserFromRole というメソッドを使って、ロールの作成・削除、ユーザーのロールへの割当・削除を行うためのアクションメソッドやビューのサンプルが記載されています。

自分でもそのページを参考にロールの操作のためのアクションメソッドとビューを実装してみました。下の画像は、Admin, Member, Moderator という 3 つのロールを作成した結果を示します。

設定されたロール

作成したロールは、ローカルアカウントのユーザーはもちろん、FaceBook, Google などの外部アカウントのユーザーにもアサインできます。アサインした結果は webpages_UsersInRoles テーブルに保存されます。

上記のアクションメソッドやビューを操作しなくても、Web サイトを起動するときに、管理者ロールとそれに属するユーザーを自動的に作ってしまう方法もあります。その具体例は Seeding & Customizing ASP.NET MVC SimpleMembership が参考になると思います。

(4) プロファイル

プロファイルとは、例えば登録済みユーザーの名前、住所、メールアドレスといった情報を格納・管理するための機能です。MVC4 のフォーム認証システムでも利用できるようになっています。

ただし、従来のように SqlProfileProvider を使って Web アプリケーションプロジェクトでプロファイル 情報を管理するのとはかなりメカニズムが異なります。

MVC4 の「インターネットアプリケーション」テンプレートで作る Web アプリでは、プロファイル情報の格納には、自動生成されるデータベース(詳しは、上の「(1) ユーザー情報のストア」のセクションを参照ください)の UserProfile テーブルを使用できます。

UserProfile テーブルが生成された時点では UserId と UserName というフィールドしかありませんが(この記事の上から 2 番目の画像を見てください)、これに必要な情報を追加できます。

例えば、ユーザーの email 情報をプロファイルに追加するとします。

それにはまず、Models フォルダの AccountModels.cs クラスファイルの中の UserProfile クラスのコードに Email プロパティの定義を追加します。以下のような感じです。

[Table("UserProfile")]
public class UserProfile
{
  [Key]
  [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
  public int UserId { get; set; }
  public string UserName { get; set; }

  // Email プロパティを追加。
  public string Email { get; set; }
}

次に、データベース内の UserProfile テーブルに Email 列を追加します。Entity Framework Code First Migrations 機能を使うと SQL Server のデータベースを直接操作しなくても列の追加ができるそうです。

ただし、自分は Migrations 機能の使い方が分からなかったので、SQL Server Management Studio で直接 UserProfile テーブルにアクセスし、Email 列を追加しました。(笑) それだけで Email 列にアクセスできるようになります。(EDM の再構築が必要かと思ってましたが、自動的に処置されるようで、自分では何もする必要はなかったです)

データには以下のようなコードでアクセスできます。

using (UsersContext context = new UsersContext())
{
  string username = User.Identity.Name;
  UserProfile user = context.UserProfiles.SingleOrDefault(
                             u => u.UserName == username);
  string email = user.Email;
}

Facebook などの外部アカウントを使用する場合、プロバイダによって提供されるユーザー情報 が異なるのが問題です。なので、UserProfile テーブルを外部アカウントのユーザー情報のストアに共用するのは難しそうです。

外部アカウントのユーザー情報は UserProfile テーブルとは別のテーブルを作ってそこに格納するという方法もあります。具体的な方法は、Facebook の例ですが、Microsoft ASP.NET サイトの記事 Using OAuth Providers with MVC 4 が参考になると思います。

(5) OAuth / OpenId

MVC4 には、OAuth 認証または OpenId 認証を利用して、Facebook, Twitter, Google, Microsoft のアカウントを使ってログインできる機能が追加されています。

詳しい手順は以下のページが参考になると思います:

自分でも上のページを参考に Facebook と Google で試してみました。

Google の場合は登録やキーの取得など事前準備は何も必要ありません。Facebook の場合は開発者としての登録、アプリケーションの登録、キーの入手の入手が必要です。MSDN Blog で紹介されている内容(古いようです)とはかなり画面が異なりますが基本は同じで、特に難しいことはないと思います。

Facebook からキーが入手できたら AuthConfig.cs ファイルの AuthConfig クラスの定義に以下のように設定してやります。Google の方はコメントアウトされた OAuthWebSecurity.RegisterGoogleClient(); を有効するだけで OK です。

namespace Mvc4App
{
  public static class AuthConfig
  {
    public static void RegisterAuth()
    {
      //OAuthWebSecurity.RegisterMicrosoftClient(
      //    clientId: "",
      //    clientSecret: "");

      //OAuthWebSecurity.RegisterTwitterClient(
      //    consumerKey: "",
      //    consumerSecret: "");

      OAuthWebSecurity.RegisterFacebookClient(
        appId: "14632444xxxxxxxx",
        appSecret: "bcc92eee6910218f0646ae3fxxxxxxxx");

      OAuthWebSecurity.RegisterGoogleClient();
    }
  }
}

この後、Visual Studio から Web アプリを起動して、初期画面の右上にある[ログイン]ボタンをクリックすると、以下のようなログイン画面が表示され、Facebook と Google のアカウントを使ってのログインが有効になっているのが分かります。

ログイン画面

上の画面で[Facebook]または[Google]ボタンをクリックすると、そのプロバイダのログイン画面が現れます。Facebook の場合は下の画像のようになります。(以下、すべて Facebook の例です)

Facebook のログイン画面

上記の画面でユーザーが ID(メールアドレス)とパスワードを入力してログインし、外部プロバイダの認証が通ると、Facebook から Web アプリにユーザー情報を渡して良いか否かを確認するためのページが表示されます。下の画面のようになります。

ユーザー情報提供の確認画面

上の画面で[OK]をクリックすると、Facebook からユーザー情報が Web アプリに渡され、ユーザー情報を Web アプリに登録するため、下の画面が表示されます。

ユーザー情報の登録画面

上の画像で、[ユーザー名]テクストボックスに Web アプリで使いたい任意の名前を入力し、[登録]ボタンをクリックすると、Web アプリのデータベースの UserProfile, webpages_OAuthMembership テーブルにユーザー情報が登録されます(初回のみ)。

一旦登録されれば、次回からはプロバイダのログイン画面でログインすれば、上に書いた確認や登録のページは飛ばして、Web アプリ上でユーザー認証が完了します。

(6) Database First の EDM との共存

上に書きましたように、ユーザー情報のストアに使われるデータベースは Entity Framework Code First の機能を利用して作られます。これと Database First で作られた EDM は同じアセンブリ内で共存できないと言う問題があります。(少なくとも Ver. 4 では。最新版は不明です)

例えば、10 行でズバリ!! ASP.NET MVC におけるデータの取得から画面表​示までの流れ (C#) のような感じで、既存のデータベースのデータを表示、更新するため Entity Framework を用いて Database First で EDM を作成して追加したとします。

その後、ログインしようとすると "System.ArgumentException: 'Mvc4App.Models.Address' の概念モデルの型が見つかりませんでした。" というエラーが出ます。Mvc4App.Models.Address は Database First で作ったモデルです。

エラー画面

上の画像にあるように、例外がスローされた場所は AccountController です。

Mvc4App.Models.Address とは何ら関係ないのに、何故そのようなエラーがそんな場所で出るのかまったく分かず、半日ぐらいハマってしまいました。(笑)

解決策は、別アセンブリに分ける、即ち Database First で作る EDM は別プロジェクトにすることです。

その際注意しなければならないのは、Web アプリがその EDM 経由でデータベースに接続に行くということです。例えば、ビューで foreach (var item in Model) というようにすると、そこでデーターベースに接続に行きます。

それゆえ、Web アプリの web.config に接続に用いる接続文字列が必要です。これの解決にも半日ぐらいハマってしまいました。(笑)

ちなみに、接続文字列がないと "指定された名前付き接続は、構成内に見つからないか、EntityClient プロバイダーと併用することを意図していないか、または無効です。" というエラーになります。

web.config に接続文字列があっても、それに指定された .mdf ファイルの場所が違っている場合は "ファイル ...\App_Data\AdventureWorksLT_Data.mdf の自動的に名前が付けられたデータベースをアタッチできませんでした。同じ名前のデータベースが既に存在するか、指定されたファイルを開けないか、UNC 共有に配置されています。" というエラーになります。(このケースでは、ユーザーインスタンスへの接続になっています)

Tags: ,

MVC

VS2010 で ASP.NET MVC 4

by WebSurfer 14. July 2014 14:30

何を今さらと言われるるかもしれませんが、VS2010 でも ASP.NET MVC 4 を使用しての開発ができるということを知って、自分の開発マシンにもインストールしてみました。

VS2010 で ASP.NET MVC 4

実は、MVC4 は VS2012 以上でなければサポートされてないと誤解しており、VS2012 はシステム要件が Windows 7 以上ということで(自分の開発マシンの OS は Vista)諦めてました。(汗)

Visual Studio 2012 / ASP.NET MVC 4 正式リリース というブログに書いてあった Microsoft のダウンロードサイト Visual Studio 2010 SP1 および Visual Web Developer 2010 SP1 用 ASP.NET MVC 4 から AspNetMVC4Setup.exe と AspNetMVC4Setup_JPN.exe を入手してインストールしました。

インストールした結果、上の画像のように VS2010 でも MVC4 のテンプレートが利用できるようになりました。

この画面で[OK]ボタンをクリックすると下の画像のダイアログが現れ、MVC4 用に用意された (1) 空、(2) 基本、(3) インターネットアプリケーション、(4) イントラネットアプリケーション、(5) モバイルアプリケーション、(6) Web API という 6 種類のテンプレートから選べるようになっています。

MVC4 用テンプレート

VS2012 に実装されているテンプレートとは少し違いがあって、VS2010 には MVC4 の新機能の一つである Single Page Application 用のテンプレートがありません。ベータ版には実装されていたが、開発が間に合わず RC 版で削除されたそうです。

全ての機能はとてもまだ使いこなせてません。なので、Web や本の記事の受け売りですが、以下に主な新機能の概要を書いておきます。

  1. モバイルアプリケーション・テンプレート
    基本的な構造は、「インターネットアプリケーション」テンプレートで提供されるフォーム認証を使用するアカウントコントローラーを含むアプリケーションと同じだそうです。ただし、View のデザインに jQuery Mobile を使用することで、モバイル端末でのタッチ操作を行いやすい Web アプリケーションを開発できるようになっているそうです。
  2. Display Modes によるビューの切り替え
    デスクトップ PC ブラウザ向けの View と、モバイル端末ブラウザ向けの View をそれぞれ用意しておくことにより、ASP.NET MVC4 フレームワークが自動的にブラウザ種類を判断して View の切り替えを行う機能です。モバイル端末の種類ごとに View を用意し(例えば、iPhone 用とAndroid 用)切り替えることも可能とのことです。
  3. jQuery Mobile, View Switcher と Browser Overriding
    モバイル向け Web アプリケーション作成には、上に述べた「モバイルアプリケーション」テンプレートを利用するアプローチの他に、「インターネットアプリケーション」テンプレートをベースとした Web アプリケーションにモバイル端末向け View を追加するアプローチがあります。
    それには NuGet パッケージとして提供されている jQuery.Mobile.MVC を VS2010 の[ツール(T)]メニューからプロジェクトに追加します。それにより jQuery Mobile と Display Modes をベースとした View Switcher 機能が利用できるようになります。
    Browser Overriding は、ブラウザ上に表示されるリンクの操作で、デスクトップ用の表示とモバイル端末用の表示を切り替えるのに用いる MVC4 の新しい機能だそうです。
  4. ASP.NET Web API
    ブラウザやモバイルデバイスを含むさまざまなクライアントに対して RESTful なサービスを提供するのに適した HTTP サービス構築用のフレームワークです。
    このテンプレートを利用して、RESTful な CRUD (Create, Read, Update, Delete)処理に必要な HTTP サービスのため、POST, GET, PUT, DELETE それぞれの HTTP メソッドに対応したアクションメソッドの雛形を作成できます。 概要は MSDN Blog の記事 ASP.NET Web API を使ってみよう: MVC 4 新機能シリーズ が参考になると思います。
  5. ASP.NET Single Page Application
    JavaScript と Web API をベースとし、AJAX と HTML 5 を使用して、定期的にページを再読み込みしないで、ユーザーのアプリケーション操作に合わせてページを動的に更新し、滑らかで応答性の高い Web アプリケーションを作成するためのテンプレートだそうです。
    概要は MSDN マガジンの記事 単一ページ アプリケーション: ASP.NET を使用して最新の応答性の高い Web アプリケーションを構築する が参考になると思います。
    ベータ版の時点からサポートが外された JavaScript ライブラリもあるそうなので、VS2010 にこの機能を追加する場合はその点に注意する必要がありそうです。(VS2012 を使用したほうがよさそうです)

上記以外の MVC4 の新機能としては、Razor 構文(ASP.NET Web Pages 2)の新機能、JavaScript/CSS ファイルの縮小化と結合処置の自動化機能、Visual Studio コード生成のためのレシピ機能、非同期コントローラーの Task サポート、NuGet パッケージングマネージャーによるコンポーネント管理があります。

・・・が、とてもついていけないので説明は割愛します。もっと勉強しないと世の中の技術の進歩に付いていけないようです。(汗)

Tags:

MVC

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  October 2021  >>
MoTuWeThFrSaSu
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

View posts in large calendar