jquery validation x asp.net mvc で遭遇した不具合 & 対抗ハック
DESCRIPTION
Community Open Day 2012 北海道会場 セッション2TRANSCRIPT
jQuery Validation x ASP.NET MVC
で遭遇した不具合 & 対抗ハック
Community Open Day 2012
@jsakamoto
Twitter Hashtag
• よろしければ、#clrh71 でお願いいたします。
– #cod2012jp だけだと、全国会場の Tweet と混信しそうなので...
– 本セッション中、MiniTwitter にて #clrh71 を含む Tweet をポップ
アップします。
jQuery Validation についておさらい
• クライアント側スクリプトによる入力検証機能を提供する JavaScript
ライブラリ。
– jQuery のプラグイン
• ASP.NET MVC の、標準のクライアント側入力検証エンジンに採用
– MVC3以降
– Visual Studio にて ASP.NET MVC アプリを新規作成すると標準で使用。
• この資料を作成している時点での最新バージョン:
– jQuery = v.1.7.2
– jQuery Validation = v.1.9
本セッションのテーマ
• jQuery Validation を使っている上で ”些細な” 不具合にいくつか遭遇
• それら不具合について紹介、どう対策して解決したのかを披露
• 対策はすべて、クライアント側 JavaScript コード上で施工
– 本セッションの本質的な部分では、C# とか ASP.NET とか出てきません。
– プラットフォーム問わず、Web アプリ共通の話題ではないでしょうか?
– っていうか、むしろ、Ruby on Rails などなど、他のプラットフォームでは
問題になってないのか? 気になります。
デモ アプリ
• こんな ASP.NET MVC4 な
Webアプリを肴に、実演を
交えつつ、進めて参ります。
文字数検証 - input type=“text”
Case 1.
Demo
何が起きてる?
• jQuery Validation は、行頭行末の空白を除いた文字数で
チェック
– ”期待” とは異なったクライアント側検証。
• サーバー側検証では、行頭行末の空白もそのままに文字
数チェックするのでセーフ。
– ”Post Back” な挙動。
– Webではクライアント側検証に頼らないという鉄則。
対応
• jQuery Validation の検証メソッドを改変すればいい
maxlength: function(value, element, param) { return this.optional(element) || this.getLength($.trim(value), element) <= param; }
この trim 要らない!
方法1 - jQuery Validation のソースを直接変更
• MIT License
• でも将来の jQuery Validation 本家のバージョンアップに
ついていける?
方法2 – 開発元にフィードバック
• trim しているのは、それはそれで意味があるのでしょう。
• その上でなお、破壊的変更が受け入れられるのか?
• 仮に受け入れられるとして、リリースされるまで待てる?
– “今そこにある危機”
方法3 – 実行時にOverride
• JavaScript なので、実行時に「書き換え」できます。
$.validator.methods.maxlength = function (value, element, param) { return this.optional(element) || this.getLength(value, element) >= param; };
JavaScript コードの Hack
• いかにも “動的言語” らしく、Hack しやすい。
• しかし Closure が使える...!
– 関数型言語っぽい手法で作成されると手が出せない。
• jQuery Validation はそんな実装されてなく良かった...
これで学びました。
文字数検証 - textarea
Case 2.
Demo
何が起きてる?
• jQuery Validation は、改行は1文字として文字数チェック。
• サーバー側検証では、改行は2文字として文字数チェック。
– POST データ中、改行が CR+LF になってる
– Windows7上で、IE9 でも Firefox12 でも Chrome19 でも同じ挙動
※以上を Fiddler v.2.3.9.3 で確認。MacOSではどうなんでしょう?
• クライアント側とサーバー側とで検証動作が異なる。
– ちなみに、XHR要求だと改行が LF で送信されたり。
対応
• サーバー側で CR+LF を LF に置換することで対応可能。
• でも、漏れなく実装するのは大変では?
• それでは jQuery Validation の実装を変更しましょう。
– オリジナルの $.validator.prototype.getLength(value, element ) が
呼び出される前に、value に含まれる改行文字(LF)を2文字に置換し
てオリジナル実装に渡すよう、カスタムコードを ”差し込む”。
実行時に Override
var org = $.validator.prototype.getLength; $.validator.prototype.getLength = function (value, element) { value = value.replace(/¥n/g, "++"); return org.apply(this, [value, element]); };
元の実装をorgに確保
LFを適当な 2文字に置換
元の実装をapplyで実行
getLength メソッドを 独自実装に差し替え
Cancel ボタン
Case 3.
Demo
何が起きてる?
• “cancel” CSSクラスを持つ input か button がクリックされると「入力検証しない」のフラグが立つ。
• そしてそのフラグは解除されない。
this .find("input,button") .filter(".cancel") .click(function() { validator.cancelSubmit = true; });
正攻法 – input で Cancel ボタンを実装しない
• a 要素で。
• Twitter Bootstrap など昨今の CSS ライブラリを使えば、a も
input も、同じ外観に作れる。
どうしても、という場合...
• 「検証しない」フラグをワンショット遅延でオフに復元。
$(".cancel").click(function () { var validator = $(this).closest("form").validate(); setTimeout(function () { validator.cancelSubmit = false; }, 0); });
IE8
Case 4.
Demo
何が起きてる?
• $.validator.elements メソッドの内部に原因
• IE8 だとなぜか、$($(“form”)[0].elements).filter(“:input”)
の結果が、要素数 = 0個になっている
– IE9 でも、ドキュメントモードが IE8 かそれ以前だと再現
対応 – jQuery Validation を最新に
• この問題を抱えているのは、実は ver.1.8.0.1 まで。
• jQuery Validation を ver.1.8.1 以降に Upgrade で解決。
– ver.1.8.1 のパッケージは 2011年6月10日頃から出現している模様。
– それ以前に作成されたASP.NET MVC3 アプリは注意?
jQuery Validation を最新にできない場合は...
• $.validator.elements の実装を実行時に Override。
• .filter(“:input”) ではなく、.find(“input, select, textarea”)
で要素を絞り込む。
$.validator.prototype.elements = function () { ... return $([]) .add(this.currentForm.elements) .find("input, select, textarea") ...; };
CSS Class 名が検証ルール名にかぶった
Case 5.
Demo
何が起きてる?
• ASP.NET としての入力検証機構とは無関係に、jQuery
Validation による入力検証機構は活きている
• そのひとつ、CSSクラス名による入力検証の発動
– required
– date
– number
– ...
jQuery Validation 標準の検証ルールは潰せる
• $.validator.classRuleSettings からCSSクラス名ルールを削除
delete $.validator.classRuleSettings.email;
徒然に
些細なことにこだわってばかりで、
自分が器の小さい人間に思えてきました...
だって、結局は、サーバー側検証が機能するんだし...
結局、フィードバックは、Microsoft を含め、
どこにもしていません。
他の仕事とか優先してしまい...
どなたか Microsoft Connect とかに投稿いただません?
Web Forms や、MVC2 までの
クライアント側入力検証では、些細とはいえ、
こんな問題はなかったよな... と思ったり。
さすが Microsoft 純正品クォリティ?
今振り返るに、jQuery Validation の採用はどうだったんだろう...
Thank you...