C#と.NETフレームワークで電話番号を検証する方法
読む所要時間: 22 分
ユーザー入力の検証は、ソフトウェアアプリケーションのセキュリティの保全と運用にとって重要な役割を果たします。特に、電話番号などのデータでは、ユーザー入力の検証の重要性が高まります。電話番号は、メッセージ送信などのアプリケーション機能と、2要素認証などのセキュリティ機能の両方を提供するために使用されるプライベートなデータであるためです。
.NET Frameworkや.NET Coreなどのアプリケーション開発フレームワークにはデータ検証機能があるため、標準のデータ型は確実かつ簡単に処理できます。.NETフレームワークで電話番号を検証することも可能ですが、国際化(i18n)など、使用できる機能が制限されています。
幸いなことに、すべてのタイプの電話番号を検証して操作するためのリソースを提供するオープンソースライブラリのlibphonenumber-csharp
があります。libphonenumber-csharp
は、Googleが作成したオープンソースライブラリから派生しています。本稿では、.NETプロジェクトにlibphonenumber-csharp
を実装し、その強力な機能を簡単に活用する方法をご紹介します。
.NETデータ検証
C#と.NETフレームワークで構築されたソフトウェアの一般的な設計パターンでは、クラスオブジェクトを使用してデータを格納します。これは、Model View Controller(MVC)ライブラリを使用するWebアプリケーションでは標準的なアプローチです。.NET フレームワークには、データ検証を検証属性に抽象化する機能があり、エンティティクラスのプロパティの「装飾」に使用されます。
次の例の[Required]
と[StringLength(100)]
は、Movie
クラスのTitle
プロパティの装飾に使用する検証属性です。
検証属性は、他の多くのデータアノテーションのように、System.ComponentModel.DataAnnotations名前空間にあり、.NET Frameworkと.NET Coreの両方で使用できます。日付やメールアドレスなど、多くの一般的なデータ型には標準の検証属性があります。
System.Component.DataAnnotationsでの電話番号の検証
DataAnnotations名前空間は、電話番号をデータ型として検証する列挙型と派生クラスの2つの方法を提供します。電話番号フィールドが単純型の場合は列挙型メソッドを使用し、フィールドがオブジェクト型の場合は派生クラスを使用します。
列挙型の形式
検証の列挙型メソッドを使用する単純型の文字列としての電話番号プロパティの例を次に示します。
DataType.PhoneNumber
列挙型は、クラスがサポートする標準データ型のリストから検証する特定の型のデータをDataTypeAttribute
クラスに提供します。これは列挙型であるため、DataTypeAttribute
クラスの標準機能を取得します。
派生クラスの形式
このアプローチでは、列挙型ではなく、検証属性としてクラスを適用します。Phone
クラスはDataTypeAttribute
クラスから派生し、追加の検証動作を提供できるようにオーバーライドや拡張ができます。
Phone
クラスの機能を変更し、それを使用してオブジェクトプロパティを検証することもできます。
一般的な使用法とベストプラクティス
[Phone]
と[DataType(DataType.PhoneNumber)]
がC#のコードで同じ意味で使用されるのは珍しいことではありませんが、[Phone]
を使用する方がコードが短くて済むため、多くの開発者はこちらを習慣的に使用しています。どちらのアプローチも、ほとんどの場合は同じように機能しますが、派生クラス形式はコードがバックグラウンドで複雑になり、バグが発生する可能性があるため、要件のために派生クラスが必要な場合を除いて、列挙形式を使用することをお勧めします。
制限事項
これらの形式は両方とも、正規表現を使用して検証を実行するように文書化されていますが、ドキュメント自体は、使用する正規表現について言及していません。GitHubのソースコードを詳しく見ると、このクラスがどのように機能するか理解をすることができます。
コード全体を確認すると、電話番号を確実に検証できるのかどうか、潜在的な懸念事項が明らかになります。
- 電話番号は、数字と文字
-.()
に加えて、ext.
、ext
、x
でマークされた内線番号で表すことができます。また、電話番号に英字が含まれる場合もあります。たとえば、米国では1 (800) LOAN-YES
と1 (800) MICROSOFT
の両方を電話番号として発信できます。 - 送信された電話番号の長さのチェックはありません。
- 電話番号が特定の国で有効かどうかを判断するためのチェックはありません。
これを見ると、PhoneAttribute.csは、送信された番号が「電話番号らしい」かどうかを判断すると言った方が正確かもしれませんが、次にご紹介する電話番号の広範な検証を実行するコードがあるため、問題ありません。
libphonenumber-csharpライブラリ
Googleでは、自社のクラウドアプリケーション、事業運営、Android、Chrome、Fuchsiaオペレーティングシステムで電話番号を多用しています。電話番号を効果的に処理することは、これらすべてのソフトウェアシステムのセキュリティと使いやすさにとって重要です。
Googleでは、「これは有効な電話番号ですか?」という質問にAndroidや他のアプリケーション開発者が容易に答えられるように、国際電話番号の解析、フォーマット、検証のためのオープンソースのJava、C++、JavaScriptライブラリであるlibphonenumberを開発し、管理をサポートしています。
このライブラリは素晴らしいですが、サーバー側のデータ検証を実行したいと考えている、ASP.NETまたはASP.NET Coreで作業しているC#開発者にとっては便利ではありません。
幸いなことに、Tom Clegg氏がC#向けのlibphonenumberのポート、libphonenumber-csharpを作成しており、.NET開発者はアプリケーションにlibphonenumberを簡単に実装できます。NuGetパッケージとして使用可能なため、任意のプロジェクトに簡単に追加できます。
必読のドキュメント
libphonenumber-csharpを.NETプロジェクトに接続して試行する前に、ドキュメントを確認することをお勧めします。電話番号に関連する一種の特異性と不確実性を理解するには、次のlibphonenumberのドキュメントをお読みください。
Falsehoods Programmers Believe About Phone Numbers(電話番号についてプログラマーが信じてしまう嘘)
これまで気づかなかった電話番号の複雑さにおそらく驚かれることでしょう。これで、libphonenumber-csharpをプロジェクトに追加する理由が多くあることがわかったと思います。
また、FAQとlibphonenumberのReadmeも確認してください。libphonenumber-csharpリポジトリのドキュメントよりもライブラリの機能について詳しく学ぶことができます。Readmeでは、簡単なコードサンプルで使用法の概要を確認することもできます。
libphonenumber-csharpをASP.NET Core MVCプロジェクトに追加する
libphonenumber-csharpは簡単に試すことができます。サーバー側の検証用に、ASP.NET Core MVCプロジェクトに追加するプロセスを見ていきましょう。JavaScriptバージョンのlibphonenumberを使用したクライアント側の検証の実行も一般的ですが、MVCの高度なモデル状態検証では、サーバー側の検証の結果として適切なフィードバックを提供できることも忘れないでください。
途中で迷った場合や、コードを参照実装と比較したい場合に、GitHubで実行可能なバージョン、BlipPhoneを用意しています。BlipPhoneプロジェクトは、libphonenumber-csharpを含むシンプルなASP.NET Core 2.1 Webアプリケーションです。Visual Studio 2017で実行できます。
デフォルトのプロジェクトを作成する
まず、Webアプリケーション(Model-View-Controller)テンプレートを選択し、ASP.NET Core WebアプリケーションプロジェクトのPhoneCheck
を作成します。デモ用プロジェクトでは、プロジェクトに認証を追加する必要はありませんが、変更を追跡して元に戻すことができるように、ソースコードリポジトリを作成することをお勧めします。アプリケーション内のデータストレージを指定できますが、このチュートリアルでは、データベースを使用してデータを保存することはしません。
libphonenumber-csharpをインストールする
プロジェクトにlibphonenumber-csharpを含めるのは簡単です。まず、NuGet.orgで最新バージョンの情報を確認します。
次に、パッケージマネージャーコンソールウィンドウで次のコマンドを入力し、必要に応じて現在のバージョン情報に置き換えます。
または、PowerShellウィンドウで次の.NETコマンドラインを入力します。現在のディレクトリがプロジェクトディレクトリになっていることを確認します。
ViewModelを作成する
ビューモデルを使用し、HTMLページでユーザーに提示したデータとユーザーから収集したデータを保持します。ビューモデルには、電話番号の発行国と検証する電話番号のフィールドが含まれています。
プロジェクトのModels
フォルダに、PhoneNumberCheckViewModel.csクラスファイルを作成します。
BlipPhoneサンプルプロジェクトには、ドロップダウンフィールドに国のリストを入力し、ビューモデルで2文字のISO国コードを返すコードが含まれています。このサンプルコードを使用するか、CountryCodeSelected
フィールドをプレーンテキストフィールドとして使用し、国コードを手動で入力できます。
PhoneNumberCheckViewModel.csファイルは次のようになります。
これらの入力フィールドを必須にし、それらのラベル要素の値を設定するためにデータ属性を使用することに注意してください。
ビューを作成する
Views
フォルダにPhone
サブフォルダを作成し、CreateテンプレートとPhoneNumberCheckViewModel.csビューモデルを使用して、新しいビューのCheck
を追加します。MVCツールで新しいビューのスキャフォールディングが終了すると、Check.cshtml
ファイルのPhoneNumberRaw
フィールドに生成されたRazorマークアップは次のようになります。
次のサンプルでは、可読性の視点から、一部省略記号(…
)を使用しています。
次のようにビューを編集します。
Razorマークアップの中の、<form>
要素の内側に存在する最初の<div>
要素のasp-validation-attribute
を以下のように変更します。
これにより、エラーメッセージが有効になります。
実行時に、ビューモデルとビューがASP.NET Core MVCで使用され、HTMLコードが提供されます。https://localhost:44383/Phone/Check
ウェブページのPhoneNumberRaw
フィールドのブラウザでのHTMLは次のようになります。
<input>
フィールドは自動的に必須として処理され、データ検証属性が接続されることに注意してください。
コントローラーを作成する
電話番号はコントローラーで検証され、ModelState
オブジェクトとビューモデルのフィールドを使用して、検証とエラー情報をユーザーに提供します。
最初に、デフォルトのツールのPhoneController
を使用し、プロジェクトのControllers
フォルダに新しいコントローラーを作成します。
PhoneNumber
とModels
の名前空間をPhoneController.csファイルに追加します。
電話番号ユーティリティクラスのプライベートメンバ変数を作成し、コントローラーコンストラクタでユーティリティクラスのインスタンスを作成します。
PhoneNumberUtil
の新しいインスタンスは、クラスコンストラクタからインスタンスを作成するためのC#の一般的なclass instance = new class();
構文ではなく、GetInstance()
メソッドを使用して作成されることに注意してください。libphonenumber-csharp
は元のJavaライブラリのポートであるため、GetInstance()
メソッドを使用します。
デフォルトのアクションの名前を変更する
デフォルトで、空のコントローラーのIndex()
メソッドがツールで作成されます。メソッドの名前をCheck
に変更します。
HttpPostアクションメソッドを作成する
コントローラーアクションメソッドは、MVCミドルウェアでHTMLフォームから返されたビューモデルを受け入れ、偽造防止トークンとビューモデルのモデル状態を検証します。これらのチェックに合格すると、前述のようにコンストラクタで作成されたPhoneNumberUtil
インスタンスを使用して、電話番号の検証と操作を実行できます。
デフォルトのアクションの下に、以下のHttpPostアクションのコードを入力します。
表示順に、コードを詳しく見てみましょう。
try…catch
ブロックは電話番号エラーを処理するために重要であるため、スキップしないでください。
サーバー側の検証用にコントローラーで電話番号が送信されたら、まずは電話番号をPhoneNumber
オブジェクトに解析します。電話番号を作成するには、少なくとも2つの必須の引数があることに注意してください。
model.PhoneNumberRaw
: ユーザーが入力したとき解析する生の番号model.CountryCodeSelected
: 番号が割り当てられている国
電話番号オブジェクトを取得したら、PhoneNumberUtil
のインスタンスを使用して、以下のような情報を判別できます。
- 選択した国で有効な番号かどうか。
- 電話番号のタイプ。(複数のタイプの結果が生成される場合があります。)
- 他の国の携帯電話から発信するためのフォーマット。
作成したphoneNumber
オブジェクトとmodel.CountryCodeSelected
を_phoneUtil
オブジェクトのIsValidNumberForRegion
メソッドに渡すことにより、有効な番号かどうかが検証されます。
同じHTMLページに結果を返すため、モデルのプロパティを直接設定してもASP.NET Coreでは機能しません。このため、IsValidNumberForRegion
メソッドの結果を返すには、ModelState
オブジェクトを使用します。
PhoneNumber
オブジェクト自体から次のような情報も取得できます。
- 内線番号が含まれているかどうか。
- 番号に関連付けられている国コード。
以下のコードで、電話番号に内線番号が提供されているかどうかを確認します。
try
ブロックが正常に完了したら、更新されたビューモデルをビューに返します。
PhoneNumberUtil
で、生の電話番号が長すぎるなどのエラーが発生すると、NumberParseException
が発生します。ASP.NET MVCでは、これらをトラップしてModelState
に追加できます。これを使用して、ユーザーにエラーメッセージを表示できます。
個々のフィールドレベルではなく、ModelState
レベルで宣言されたエラーを表示するには、モデルのフィールドレベルのエラーだけでなく、すべてのエラーを表示するようにCheck.cshtml
ビューの検証サマリーを設定する必要があることに注意してください。これが、ビューを作成したときに変更を加えた理由です。
ModelState.IsValid
のテストがfalse
の場合、値を返す前にフォームの値をリセットする必要があるため、if
ブロックの後に次のコードを追加し、HttpPost
アクションメソッドを完了します。
このパターンを使用して、携帯電話やさまざまな国の固定電話から発信する国際電話用の番号のフォーマットなど、電話番号のさまざまなチェックと変換を実行できます。コントローラーのPhoneNumber
オブジェクトまたはPhoneNumberUtil
クラスを使用して追加のチェックを試したい場合は、それらを記述し、ビューモデルとビューにフィールドを出力または追加できます。BlipPhoneサンプルプロジェクトでは、一般に使用される追加フィールドを示しています。
リンクをビューに追加する
便宜上、以下のようなRazor構文で、トップページやトップナビゲーションバーに/Phone/Check
ページへのリンクを追加することができます。
分かりやすい場所に配置してください。
プロジェクトを試す
これで、プロジェクトを実行できます。行き詰まった場合は、BlipPhoneサンプルプロジェクトを参照してください。作成したプロジェクトまたはBlipPhoneプロジェクトで、次のサンプル番号を使用します。
サンプル電話番号
ライブラリのさまざまな機能を試すことのできる番号を以下に例示します。
発行国 | ISOコード | 電話番号 | 注記 |
米国 | US | 1-800-LOAN-YES | 英数字データ |
スイス | CH | 446681800 | 米国からの国際電話 |
米国 | US | 617-229-1234 x1234 | 内線番号 |
米国 | US | 212-439-12345678901 | 長すぎる(16桁を超えている) |
まとめ
有効な電話番号や、送信したい種類のデータ(SMSなど)を受け入れられる電話番号があるかどうか分からない場合、電話をかけたり、テキストを送信したりすると、危険な可能性があります。電話番号の検証に関するGoogleの専門知識を提供できるNuGetパッケージを利用できるため、C#開発者は安心できます。これにより、テレフォニー対応の.NETアプリケーションで使用されるデータを検証する手間が省けます。その他の対応はTwilioにお任せください。
コンパニオンサンプルプロジェクトをダウンロードし、ご自身の目でお確かめください。コードについて質問がある場合は、プロジェクトのイシューリストで新しい質問を開いてください。
コーディングを楽しみましょう!
.NET CoreアプリケーションでのTwilio APIの完全な統合については、5部構成のビデオシリーズをご覧ください。一度に多くのAPIの概要を確認できます。