アーカイブ

Archive for the ‘ASP.NET 備忘録’ Category

Update 2 そして その先の話

TechEd North America 2014 がはじまりました。
ここ でセッションが見れるようになってくるかと。

で、VS2013 の Update 2 も発表になりました。

○Update 2 の概要

Visual Studio 2013 Update 2 is here!

○ASP.NET 関係の Update 2 での変更点

Announcing new Web Features in Visual Studio 2013 Update 2 RTM

 

ここまではまあ予想のうち。
で、.NET Framework に関して、この先の話まで発表されてます。

○VisualStudio に関する発表の全体像

Mobile-first, Cloud-first Development – Visual Studio 2013 Update 2 released, Visual Studio Apache Cordova Tooling preview and the future of .NET for Cloud and Server

The Next Generation of .NET – ASP.NET vNext

 

ASP.NET vNext に関しては、 Scott Hanselman の Blog が詳しいです。
というか、この Blog をみて何ができるようになるのかやっとわかりました。

Introducing ASP.NET vNext

とうとう IIS から切り離された形で ASP.NET が動き出す、んですね。
そか、ASP.NET は中でコンパイラはしってたから Roslyn が必要だった、、、んか?
とか、いろいろ考えるとこはあります。

まだ「次」はいつなのかはっきりしませんが、こんなセカイが近づいていると思うとわくわくしますね。

カテゴリー:.NET, ASP.NET 備忘録, VS2013

Identity 2.0 の有用な情報かな?

すみません、自分でまとめたんじゃありません(w

ASP.NET MVC and Identity 2.0: Understanding the Basics

ASP.NET Identity 2.0: Setting Up Account Validation and Two-Factor Authorization

基本的な情報と実際に使うために必要な設定情報とかがまとめられているようです。
自分としては outlook.com をつかったメールの送信方法のサンプルがうれしかったり(w

だいぶ変わったけど、しっかり「使える」ものになっていると感じます。
まずは空のプロジェクトつくって

PM> Install-Package Microsoft.AspNet.Identity.Samples –Pre

とやって、サンプルプログラムを動かしてみるのがよいかと。

ただ、このサンプル、結構コード量が多いんですよね。

Update 2 では Identity 2.0 がテンプレートに入ってくるんだと思うけど、どこまでの機能を持たせたものになるのかなぁ。。。

最新の GridView なら、、、の裏側

間があいてしまいましたが。
前回の記事でほのめかしておいた、ItemType プロパティを設定したときになにが起きてるのか、というあたりをちょっとのぞいてみましょう。

まず、GridView の AutoGenerateCollumns プロパティを false にして、BoundField コントロールとして ID、Name、Mail の各項目を追加します。

image

こんな感じになります。
で、実行して動作を確認すると、、、

image

こんな動きをします。
ItemType を追加した直後とちょっとちがいますね?

さて、BoundField コントロールをすべて DynamicField コントロールに置き換えましょう。

image

これで動かすと、

image

はい、ItemType を追加したときと同じ動きになりました。

これでわかりますかね?
ItemType を設定する前は GridView の内部では BoundField コントロールが使われていて、ItemType を追加すると、DynamicField コントロールが使われるんですね。

GridView の内部で使われるコントロールが変化するあたりは ASP.NET 4 で追加された EnableDynamicData 拡張メソッドを利用したときと一緒です。
というか、拡張メソッドを利用するのはちょっと面倒だったんですが、ItemType プロパティを設定するだけで動くようになった、というのが正しいんですかね?

DynamicField コントロールは検証コントロールまで自動的に追加してくれるのでクライアント側の検証が動作するんですね。
クライアント側の検証では「控えめなバリデーション」が使われるようになったのは 4.5 からなんですが、そのあたりは kiyokura さんの Blog のこの記事で確認してもらうのがよいかな?

DynamicField コントロールについては別にもう少し掘り下げてみようかと思います。
というか、ちょっと面白い動きしたはずなんですが、いま確認とってないので確認でき次第まとめる、ということで。

DynamicField コントロール面白いんですけどね。
いかんせん、情報がないですよね。
EnableDynamicData 拡張メソッドの話も、日本語だと私の Blog の記事とナオキ君が CodeZine に書いた記事ぐらいしか見つからないし。。。

あ、ひとつ注意点を。
DynamicField コントロールを明示的に記述して使うとき、ItemType プロパティの設定を削除するとエラーになります。
VSUG Day でのセッションを聞かれた方は覚えてるかもしれませんが、最後のほうで DynamicField コントロール使おうとしてエラーになって動かなかったのはこのせいでした。

ItemType プロパティのからみで、もうひとつ。
ItemType プロパティを設定しなくてもモデルバインディングは動きます。
それは前回の記事の動作で確認できますよね。

このモデルバインディング、ASP.NET MVC のように汎用的に使えるといろいろと面白いんですが、WebForms ではどうやら特定のコントロールでのみ使えるような感じです。
このあたりもきちんと調べてみないと。。。

というところで、今回の記事はここまで。
次は、、、モデルバインディングの話が先になるかな?

カテゴリー:.NET, ASP.NET 4.5, ASP.NET 備忘録

最新の GridView なら検証の設定も楽々!

※この記事は One ASP.NET Advent Calender の21日分のエントリーです。
21日分、、、

前の記事では GridView の SelectMethod プロパティを設定してデータの抽出を行いました。
データの更新には UpdateMethod を利用します。

image

GridView に UpdateMethod と AutoGenerateEditButton プロパティの設定を追加します。

image

UpdateMember メソッドの実装はこんな感じです。
ASP.NET MVC を使ったことのある人にはわかりやすいですね。
UpdateMember メソッドは Member 型の引数をとっていますが、これはモデルバインダーという仕組みが今回 WebForms にも採用されているからできることです。
モデルバインダーはブラウザからのリクエストであがってきたデータを、モデル(上記の場合は Member)のプロパティ名と照らし合わせて、自動的に Member 型のインスタンスを生成してくれます。

データの追加の部分は EntityFramework の最近のバージョン(4.2からじゃなかったかな?)ではこういう記述でデータの追加ができます。

image

デバッグの実行を開始すると編集リンクが追加されていて、データの編集が可能になっています。
Name を「おの2」としてデータが更新できることを確認してみましょう。

image

さて、ここから今日の本題。
以前の GridView では、データの更新時に検証を行おうとすると、データのフィールドをテンプレートフィールドにして、そこに検証コントロールを一つ一つ貼っていかないといけない、というかなり手間のかかるものでした。
それが、今なら。。。

まず、GridView のすぐ下あたりにエラー時のメッセージを表示するために ValidationSummary を貼り付けます。

image

Member クラスの Name プロパティに Required 属性を追加します。
Name を必須の入力項目にするわけですね。

image

Member クラスは EDM を作り直したら上書きされますので、そのような操作を行うときは注意しましょう。
まぁ、どんな属性を設定したか覚えておけばいいだけの話です。
そして UpdateMember メソッドをちょっと修正します。

image

このあたり、ASP.NET MVC と同様ですね。
で、デバッグ実行して Name を空にして更新しようとすると、

image

このように、きちんと必須チェックを行ってくれるようになります。
モデルバインダーが Member のインスタンスを生成する際、設定されている属性によるチェックも自動的に実施してくれて、エラーの状態まで登録してくれるのでこのようになるんですね。

エラーの状態はプログラムで追加することもできます。

image

こんなふうに ModelState にエラー状態を追加すると、どんな場合でも更新できなくなります。

image

まあ、ふつうは独自の更新チェックの条件を追加する場合に使うんですけどね。

ここまででも便利は便利なのですが、もうひとつ。

image

GridView の ItemType プロパティに Member クラスを設定します。
そうすると、

image

さっきのすべての更新をエラーにするプログラムを修正していないのに、必須入力の検証が行われて、またそのチェックが実行された項目に「*」が表示されています。
これ、HTMLをみるとわかりますがクライアント側でスクリプトによる検証が行われているんですね。

ItemType プロパティを設定することで何が起きてるのか。。。
という話を続けるには記事がながくなりすぎたので、それは次の機会にしたいと思います。

しかし、GridView、かなり使えるやつになってると思いません?
環境が許すならどんどん使っていきたいですね。

カテゴリー:.NET, ASP.NET 4.5, ASP.NET 備忘録

最新の GridView ならページングもソーティングも楽々!

この記事は One ASP.NET Advent Calender の20日のエントリーです

GridView は便利なんですけど、ページングやソーティングをしっかり実装しようとするとなかなか手ごわいですよね。
データ量が限られてるのがわかってるなら SqlDataSource でさくっと動かしてもいいんですけど、のちのち問題になるのわかりきってますしねぇ。。。

と、面倒だった実装が最新(4.5)版の GridView なら楽々です。
ということでとにかく動かしてみましょう。

さて、まずは新しい Web サイトで ASP.NET Web フォームサイトを作って DB を追加します。
DB じゃなくてもいけるはずですが、明日もこの環境使うために DB で。
そして WebForms で CodeFirst で簡単に DbContext 作る方法がわかってないので DB First で Entity Framework 使っていきたいと思います。

#ASP.NET MVC なら POCO のクラス書くだけであとはスキャッフォールディングにおまかせで DbContext 作ってくれるんですけどね。。。

と、気を取り直して DB 作成。

image

そそ、この新しいテーブルデザイン画面いいですよね。
なにがいいって IDENTITY の設定がワンクリックでできること。
最初は項目表示されてないので右クリックして表示項目を追加してあげるひつようがありますが。
あと、CREATE 文もぱっと目に入ってくるので SQL の勉強にもいいですよね。
つい保存ボタン押したくなっちゃうんですが、専用の「更新」メニューをクリックして DB つか Member テーブル作成、っと。
で、GridView でページングとソーティングの話ですから適当にデータつっこんでおきましょう。

さて、DB First ですから次は EDM 追加します。

image

image

もうデフォルト設定のままウィザードたたいて突っ走ってしまいますよ、と。。。

image

はい、できました、っと。
なんかセキュリティの警告でますけど、T4テンプレートでソース生成するときって出るみたいです。
なぜか連続2回。
まぁ、とにかく EDM できたけどタブに[*]ついてるので一回ビルド走らせておきます。

で、今回かなり優秀になってるな、と思ったのが

image

へんな名前空間とかなしで、Member クラスを生成してくれます。
これなら使い勝手いいですよね。

と、GridView はどうしたんだ、といわれそうなので新規でWebページを追加します。
で、いきなりコードを表示させて次のようなデータを呼び出してくるメソッドを追加します。

image

と、ここで待望の GridView です。
GridView を Web ページに追加して SelectMethod プロパティにさっき書いたメソッドを設定してあげましょう。

image

はい、ここでとりあえずデバッグ実行してみましょうか。

image

さくっとデータ拾ってきてますね。
では、本題のページングとソーティング。

image

プロパティの設定を3つ追加しました。
で、実行すると。。。

image

あらあら、エラーです。
でも、このエラーきちんと見ておいてくださいね。
LINQ に慣れてる人ならもうなんとなくわかるかも。
で、OrderBy つけろ、と言われているのでデータ取り出すとこにデフォルトのソート順設定しましょう。

image

ま、こんなとこでしょうか。
さて、デバッグ実行っと。

image

はい、ページングとソーティングのリンクが追加されました。
2ページめは、、、

image

ちゃんと表示されますね。
Name をクリックすると、、、

image

image

ソートした状態でのページングもOK、っと。
ソーティングの昇順降順もきちんと保持しているようで、同じソートリンクを何回もクリックするとそのたびに昇順降順が入れ替わります。

いやー、ここまでコード何行書きました?
いままでのあの苦労はなんだったんだろう、と思いません?

で、ちょっとだけ裏側を解説すると、さっきでたエラーで メソッド Skip を GridView が使ってるのがわかります。
Skip、Take は LINQ 使ってページングするときの定番ですよね。
SelectMethod で IQueryable を返しているので、そこに Skip、Take がのせられてデータをとってきてるんだろう、という推測ができます。
なら、ソーティングは当然 OrderBy が使われてるんだろうな、と。
LINQ は遅延実行されるので、実際に DB から取り出されるのは Skip、Take で指定された必要なデータのみ。
なので、ViewState の肥大化なんて気にすることなく安心して利用することができますね。

と、とりあえず今日はここまで。
明日は GridView 使ううえでやっぱり面倒だった検証関係をとりあげます。

そだ、最後にひとつ。
わかりやすいので GridView を例にあげてますけど、ほかのデータ操作系のコントロール、DetailsView、FormView、ListView、ListView でもこれ使えますからね。
便利になりますねぇ。。。

カテゴリー:.NET, ASP.NET 4.5, ASP.NET 備忘録

Form 認証に関するあれこれ

※この記事は One ASP.NET Advent Calender 2012 6日めのエントリーです。
ええ、6日分です。。。だれがなんといっても6日分です。。。

 

テンプレートに組み込まれているため、あまり考えもせずにさくっと使えてしまう Form 認証ですが、その実行を支えている要素についてあれこれ考えてみたいと思います。

 

○Form 認証を有効にする

Form 認証を有効にするには、web.config に authentication 要素を記述します。

<authentication mode="Forms" />

この設定は、ルートフォルダ直下のweb.configに記述する必要があります。

不思議なことに、 WebPages のテンプレートにはこの記述が存在しないのに、Form 認証が実行されます。
これは、SimpleMembershipProvider を含む WebMatrix.WebData.dll が登録されていると、アプリケーションの起動時に強制的に Form 認証を使うように設定されるためです。

 

○ログインの実行

WebFormsだとログインの実行に使われるのは Login コントロールです。
SqlMembershipProvier や Universal Membership Provider とともに使えば、コントロールを貼り付けるだけでログインの操作は自動でできるようになります。
ただ、これだとなかの動きはまったく見えませんね。

SimpleMembershipProvider とともに使われるのは WebSecurity.Login メソッドです。
ドキュメント中に記載がありますが、「ユーザーがログインすると、ASP.NET によって Cookie に認証トークンが設定されます。」
Loinコントロールも実は同じことをやっています。

この動きがはっきり見えるのは ASP.NET MVC 3 のテンプレート中の LogOn 時の動きです。
Membership.ValidateUser メソッドを使ってユーザーが登録されているかどうかを確認し、 FormsAuthentication.SetAuthCookie メソッドによって Cookie に認証トークンを設定しています。

ここで重要なことは、

  • ASP.NETのログインとはCookieに認証トークンを設定することである。
  • 認証トークンは FormsAuthentication.SetAuthCookie メソッドによって発行することができる

ということです。
なんらかの MembershipProvider を使わなくても、たとえば独自のデータベースの情報からユーザーが登録されているかどうかを判定して、FormsAuthentication.SetAuthCookie メソッドを使えば ASP.NET が用意している Form 認証の仕組みを使うことができるのです。

なお、Session の管理にも Cookie が使われますが、Session 用の Cookie と認証トークンとしての Cookie は別のものです。
Session と認証トークンはそれぞれ別に管理される、ということは覚えておいてよいことかと思います。

 

○ログインユーザーの認証

ログインすると Cookie に認証トークンが設定されることはわかりました。
では、この認証トークンはどのように使われるのでしょう。
このあたりは ASP.NET のフレームワークがうまくいろいろとやってくれるところです。
具体的には HttpApplication クラスのアプリケーションイベントの発生順をみてください。

ここの AuthenticateRequest イベントのタイミングで、フレームワークは認証トークンを解析し、HttpContext.User.Identity.IsAuthenticated に true を設定します。
まぁ、1リクエストを処理する間存在するある意味大域変数とも考えられる HttpContext にユーザーの情報を設定するわけです。

その後、AuthorizeRequest イベントのタイミングで承認(URLにアクセスする権限があるかの確認)が行われます。
承認の作業は HttpContext のユーザー情報を確認し、そのユーザーがアクセスする権限を持っているかどうかが判断されます。

 

○承認の設定

承認の設定は web.config に

<authorization>
  <deny users="?"/>
</authorization>

のように記述されます。
これは認証されていないユーザーへのアクセスを許可しない、という設定ですね。

web.config はフォルダごとに配置することが可能ですので、特定のフォルダに上記を含む web.config を配置すると、そのフォルダ内のリソースは認証されていないユーザーには表示されない、ということになります。

この設定は location 要素を利用することで特定のファイルにのみ設定を有効にすることも可能です。

<location path="Manage.aspx">
  <system.web>
    <authorization>
      <deny users="?"/>
    </authorization>
  </system.web>
</location>

また、location 要素にフォルダを設定することもできますので、各フォルダごとに web.config を配置するのではなく、ルートの web.config 内にすべての設定をまとめて記述することも可能です。

この承認の設定は、実際には URL に対して行われている、ということを理解するのが重要です。
ASP.NET MVC のように、フォルダの構成と URL の構成が一致しない場合、URL に合うように承認の設定を記述する必要があります。

ASP.NET MVC で /admin の中を認証ユーザーのみに公開したい、といったとき、 View フォルダ内の adminフォルダに 承認の設定を記述してもそれは有効になりません。
その場合、ルート直下にadminというフォルダを作成してしまってそこに承認の設定を配置するか、location を使って /admin にたいして承認の設定を記述すれば有効になります。

まぁ、実際には ASP.NET MVC では Authorize 属性をコントローラ(クラス)、またはアクション(メソッド)に設定することで承認の設定とするほうがわかりやすいでしょう。
この場合、web.config には承認の設定は記述しません。
そのため、HttpApplication の AuthorizeRequest イベント時には承認の解決は行われていません。
Authorize 属性は Actionフィルターの一種ですので、各アクションの実行直前のタイミングで承認が行われることになります。

○まとめ

ASP.NET の Form 認証がどのようにして実行されているかをまとめてみました。
ここに記述した内容が理解できていると、独自の認証の仕組みを構築するのに MembershipProvider のカスタマイズなんておおげさなことをしなくても、ちょっとした実装でそれなりの仕組みを構築できるようになっていることがわかるのではないかと思います。

実はこれから Membership の仕組みに新しいものが登場することになっています。(ロードマップ参照
ただ、ここに記述した認証/承認のベースの仕組みは ASP.NET 登場当時からのものであり、今後もこのベースそのものが変わることは考えにくいと思っています。
基礎となっている部分をしっかり理解していれば、新しい仕組みがでてきてもどこが違うのか、をおさえるだけで使えますから、このあたりの知識は無駄にならないんじゃないかなぁ、と思っています。

カテゴリー:.NET, ASP.NET 備忘録

ASP.NET MVC 2 で簡単データ検証

EnableDynamicDataを利用してWebフォームでDataAnnotationを使ったデータ検証方法をまとめてきましたが、DataAnnotationはASP.NET MVC 2でも利用できます。
その動作を確認できるサンプルを作成してみました。

ただし、サンプルアプリケーション自体の作り方についてはこの記事では説明しません。
ウィザードが生成するスキャッフォールドの状態に最低限の手しか入れてないので、説明する内容もほとんどないですし。

リストページ

サンプルアプリケーションを起動すると上記のようなページが表示されます。
ここでEditリンクをクリックし、データを適当に修正して更新しようとすると、以下のようなエラーが表示されます。

エラー1

このサンプルではEntity Data Modelを利用しています。
そして、上記のエラーを表示させるためのDataAnnotationの設定は以下のプログラムで行っています。

——————————————————————————————————————-

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.Data.Objects;

/// <summary>
/// Summary description for Person
/// </summary>
namespace MvcApplication2.Models
{
    [MetadataType(typeof(MetaPerson))]
    [CustomValidation(typeof(MetaPerson), "CheckAge_Mail")]
    public partial class Person
    {
    }

    public class MetaPerson
    {
        [DisplayName("ユーザID")]
        public int id { get; set; }

        [Required(ErrorMessage = "名前は必須項目です")]
        [DisplayName("名前")]
        public string name { get; set; }

        [DisplayName("年齢")]
        [Required(ErrorMessage = "年齢は必須項目です")]
        [Range(0, 120, ErrorMessage = "年齢に誤りがあります")]
        public int age { get; set; }

        [DisplayName("メールアドレス")]
        [RegularExpression(@"\w+([-+.’]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", ErrorMessage = "正しいメールアドレスを入力してください")]
        public string mail { get; set; }

        [DisplayName("備考")]
        [CustomValidation(typeof(MetaPerson), "CheckMinLength")]
        public string memo { get; set; }

        public static ValidationResult CheckMinLength(string memo, ValidationContext vCont)
        {
            if (memo == null || memo.Length < 5)
                return new ValidationResult("5文字以上入力入力してください");
            return ValidationResult.Success;
        }

        public static ValidationResult CheckAge_Mail(Person p)
        {
            if (p.age >= 20 && p.mail == null)
                return new ValidationResult("成人はメールアドレス必須です");
            return ValidationResult.Success;
        }
    }
}

——————————————————————————————————————-

ここで注目してほしいのはPersonクラスに対してCustomValidation属性を設定しているところです。
Personクラスが持つ複数のプロパティの状態をチェックしてエラーを表示することができます。
EnableDynamicDataを利用した場合は、クラスにCustomValidation属性を設定してもそこでのエラーをうまくひろって表示してくれませんでした。
そのため、イベントを登録してデータを保存する直前でValidationExceptionを返すといったプログラムを記述する必要がありました。
ASP.NET MVC 2では同じ内容をCustomValidation属性をクラスに付加することでこんなに簡単に実装できてしまいます。

このエラーは以下のように表示されます。

エラー2

このエラー表示のためにスキャッフォールドで作成されたViewに手を加える必要はありません。
デフォルトの状態でこういったModelレベルでのエラーの表示に対応しています。

ちなみにControllerのほうはちょっと手を加える必要があります。
スキャッフォールドで生成されるEditメソッドだとtry-catchでエラーを拾うようになっていますが、そこを以下のようにModelStateの状態を判断するようなプログラムに置き換えます。
メソッドの引数でModelを利用する点も注意が必要かな。

——————————————————————————————————————-

[HttpPost]
public ActionResult Edit(int id, Person editPerson)
{
    if(ModelState.IsValid)
    {
        pService.UpdatePerson(id, editPerson);
        return RedirectToAction("Index");
    }
    else
    {

        return View(editPerson);
    }
}

——————————————————————————————————————-

なお、このサンプルで利用しているCustomValidation属性ですが、これは.NET Framework 4で追加されたものです。
ASP.NET MVC 2は.NET Framework 3.5上でも動作しますし、その場合にDataAnnotationも使えるのですが、CustomValidation属性は使えませんので注意してください。

ASP.NET MVC 2のテンプレートで生成される認証用のModelではこのあたりを考慮しているのかValidationAttributeを拡張したクラスで独自の検証を行っています。
CustomValidation属性が使えない.NET Framework 3.5ではその方法がもっともシンプルだと思います。

カテゴリー:.NET, ASP.NET 備忘録