111008 silverlight square_datavalidation
TRANSCRIPT
入力データ検証を使いこなそう
Silverlightを囲む会in東京#4
田中 孝佳(@tanaka_733)
はじめに
サンプルアプリの公開
説明に使うサンプルアプリを公開しています
– http://techblog.hilife-jp.info/2011/10/silverlightin4.html
– PC持参の方はぜひどうぞ
– IS12T, Win8MetroUIではだめですm(_ _)m
ソースコードはこちらで公開しています
– https://skydrive.live.com/?cid=B43F4832F5BAFBB9&id=B43F4832F5BAFBB9%211121#
で、公開してるブログの紹介
銀の光と藍い空
– http://techblog.hilife-jp.info/
Silverlight(Web), WP7, Azure, Kinect ネタが中心です
最近はSilverlight 5 シリーズやってます
– http://techblog.hilife-jp.info/search/label/Silverlight5
自己紹介 (@tanaka_733)
ERPパッケージベンダーの研究部門 – クラウドを使っていい感じにする研究
Silverlightは業務アプリ開発で使ってます – サーバーサイドはJava – 前回発表したものです
https://skydrive.live.com/view.aspx?cid=B43F4832F5BAFBB9&resid=B43F4832F5BAFBB9%211128
今回から 囲む会in東京 の運営にも 参加しています
WP7, Kinect, クラウド関連の勉強会 にも出現します
なぜクライアントサイドの 入力データ検証が必要なのか
サーバーサイド検証との違い
サーバーサイドの検証は信頼性のため そして業務用要件を満たすため
– SQLインジェクションなどを防ぎたい
–業務的にありえない値を入力させたくない
クライアントサイド検証はUX向上
–サーバーサイド検証だけだと応答性が悪い
–どんな値を入力すればいいか伝えてあげる
単にNGを出せばいいわけではない
サーバーサイド検証
Server
検証
Client
検証
API呼び出し
クライアントサイドに求められる事
あらかじめ入力形式を教えてあげる
–入力データ検証を助けるため
入力形式が誤っていた時、 どう修正すればいいか伝える
–よくない例
入力データ検証を実装するには
WebフォームだとJSが基本
HTMLは静的なので単体では検証できない
–サーバーサイドで毎回検証するのは 通信コスト・サーバーの処理コストがかかる
そこでJavaScriptの出番
–でもサーバーサイドでの検証も必要ですよ
JavaScriptが無効だったり、 フォームを通さず通信されたりします
公開APIを用意すると、 もはやサーバーサイド検証のみ
Silverlightでの検証
入力検証の仕組みが用意されています
– ASP.NET の検証コントロール的なもの
WCF RIA Servicesなど使えば、 サーバーサイドとコードを共有する ことも可能
–ただし今回はやりません
–どちらもC#/VB であることの強みですね
Silverlightにおける 入力データ検証の実装
用意されているもの
UI部品
– DataForm (ちょっと特殊なので今回はなし)
– Label
– DescriptionViewer
– ValidationSummary
– TextBox, ComboBoxなど入力系UI
検証ロジック
–いくつかのやり方が存在
UI部品を使ったサンプルアプリ
このアプリを例にとって説明していきます
その前に前提条件
MVVMでの実装です – 今回の実装にはPrismを使っていますが、
MVVMサポートライブラリに依存しない話です
– ViewとViewModelの分離と Bindingが重要 検証ロジックはViewModel側に定義します
今回はロジックがないのでModelは出てきません
Silverlight4 です (5 RCでも動作を確認)
Rx使ってます – 非同期検証を簡単に書きたかったから
VM側の実装方法
データ検証の実装方法いろいろ
検証方法の定義
–自前の検証関数で定義
– DataAnnotationsで定義
VMでの実装方法
–検証してNGだったら例外を投げる
– IDataErrorInfoをVMが実装する
– INotifyDataErrorInfoをVMが実装する
データ検証の実装方法
検証方法の定義
–自前の検証関数で定義
– DataAnnotationsで定義
VMでの実装方法
–検証してNGだったら例外を投げる
– IDataErrorInfoをVMが実装する
– INotifyDataErrorInfoをVMが実装する
個人的に おすすめ
おすすめの理由
DataAnnotations
–検証ロジックを宣言的に記述できる
if (str.Length >= 8 && str.Length <= 20) とか書かなくていい
– Label, DataformなどUIとの相性がよい
INotifyDataErrorInfo
–例外を投げる=処理が中断される のが嫌い
– IDataErrorInfoより改善されている
Data Annotationsの使い方
DataAnnotationsの使い方
プロパティにAnnotationを付与
Annotationに従って検証する処理を追加
– Validator.TryValidateProperty やTryValidateObjectで検証できる 今回はINotifyDataErrorInfo を実装したViewModelの基底クラス内 で記述します
DataAnnotations一覧
検証属性 説明
CustomValidationAttribute 検証用にカスタム メソッドを使用します。
DataTypeAttribute 特定の種類のデータ (電子メール アドレス、電話番号など) を指定します。
EnumDataTypeAttribute 値が列挙体に含まれることを保証します。
RangeAttribute 最小値および最大値の制約を指定します。
RegularExpressionAttribute 正規表現を使用して有効な値を指定します。
RequiredAttribute 値が必須であることを指定します。
StringLengthAttribute 最大文字数および最小文字数を指定します。
ValidationAttribute 検証属性の基本クラスとして動作します。
http://msdn.microsoft.com/ja-jp/library/dd901590%28v=vs.95%29.aspx
DataAnnotationsの使い方
プロパティに付加する
setterのコードは後で。
DataAnnotationsの欠点
複雑な検証ロジックは カスタム検証メソッドが必要 –例えば、IPv4アドレスとかCIDRとか
–正規表現でできるかもしれないけど、 複雑な正規表現はわかりづらい
複数プロパティ間の検証がしづらい –開始日は終了日より前とか
–プロコトル一覧の選択がTCPなら ポート番号が入力必須とか
カスタム検証メソッドの定義
検証メソッドは下記の条件を満たすこと
– publicなクラスで定義
– public staticなメソッド
–返り値はValidationResult
成功時はValidationResult.Success
–第一引数は検証対象の値を表すオブジェクト
–第二引数は任意 検証要求についての追加情報を提供する ValidationContext
カスタム検証メソッドの例
IPv4アドレスをチェックする
– IPAddress.TryParse メソッドを使用
– ValicationContextは使っていないので省略可
INotifyDataErrorInfo の使い方
IDataErrorInfoとINotifyDataErrorInfoの違い
MSDNにはこう書いてます
–一般に、Silverlight の新しいエンティティ クラスでは、IDataErrorInfo を実装するのではなく、INotifyDataErrorInfo を実装して、柔軟性を高める必要があります。
IDataErrorInfoの特徴
–オブジェクトにつき1つのエラーメッセージ
–検証のタイミングはBinding時のみ
INotifyDataErrorInfo メンバ
HasErrors プロパティ – オブジェクトの検証エラーが発生しているかどうかを示します
GetErrors メソッド – 指定されたプロパティまたはオブジェクト全体の検証エラーを含む IEnumerableを返します
– IEnumerableの要素はToStringメソッドでエラーメッセージを返す
ErrorsChanged イベント – IEnumerable が変更されるたびに、ユーザー インターフェイス (UI) スレッド上で発生させる
INotifyDataErrorInfoの実装例
ViewModelに実装させたいことが多い
そこで、ViewModelの基底クラスとして INotifyPropertyChangedと一緒に実装
使用するMVVMインフラに合わせて 実装しておくと便利
– Prismの場合、 INotifyPropertyChanged を実装したNotificationObjectを継承し、 検証結果を格納するErrorsContainerを使います
INotifyDataErrorInfoの実装例
ViewModelBaseクラス
ValidateProperty, ValidateObject メソッドを呼ぶと検証する
検証するとその結果をErrorsContainerに格納
検証結果に変更があると、ErrorsChanged イベントハンドラを呼び出す
この実装の注意点
初期化時の値のままだと、 検証は起きません
–最初から検証すると、 入力画面がいきなり真っ赤でやな感じ
なにも入力せずに送信する事があるので、 TryValidateObjectを必ず行う
プロパティの実装
コードスニペットにしておくのがお手軽 <Code Language="csharp"> <![CDATA[#region $property$ private $type$ $var$; public $type$ $property$ { get { return $var$; } set { if ($var$ == value) { return; } $var$ = value; RaisePropertyChanged("$property$"); ValidateProperty("$property$", value); } } #endregion $end$]]> </Code>
複数プロパティの関連の検証
複数プロパティの関連を検証
DataAnnotationでは単一プロパティしか 検証できない
方法は2つ(もしくはそれ以上)
– ValidationContext経由で検証に必要な ほかのプロパティを渡す
– ValidatePropertyメソッドなどを継承して、 そのオブジェクト特有の検証処理を追加する
ValidationContextを使う方法
ValidationContext.Items に必要な値をキーを指定して渡す
検証メソッドでは必要な値を取り出す
UIコンポーネントの使い方
使えるUIコンポーネント
入力系UI – 検証時にポップアップ
Label – 必須入力時にVisualStateが代わる
– Display要素でLabelのContentを指定できる
DescriptionViewer – メッセージを表示
ValidationSummary – メッセージを一覧表示
入力系UIでの設定
ValidationSummary使用時には Bindingオプションを指定します
Windows Phone 7 では
入力UIの検証属性は存在する
検証系のUIは非サポートとの記述
実際に検証属性を使っても何も起きなかった
要はUI側のデータ検証は使えない –画面が小さいので そんな面倒な入力はさせるなってこと!?
ロジック内でのデータ検証には使えそう
+α 非同期の検証が必要なとき
検証はクライアントサイドのみで完結が原則
– この場合の検証は同期処理でOK
しかし、例えば・・・
– SNSの入会フォームで ユーザーIDの存在チェックは それだけ先にチェックしたい!
– 検証している間に他の項目を入力できる
この場合非同期の検証が必要
– Silverlightだと通信がからむので必須
+α 非同期の検証の実装
INotifyPropertChangedを実装している場合、 非同期処理の最後でGetErrorsの結果を変更してErrorsChangedを呼べばよい
今回のViewModelBaseの場合は、 ErrorsContainerに追加しさえすればOK
+α 非同期の検証の実装サンプル
おなじみ(?)のRx使ってます
実際は、3秒待ってではなく、 通信してWebResponseなりを見て検証する
LTで面白い話があるそうなのでそれも期待
ご清聴 ありがとうございました