単体入力エラーチェックの実装パターン

さて Part 1. のエントリでは、業務処理の終了パターンの分類と、各アプリケーションタイプにおける基本的な実装パターンを整理しました。要点をまとめると、以下のようになります。 業務処理の終了パターンは、以下のように分類される。 突き合わせエラーについては、バックエンドのモジュール(BC や DAC)との連携によるチェック作業が必要になる。UI 部単体でチェックが可能なのは、単体入力エラーに限られる。 .NET Framework では、UI 開発技術として、ASP.NET, Silverlight, WPF, Windows フォームなど、様々なテクノロジが提供されています。これらの技術には、いずれにも、UI 部において、単体入力エラーチェックを効率よく実装していくための機能が備わっています。(これらの機能は、いずれも単体入力チェックを効率よく実装するための機能であり、突き合わせエラーのチェックや、システムエラーに関する対処を実装するための機能ではありません。いや無理矢理使えば使えるかもしれませんが;、それはこれらの機能が用意された目的や意図とはズレた使い方だと考えるべきだと思います。) ① ASP.NET Web フォーム : 入力検証コントロール ② Silverlight 3, WPF 3 : 例外ベースの双方向データバインド ③ Windows フォーム 2.0, WPF 3.5 : IDataErrorInfo ベースの双方向データバインド さてこれらの機能は、いずれも「単体入力チェックを行う」「フィールド単位のチェックとインスタンス単位のチェックを行う」という点においては違いがありません。しかし、その実装方法や、エラーチェックに対する考え方は、全くといっていいほど違います。この実装方法の特性の違いを理解しておかないと、単体入力エラーチェックをうまく実装できないばかりか、開発生産性をかえって大幅に損なう結果に繋がりかねません。特に、ASP.NET Web アプリケーション開発の入力検証コントロールの使い方に慣れた人が、Windows フォームや WPF などのテクノロジを遣うと、おそらく入力検証のやり方が全くといっていいほど違うため、相当に戸惑うことになるはずです。(というよりも私はむちゃくちゃ戸惑いましたよ....orz) 本エントリの目的は、これらの各テクノロジにおける、実装パターンの違い(実装方法やエラーチェックに対する考え方の違い)を明確化することです。 ① ASP.NET Web フォーム : 入力検証コントロール 検証コントロールを使って、「正しい文字列」を作成する方式 ②…

6

エラーチェックの体系的な分類方法

まず最初のエントリでは、「エラーチェック」とひとくくりにされている「エラー」を、体系的に分類することを試みてみます。このエントリでは、Web / Windows、あるいは Java / .NET などといった技術論とは無関係な部分についての解説を進めていきたいと思います。 エラーチェック(ユーザ入力検証)の意味 正常終了/業務エラー/システムエラーの分類 業務エラーの細分化 アーキテクチャから見たエラーチェックの実装場所 ※ なお、本エントリで解説されている分類方法や命名方法は、あくまで nakama 個人の考え方・整理方法です。もしかしたらもっとよい設計パターンなどがあるかもしれませんので、その辺についてはあしからずご了承ください;。 [エラーチェック(ユーザ入力検証)の意味] まずは、そもそもどのようなケースでエラーチェックが必要になるのか、ユーザ入力検証にどのような目的があるのかを考えてみましょう。 一般的に、業務アプリケーションは、参照系アプリケーションと更新系アプリケーションに大別されます。 参照系と更新系では、求められるアプリケーションの機能が大きく異なりますが、更新系アプリケーションでは、適切な入力エラーチェックをどのように実装するのかが、極めて重要なポイントになります。そもそもなぜ更新系アプリケーションでは、適切な入力エラーチェックが重要になるのか? ユーザ入力検証(エラーチェック)には、大別して以下の 2 つの目的があります。 アプリケーションの保護 ユーザから入力された値をそのまま利用すると、エラーやセキュリティ脆弱性の原因になってしまうため、適切にフォーマットチェックなどを行う必要があります。(SQL 挿入、Cross-Site Scripting など) ユーザビリティの向上 エンドユーザに親切なエラーメッセージを表示するように作成すると、使いやすいアプリケーションを実現することができます。 しかし、このようなユーザ入力検証機能(エラーチェック機能)を場当たり的に実装すると、開発生産性を大きく損なうことになります。このため、通常のアプリケーション開発では、ランタイムが持っている「ユーザ入力検証のための機能」をうまく活用して実装していくことが重要になるわけです。 こうしたランタイムのユーザ入力検証機能を利用する上で欠かせないのが、以下の 3 つのポイントに関する知識です。 アプリケーションの終了パターンの分類 正常終了/業務エラー/システムエラーを正しく分類できること。 業務エラーが、さらに単体入力エラーと突合せエラーに分類されることを知っていること。 アーキテクチャ的な観点から見た、エラーチェックの実装方法 論理 3 階層型アプリケーションにおいて、どこで何をチェックすべきかを判断できること。 ランタイムが持つバリデーション機能(エラーチェック機能)の狙い ランタイムが持つバリデーション機能のコンセプトの違いを理解していること。 どの部分をカバーする目的で作られているのか、どこまでできるのか、その限界点を理解していること。 本エントリでは、まずこのうち最初の、「エラーパターンの分類」の部分について解説します。 [正常終了/業務エラー/システムエラーの分類] 業務アプリケーションの「入力エラー」を考える上で欠かせないのが、ひとくくりに「エラー」とされているものを体系的に分類することです。これを考えるには、業務処理が終了するパターンを、以下の 3 つに分類するのが最初のスタートポイントになります。(※ この終了パターン分類は、nakama による勝手な分類で、業界標準でもなんでもありません;。あしからずご了承ください、とつぶやいてみる^^) 正常終了 : 特に問題なく、期待通りに業務処理が終了できた 業務エラー :…

0

エラーチェックの体系的な分類と実装パターン

というわけで久しくエントリをアップしていなかったこの blog ですが、最近、複数方面からお叱りの言葉が……; 忙しかったこともあってエントリをサボっていたこともあったのですが、ちょうどいいネタがなかったのも実際のところ。がしかし、先日 2009/9/26(土) に行った、わんくま同盟さんでの勉強会のネタが blog 化するにはちょうどいいだろう、という感じなので、その資料を使いつつ、blog エントリを書いてみることにします。 今回の解説ネタは、更新系業務アプリケーションで求められることになる、エラーチェックの実装パターンを体系的に分類してみる、というものです。ASP.NET や Windows フォームなどには様々なデータ入力検証のフレームワークがあるのですが、名称こそ同じ「データ入力検証」となっていても、データ入力検証に対する考え方は、フレームワークごとにかなり異なっています。そこで、本エントリでは、特に .NET Framework 標準のデータ入力検証機能である、以下の 3 つを横並びにして解説してみて、各データ入力検証にどのような食い違いがあるのかを解説してみたいと思います。 ASP.NET 検証コントロール Silverlight 3, WPF 3 の例外ベースの双方向データバインド Windows フォーム 2.0, WPF 3.5 の IDataErrorInfo ベースの双方向データバインド なお、今回のサンプルコードは以下になります。エントリ中では、キーポイントとなるコード部分についてしか触れませんので、詳細なコードについてはこちらのサンプルコードをご覧ください。 [Agenda] Part 1. エラーチェックの体系的な分類方法 エラーチェック(ユーザ入力検証)の意味 正常終了/業務エラー/システムエラーの分類 業務エラーの分類  アーキテクチャから見たエラーチェックの実装場所 Part 2. 単体入力エラーチェックの実装パターン ① ASP.NET Web フォームの場合 ② Silverlight 3, WPF 3 の場合…

0

Part 4. Visual Studio によるマルチスレッドアプリの開発

さて、Part 1~3 の解説で、Windows フォームにおけるマルチスレッドアプリケーションをスクラッチで開発する方法について述べてきました。結論としては、実は Windows フォームにおけるマルチスレッドアプリケーション開発は恐ろしく厄介で面倒である、ということになると思うのですが;、とはいえ 長時間を要する処理があるため、どうしてもマルチスレッドアプリにしなければならない。 ということも当然あると思います。幸い、.NET Framework 2.0/Visual Studio 2005 以降では、BackgroundWorker コンポーネントをはじめとして、マルチスレッドアプリを比較的簡単に書けるようにするための各種のコンポーネントやツールセットがいくつか追加されました。最後にこれらについて解説して、4 回にわたるエントリを締めくくっていきたいと思います。 今回のエントリで解説する内容は以下の 3 つです。 XML Web サービス呼び出しの非同期処理化 WCF サービス呼び出しの非同期処理化 BackgroundWorker コンポーネントによる一般的なタスクの非同期処理化 なお、本エントリでは基本的な XML Web サービスの作り方・使い方に関する解説は行いません。*.asmx による XML Web サービス開発をご存じない方は、一般的な書籍や Web の情報などを参照してみてください。また、今回のサンプルコードはこちらになります。 では、順番に解説していきましょう。 [XML Web サービス呼び出しの非同期処理化] ASP.NET 2.0 XML Web サービス(*.asmx)に対する Web サービス参照(.NET Framework 2.0 ベースのプロキシクラス)には、非常に簡単に XML Web サービス呼び出しを非同期処理化できる機能が備わっています。ここではこの機能を使って、長時間を要する XML Web サービス呼び出しを行う…

3

Part 3. タスクスレッドと UI の協調動作

さて、前回の Part 2. のエントリでは、タスクスレッド(UI の背後で動作させる処理を動作させるスレッド、すなわちマニュアルスレッドやプールスレッドの総称)の様々な起動方法について解説しました。主な方法として、以下の 4 つの方法がありました。 マニュアルスレッドの新規作成 プールスレッドの利用 非同期デリゲートの利用 タイマの利用 さて、いずれの方法を利用する場合であっても守る必要のあるルールとして、UI スレッド以外から UI コントロールの読み書きをしてはならない、というものがありました。 ここまで実際にプログラミングをしてみた方は感じられていると思うのですが、実はこの制限はかなり厄介です。例えば、以下のような処理を簡単に書くことはできません。 背後で行っているタスク処理の進捗状況や完了結果を、UI 上に表示する。 (これはすでに解説済み。.BeginInvoke() 処理が必要。) 背後で行っているタスク処理から、UI 上のコントロールのプロパティを読み出す。 (タスクスレッドから、textBox1.Text プロパティを読み出すことは NG だがどうすればよい?) 背後で行っているタスク処理を、UI 上のキャンセルボタン押下により中断させる。 (どうやって UI のイベントハンドラから背後のスレッドに通知を行えばよいのか?) 背後で行っているタスクスレッド上で発生した例外の情報を、UI 上に表示する。 (どうやってタスクスレッドで発生した未処理例外を UI に通知すればよいのか?) マルチスレッド処理を行う Windows フォームアプリケーションを書く上では、上記のような問題が発生したときの対処方法を知っておく必要があります。本エントリでは、これらについて解説します。 タスクスレッドからの UI 画面の更新方法 タスクスレッドからの UI 画面上のデータの読み取り方法 UI 画面からのタスクスレッドの制御方法 タスクスレッド上で発生した未処理例外の取り扱い方法 本エントリのサンプルコードはこちらになります。 では、以下に順に解説していきます。 [タスクスレッドからの UI 画面の更新方法] さて、まずはおさらいです。タスクスレッド(マニュアルスレッドやプールスレッド)から UI…

5

タスクスレッドの起動方法

さて、前回のエントリでは、Windows フォーム内部におけるスレッドの構成や、メッセージループの働きなどについて解説しました。中でも重要なこととして、以下のようなキーポイントがありました。 UI スレッド上で、長時間処理を動かしてはならない。 長時間処理は、マニュアルスレッドやプールスレッドなどの、他のスレッドに切り出す。 UI スレッド以外から、UI コントロールを触ってはいけない。 マニュアルスレッドやプールスレッド上から、UI コントロールを読み書き・操作してはいけない。 上記の 2 つの重要ルールについて、Part 2~4 にてより実践的な解説を行っていきます。 Part 2. タスクスレッドの起動方法 まず、マニュアルスレッドやスレッドプールの起動方法について解説します。 Part 3. タスクスレッドと UI の協調動作 マニュアルスレッドやプールスレッドから UI コントロールを操作したり読み書きしたりすることはできないため、その回避方法について解説します。 Part 4. Visual Studio を使ったマルチスレッドアプリケーション開発 上記 Part 2, 3 の作業を簡素化するために用意されている、Visual Studio の機能について解説します。 まず本エントリでは、UI スレッドから切り離した処理を動かすために利用するマニュアルスレッドやプールスレッドのことを、タスクスレッドと呼ぶことにし、その作成方法について解説します。 デリゲートとは何か マニュアルスレッドの新規作成  スレッドプールへのワークアイテムの追加 非同期デリゲートの利用 タイマの利用 なお、以降の説明では様々なスレッドの起動方法を解説していきますが、突き詰めると、タスクを動かすスレッドには、マニュアルスレッドかプールスレッドかのどちらかを使っています。ただ、その起動方法が様々な種類がある、というだけの話ですので、見かけの多様性に惑わされず、しっかり学習していただければと思います。(今回はサンプルらしいサンプルはないですが、一応くっつけておきます。) では、順番に解説していきます。 [デリゲートとは何か] マニュアルスレッドやプールスレッドの起動処理を記述する上で欠かせない技術のひとつが、デリゲートです。デリゲートとは、オブジェクトに対して、「関数や処理ロジック」を引数として渡す際に利用される技術であり、.NET Framework の基盤技術の一つになっています。 そもそも「関数」や「処理」を引き渡すイメージがわかない、という方も多いと思いますので、まずここで簡単に解説します。以降の解説は、スレッディングの話からはちょっとそれますが、非常に重要なので必ず理解してください。(※ すでにデリゲートをご存じの方は、この項目は飛ばして先へ進んでください) まず、なぜ「関数」を引数として引き渡す必要があるのかを理解するために、「コレクションから、ある条件を満たすものだけを抽出する処理」を考えてみることにします。例えば、List<int>型(動的配列)に含まれる整数値から、3で割り切れるものだけを取り出す処理を行う場合、おそらく多くの方は以下のようなコードを記述すると思います。…

5

Part 1. Windows フォームのマルチスレッド処理の基礎

さて、Windows フォームは、Windows OS が持つ様々なウィンドウ制御の仕組みに基づいて開発されている UI 技術です。このため、Windows フォームのマルチスレッド処理を理解するためには、まず Windows OS がどのようにして Windows フォームアプリケーションを動作させているのかについて理解する必要があります。その中でも特に重要なのが、メッセージキューとメッセージループです。これらを理解することで、なぜ UI が固まるのか、また固まることを防ぐにはどうしたらよいのか、といったことが理解できるようになります。これについて解説します。 メッセージキューとメッセージループ UI フリーズの発生理由 Windows フォーム上でのマルチスレッド処理の基本ルール BeginInvoke() 命令 最も簡単なマルチスレッドアプリケーションの例 Windows フォームにおけるスレッドの種類 なお、今回のサンプルは以下の通りです。ご活用ください。 [メッセージキューとメッセージループ] Windows フォームは、メッセージループと呼ばれる仕組みを使うことにより、イベント駆動型のプログラミングモデルを実現しています。まず、概略図を以下に示します。 エンドユーザがマウスやキーボードによって Windows フォームのアプリケーションを操作した際に Button_Click などのイベントが発生するのは、以下のようなメカニズムによります。 マウスやキーボードからの入力は、まず Windows OS が受け取る。 Windows OS は、その操作内容(キーが押された、マウスが動いた、マウスのボタンがクリックされた、etc)を、メッセージ構造体(MSG 構造体)に固め、それを各アプリケーション用のメッセージキューに放り込む。 各アプリケーション内部では、メッセージループと呼ばれる処理が走っている。 メッセージループは、自分用のメッセージキューからメッセージ構造体をひとつずつ取り出し、そのデータを解析し、イベントハンドラ呼び出し(Button_Click 呼び出しなど)を行う。 ※ なお、ここでいうメッセージキューとは、MSMQ (Microsoft Message Queue)のことではありません。Windows OS が持っている、GUI 処理のための特殊なキューです。 C# で Windows…

2

マルチスレッド Windows フォームアプリケーションの開発

というわけでまたしてもかなり日にちが空いてしまいました;。年度末ということもあって仕事が立て込んでいたのですが、ほぼ一段落したので久しぶりにエントリを。どうしてもまとまった話題を書こうとすると時間がかかっちゃいますね.... 今回の話題は、Windows フォームにおけるマルチスレッド処理の正しい書き方です。以前、マルチスレッドアプリケーションにおけるデータ変数の排他制御(スレッドセーフか否かの判定)についてこちらとこちらのエントリに書きましたが、さらにもう少し応用的なトピックとして、Windows フォームにおけるマルチスレッド処理について解説したいと思います。 この辺の話は、C++ でアプリケーションを作られている方には当たり前の話(らしい)のですが、私のような pure .NET デベロッパーな人にはあまり馴染みのない話だと思います。しかし、C# や VB でしか Windows フォームのアプリケーションを書いたことがない人であっても、うまくコードを書かないと、下図のような「フリーズしてしまう」アプリケーションができあがってしまいます。 今回のエントリでは、以下について解説します。 そもそもなぜ UI のフリーズ現象は発生するのか? それはどうすれば回避できるのか? Windows フォームにおける UI スレッドの位置づけ Windows フォーム上で、背後にスレッドを起こすための適切な方法 では、以降のエントリでこれらについて解説していきます。 [Part 1. Windows フォームのマルチスレッド処理の基礎] メッセージキューとメッセージループ UI フリーズの発生理由 Windows フォーム上でのマルチスレッド処理の基本ルール BeginInvoke() 命令 最も簡単なマルチスレッドアプリケーション Windows フォームにおけるスレッドの種類 [Part 2. タスクスレッドの起動方法] マニュアルスレッドの新規作成 スレッドプールへのワークアイテムの追加 非同期デリゲートの利用 タイマの利用 [Part 3. タスクスレッドと UI の協調動作] タスクスレッドからの UI 画面の更新方法…

0

Part 2. スマートクライアントにおける単体入力データ検証

さて、前回のエントリでは Windows フォームにおける双方向データバインドの基本的な使い方を解説しました。要点をまとめると、以下の通りとなります。 双方向データバインドを用いると、データソースから UI コントロールへ値を表示するだけでなく、UI コントロールからの入力をデータソースに反映できる。 データバインドには、2 種類のデータバインドがある。 ① 単一値データバインド(単票形式データバインド) ② コレクションデータバインド(グリッド形式データバインド) どちらの場合も、BindingSource コントロールを介して、UI コントロールとデータソースを紐づける。 さて前回のエントリでは、 双方向データバインドにより、テキストボックスから入力された値がデータソースオブジェクトに反映されることを確認しました。しかし、これらのデータはそのまま使えるとは限りません。例えば配達希望日を入力するテキストボックスの場合、 “ABCDE” や “2008/14/63” といった、そもそも日付ではない(型変換できない)データが入力された場合はどうすればよいか? “1973/06/07” のように、日付としては有効でも、未来の日付ではないデータが入力された場合はどうすればよいか? といった問題があるため、入力されたデータ値は検証を行った上で利用する必要があります。しかし、こうしたデータ入力検証を場当たり的に実装すると、コード量が膨大に膨れ上がり、アプリケーションの保守性も極端に悪化します。これを避けるためには、データ入力検証に関して、アプリケーション全体で一貫した考え方を使う必要があります。 本エントリでは、スマートクライアント(Windows フォーム)における、業務アプリケーションを想定した入力データ検証の考え方と、その実装方法について解説します。 エラーの分類 単体入力エラーの分類 単体入力チェックとエラーメッセージの関係 双方向データバインドにおける値の同期の考え方 IDataErrorInfo インタフェースとは何か 具体的な単体入力チェックの実装方法 DTO と UI バインドオブジェクトの違い なお、今回の実装サンプルコードはこちらになります。 では、以下に解説していきましょう。 [エラーの分類] Web アプリ、Windows アプリすべてに共通する考え方ですが、業務アプリケーションにおける「エラー」は、以下の 3 種類に分類されます。 単体入力エラー : UI 内部のみで単体で正誤判定できるもの。 例) 入力された電子メールアドレスが「nakama@ms」だった、入力された価格が 0 未満だった、生年月日として未来の日付を入力された、日付入力欄に “AAA”…

5

Part 1. 双方向データバインドの基本的な使い方

Windows フォームにおけるデータ入力において、スマートに単体入力エラーチェックを行いたい場合には、双方向データバインドと IDataErrorInfo インタフェースを利用する方式が便利です。ただし、この Windows フォームのデータバインドは Web フォームのデータバインドとは大きく異なる点があります。 双方向データバインドが利用できる。(※ Web フォームでも使えますが、極めて限定的です。) 入力データのデータソースへの反映がリアルタイムに行われる。(リアルタイムにデータが同期。) このため、ASP.NET Web アプリケーションでのデータバインドにすでに慣れ親しんでいる方でも、Windows フォームのデータバインドについては、全く新しい技術として学習しなおす、ぐらいの感覚で取り組むことが重要です。今回のエントリでは、まず基本的な Windows フォームのデータバインドの実装方法を解説したいと思います。具体的な解説トピックは以下の通りです。 双方向データバインドとは何か 2 種類のデータバインド データバインドの基本的な使い方 : データソースとなりうるオブジェクト データバインドの基本的な使い方 : 単票形式データバインド データバインドの基本的な使い方 : グリッド形式データバインド null 値の入力制御方法(パース処理のカスタマイズ方法) なお、今回のサンプルを最後まで実装したサンプルコードはこちらになります。併せてご利用ください。 では、以下に解説していきます。 [双方向データバインドとは何か] 双方向データバインドとは、UI コントロール(DataGrid や TextBox, Label コントロールなど)の特定のプロパティと、データソースとなるオブジェクト(型付きデータセットやカスタムオブジェクト)とを紐づけておき、 データソースから自動的にデータを抽出して UI コントロールに表示する。 UI コントロールから入力された値を、自動的にデータソースに反映する。 という動作をさせるものになります。   ASP.NET Web フォームなどのデータバインドでは、ほとんどの場合、データソース内のデータを UI コントロールに表示するという目的のみで利用されます。このため、更新系アプリケーションにおけるデータ入力シートを作成する目的でデータバインドを使うことはまずありません、しかし、Windows フォームや WPF…

1