CodeZine(コードジン)

特集ページ一覧

フェッチ機能付きのコントロールの作成

プロパティに基づいて自動でデータソースにバインドするドロップダウンリスト

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加
2005/11/24 12:00

本稿では.NETの「継承」と「サーバーコントロール」という2つの強力な機能を組み合わせて、フェッチ機能付きドロップダウンリストコントロールを作成する方法を紹介します。

背景

 本稿では、Microsoft .NETプラットフォームの持つ2つの強力な要素、「カスタムサーバーコントロール」と「継承」を組み合わせる方法を説明します。ここではASP.NETで提供されている標準的なドロップダウンリストのサーバーコントロールを継承した、カスタムWebサーバーコントロールを開発します。今回作成するカスタムサーバーコントロールは、指定のパラメータに基づいてデータをフェッチし、自分自身に割り当てます。このコントロールを利用すれば、もう実際のデータアクセスコードを書く必要はなくなります。

 .NETのドロップダウンリストコントロールの威力は、DataSetsDataReadersなどのADO.NETオブジェクトにバインドできる点にあります。一度バインドしてしまえば、DataSetDataReaderオブジェクトのデータ要素を物理的にコントロールに配置するコードを書く必要はなくなり、コントロールそのものがHTMLのselect要素となります)。開発者にとって必要なのは、ただデータソースと、データソースの中の使用する列を値として指定し、select要素の属性を表示することだけです。コントロール自体は、ブラウザに送信する上で必要となる実際のHTMLの材料や表現を実装しています。しかし、DataSetDataReaderをデータベースからフェッチする「グルーコード(glue code)」だけは書く必要があります。これはVisual Studio .NET IDEのウィザードでも実行できますが、それでも完了するには時間のかかる作業です。本稿では、リストコントロールにデータを割り当てる際のフェッチコードを書く手間を省くために、既定のドロップダウンリストを利用して、自身のプロパティの値に基づいてDataReaderをフェッチするカスタムサーバーコントロールを作成します。

継承

 「フェッチ機能付きドロップダウンリストコントロールを開発する」という目標を達成するためには、継承を利用します。「継承」とは、「IS-Aリレーションシップ」を表す、オブジェクト指向では一般的な概念です。オブジェクト指向の文献でしばしば使われる一般的な例では、「人」と「従業員」が引き合いに出されます。「"従業員(Employee)"は"人(Person)"の一種である」というリレーションシップは、IS-Aリレーションシップです。ここで、C#のPersonというクラスがあると仮定しましょう。このクラスは、「Name(名前)」および「SSN(Social Security Number:社会保障番号)」という2つの属性を公開しています。さらに、C#のEmployeeというクラスも存在し、「Manager(マネージャ)」と「Salary(給与)」という2つのパブリック属性があるとしましょう。PersonクラスとEmployeeクラスの間に継承を設定(つまり、EmployeeクラスがPersonクラスを継承するよう設定)すると、EmployeeクラスはPersonクラスが持つパブリック属性とパブリックメソッドもすべて持つことになります。この例では、EmployeeというクラスはPersonというクラスから「派生した」とも言うことができ、EmployeeクラスにはNameSSNManagerSalaryという4つのプロパティを持つことになります。また、この例では、Personクラスは「ベースクラス」と呼ばれ、Employeeクラスは「派生クラス」と呼ばれます。さらに別の言い方をすると、Employeeは「サブクラス(下位クラス)」、Personは「スーパークラス(上位クラス)」です。

 派生クラスに新しいプロパティとメソッドを追加して、ベースクラスの機能を拡張することができます。C#のbaseというキーワードを使えば、ベースクラスの要素に派生クラスからアクセスすることもできます。継承は.NETの非常に強力な機能で、その活用方法は無数にあります。本稿では、継承を使って開発の労力を軽減する方法を1つだけ示します。継承にまつわるオブジェクト指向の概念すべてをここで説明することはできませんが、本稿で紹介するサンプルの実装方法を理解し、学習するには十分なはずです。

データアクセスの基盤を作成する

 フェッチ機能付きドロップダウンリストコントロールの開発に取りかかる前に、グルーコードがデータを取得してコントロールに割り当てるしくみを具体的に見ておきましょう。後で、このコードを使って、本稿の派生コントロールに挿入するテンプレートを作成します。まずは、Webフォーム上の単純なドロップダウンリストコントロールにデータを割り当ててみましょう。

 Visual C#のプロジェクトから、新しいASP.NET Webアプリケーションプロジェクトを作成します(図1)。

図1 新しいASP.NET Webアプリケーションプロジェクトを作成
図1 新しいASP.NET Webアプリケーションプロジェクトを作成

 次に、ツールボックスからドロップダウンリストコントロールをドラッグし、プロジェクトウィザードで作成された既定のWebフォーム「WebForm1.aspx」にドロップします。このコントロールの名前をlstDemoに変更しましょう(図2)。

図2 コントロールの名前をlstDemoに変更
図2 コントロールの名前をlstDemoに変更

 ドロップダウンリストコントロールをページに追加したら、次はこのドロップダウンリストにデータを割り当てるためのコードを追加します(図3)。このドロップダウンリストには、ページが自分自身にポストバックされたときではなく、ページが最初に読み込まれたときにデータが割り当てられるようにします。このためには、IsPostBackの値をチェックし、IsPostBackの値がfalseの場合にのみドロップダウンリストを割り当てます。

図3 データをフェッチしてドロップダウンリストに割り当てるコード
図3 データをフェッチしてドロップダウンリストに割り当てるコード

 ドロップダウンリストは、DataSetDataReaderのどちらにもバインドできます。本稿のシナリオでは、パフォーマンスを上げるために後者を選びました。DataSetには豊富な機能が用意されていますが、ここではドロップダウンリストへのデータ割り当てを単純化したかったのと、パフォーマンス的な理由から、サイズが小さくて単純なDataReaderを使用することにしました。また、この例ではOLEDBDataReaderクラスではなく、SqlDataReaderクラスを使っている点にも注意してください。この選択により、SQLデータソースにしかアクセスできなくなりますが、パフォーマンスは最適化されます。Microsoft SQL以外のデータベースに接続する必要がある場合は、OLEDBDataReaderクラスを使っても構いません。ただし、既定のASPXページにはSystem.Data名前空間しか含まれていないため、適切なデータクライアントの名前空間を使用するために、必要なusingディレクティブを必ず追加してください。

 コードの残り部分は単純明快です。この例ではusingステートメントを使ってコネクションとコマンドを作成しています。usingステートメントを使用すると、それで囲んだコードブロックの実行後に、usingステートメントで宣言したオブジェクトのDisposeメソッドが自動的に呼び出されます。コマンドとコネクションを作成して定義した後は、コマンドのExecuteReaderメソッドを使用して、「pubs」データベースの「authors」テーブルから著者ID(au_id)と著者の姓(au_lname)を取得し、DataReaderオブジェクトに割り当てます。データを取得した後は、そのDataReaderオブジェクトをドロップダウンリストのデータソースとして設定し、ドロップダウンリストの表示テキストとオプション値の取得元となる列名を設定して、最後にデータソースをドロップダウンリストにバインドします。図3のコードを入力したら、プロジェクトをコンパイルしてください。コードを実行するとHTMLのselect要素が生成され、au_id列はドロップダウンリストのオプション値、au_lname列はドロップダウンリスト表示テキストとなります。

必要なプロパティの定義

 テンプレートに使える実用的な例が作成できました。これで、本稿の派生コントロールの開発をどう進めるかについて計画を立てることができます。最初のステップは、何を一般化し、パラメータとして収集するか、そして何をコントロールに埋め込むかを決定することです。一見すると、次の項目がパラメータとして渡す候補になりそうです。

  • コネクション文字列
  • データベーステーブル名
  • HTMLのselect要素の個々のオプションサブ要素の「オプション値」になる列と「表示テキスト」になる列

 コネクション文字列は、どのデータベースに接続すべきかを知るために必要です。たいていの場合、これは「Web.Config」ファイルに格納され、おそらくはApplicationレベルの変数のどこかにキャッシュされるため、この値は簡単にキャプチャできます。

 データベーステーブル名は、SELECTステートメントで使います。今回使用するSELECTステートメントは単純なので、データベーステーブル名と、ドロップダウンリストのオプション値および表示テキストとして使用する2つの列の名前だけで、SELECTステートメントを動的に作成することができます。

 ちょうどよいことに、オプション値と表示テキストの列を指定するための機能は継承元のコントロールにプロパティとして用意されているので、それらを親コントロールから「拝借」することができます。

 これで、まだ考慮されていない部分はエラー処理だけになりました。コネクション名やテーブル列名のようなユーザー入力の受け付けを開始するときは、想定されるすべてのエラー、たとえば不正なコネクション文字列やパラメータの不足などをきちんと処理しなければなりません。既定のドロップダウンリストと同じように、エラーを処理せず、呼び出し元にエラーを送り返すだけにしておくこともできますが、この場合、エラーを効果的に処理するには、エンドユーザーがコントロールをtry-catchブロックにラップする必要があります。一方、新しいコントロールを派生させるメリットの1つは、自己完結型のエラー処理といった高度な機能を追加できる点にあります。もっとも、これを実装するかどうかは開発者の判断しだいなので、何も手をつけたくない場合はそのままでも構いません。代わりに.NETに組み込まれた例外フレームワークが処理を引き受けてくれます。

 さて、そろそろ派生コントロールの作成に話を戻しましょう。最初のステップは、C#で新しいWebコントロールライブラリプロジェクトを作成することです。プロジェクトには、「mycoServerControls」と名前を付けてください。工程管理のために、コントロールの名前に自分の会社名をプレフィックスとして付けておくと好都合な場合もしばしばあります。この例では、会社名を表すプレフィックスとして「myco」を使います。

 グルーコードを追加してデータをフェッチし、コントロールに割り当てるには、前もって処理しておくべき細かな事柄がいくつかあります。

  • コントロールの名前空間を、mycoServerControlsからmycoServerControls.DropDownListに変更します(図4)。
  • 図4 コントロールの名前空間を変更
    図4 コントロールの名前空間を変更
  • csファイルの名前を、「WebCustomControl1」から「mycoServerControls.DropDownList」に変更します(図5)。
  • 図5 名前空間に一致するようファイル名を変更
    図5 名前空間に一致するようファイル名を変更
  • クラスの名前をWebCustomControl1からmycoDropDownListに変更し、コントロールの継承をSystem.Web.UI.WebControls.WebControlからSystem.Web.UI.WebControls.DropDownListに変更します(図6)。
  • 図6 クラス名と継承を設定
    図6 クラス名と継承を設定
  • SQLクライアントのクラスと名前空間に、必要な参照を追加します(図7)。
  • 図7 必要な参照を追加
    図7 必要な参照を追加

名前空間の内容

 まずは既定のWebコントロールライブラリプロジェクトに含まれているコードを見ていきますが、その前に、私がなぜファイル名と名前空間を変更するよう勧めたのかを理解していただくために、名前空間についていくつか説明しておきます。これらの変更はあくまでも私の推奨にすぎず、既定の名前空間とファイル名のまま作業を進めても、特に何の影響もなく、完全に機能するサーバーコントロールを開発できます。しかし、変更を加えておけば、いつか企業環境で実装やメンテナンスに携わるような場合にも、作業が簡単になります。

 私はいつも、自作のC#ソースファイルの名前を、そのソースファイルに含まれている名前空間へと変更します。確かに、こうするとファイルには名前空間が1つしか含まれなくなりますが、これは、プロジェクト内の作業を論理的に分割するのには好都合です。1つのプロジェクトに複数の名前空間が含まれている場合、プロジェクトに他のソースファイルを追加するのが非常にたやすくなり、なおかつ、プロジェクト内のソースコードをクリーンかつわかりやすい形に分割することができます。また、多くの場合、短めのソースファイルの扱いが簡単になります。さらに、特定の名前空間があるソースコードの場所を識別するのにも役立ちます。ファイルを1つずつ開いて、その中に含まれている名前空間をいちいち調べる必要がなくなるためです。

 先ほど、コントロールの名前空間をmycoServerControlsからmycoServerControls.DropDownListに変更することも勧めました。これは、名前空間に含まれるソースのスコープを狭くすることだけを目的にしています。いずれ、読者の皆さんが本稿の手法を利用して、自分でテキストボックスコントロール用の派生コントロールを開発することがあるかもしれません(たとえば、数値データ入力を評価するコントロールや、文字列入力を評価するコントロールなど)。また、動的SQLではなくストアドプロシージャを使った、別のドロップダウンリスト派生コントロールを開発するケースも考えられます。その場合、ドロップダウンリスト(DropDownList)コントロールの名前空間を既定のまま変更しなければ、4つのコントロールすべてがmycoServerControlsという1つの名前空間に含まれることになり、前の段落で説明したファイルの命名規則を守れば、4つのコントロールすべてが1つのファイルに含まれることになります。お察しのとおり、この調子で新しいコントロール型を次々に派生させていくと、1つのソースコードファイルを使用する手法では、管理が楽になるどころか、手に負えなくなります。

 しかし、名前空間をより説明的にしておく(つまり、mycoServerControls.DropDownListmycoServerControls.TextBoxという名前空間を作成する)と、コントロール型を1つしか含まないソースコードファイルを個別に作成できるようになります。これにより、.NETでクラスと機能をグループ化するための、はるかにすっきりした論理的なアプローチが生まれます。.NET Frameworkは、必要に応じて開発者の手で拡張できるように設計されています。.NET Frameworkの基本的な名前空間がどうセットアップされているかを調べ、その構造を自作のカスタム名前空間によってモデル化するよう努めていけば、企業全体で利用しても名前空間が衝突することのない、プロフェッショナルなツールキットが出来上がっていきます。重要なのは、名前空間のストラテジを前もって定めておき、断固としてそのストラテジを進めていくことです。.NETを採用する初期段階でこのステップが完了していないと、事態が複雑になり、やがては名前空間を再編成する一大プロジェクトを立ち上げざるを得なくなります。

DefaultPropertyとToolboxDataの情報の設定

 Webコントロールライブラリプロジェクトを選択すると、Visual Studio .NET IDEは自動的に既定のコードをプロジェクトに追加します。まず見てほしいのは、図8のコードブロックです。

図8 WebコントロールライブラリプロジェクトのDefaultProperty/ToolboxDataコード
図8 WebコントロールライブラリプロジェクトのDefaultProperty/ToolboxDataコード

 このコード行では、「コントロールの既定のプロパティ」と、「ツールボックス/タグ情報」の2つを設定しています。既定のプロパティは、コントロールのプロパティと一致している必要があります。ToolboxDataでは、このコントロールがツールボックスに表示されるときの名前と、このコントロールがWebフォームに追加された際にASPXページに挿入されるタグの既定のクラス名(この例ではWebCustomControl1)を指定します。フォーマット文字列内の{0}は、タグプレフィックスによって置き換えられます。WebCustomControl1のインスタンスは、新しいクラス名であるmycoDropDownListによって両方とも置き換えられます。さらに、このコントロールでは「Text」という名前のプロパティは公開しないため、既定のプロパティを「ConnectionString」に変更する必要があります。それぞれの変更については、図9を参照してください。

図9 DefaultProperty/ToolboxDataの部分を変更
図9 DefaultProperty/ToolboxDataの部分を変更

コントロールのプロパティ

図10 コントロールのパブリックプロパティ宣言
図10 コントロールのパブリックプロパティ宣言

 次は、図10のコードを見てください。この部分は、コントロールのパブリックプロパティ宣言です。ここには、目を通すべき属性がいくつかあります。1つ目はBindable(true)です。この属性は設計時に、「このプロパティは有効なソースにデータバインドできるかどうか」をIDEに示すために使われています。次はCategory("Appearance")です。この属性は、このプロパティをプロパティデザイナ内のどのカテゴリに配置するかを制御します。ここでは「Appearance」や「Data」などの既定のカテゴリの1つを使うか、自作のカスタムカテゴリを入力することができます。最後の属性であるDefaultValueには、そのプロパティの既定値を指定します。Textプロパティを削除するか、名称を変更して、次のプロパティをコントロールに追加する必要があります。

  • ConnectionString
  • SourceTable
  • ErrorMsg

 これら3つのプロパティ用のコードを、図11に示します。ErrorMsgプロパティが読み取り専用として実装されている点に注目してください。

図11 修正後のパブリックプロパティ宣言
図11 修正後のパブリックプロパティ宣言

コントロールのメソッド

 IDEによって追加されたコードの最後の部分は、Renderメソッドの実装サンプルです。メソッドの宣言に、overrideキーワードがあることに注目してください。本稿の親クラスにも、Renderという名前のメソッドがあります。このメソッドには、スーパークラスの中でoverridable(オーバーライド可能)というマークが付けられており、これは「派生クラスは同じ名前でメソッドを公開してもよい」ということを意味しています。overrideキーワードの付いたメソッドを派生クラスが実装すると、その機能を派生クラスが担当することになり、親のメソッド実装は、派生クラスから明示的に呼び出されない限り実行されなくなります。要するに、子クラスの動作が親クラスの動作をオーバーライド(上書き)するわけです。今回の例では、コントロールの描画方法を変更しなければならない理由はないので(派生コントロールにデータを割り当てることさえできれば、それで目的は達成されます)、Renderメソッドは完全に削除できます。ここが継承のすばらしいところです。メソッドをオーバーライドして実装する必要のない機能はすべて親が担当してくれるため、一部の特別な機能を追加するだけで済みます。

 今回作成する派生コントロールでは、Populate()というメソッドだけを公開します。このメソッドは、データをデータベースからフェッチし、その結果として生成されるDataReaderをドロップダウンリストコントロール(つまり親コントロール)にバインドします。単に親のDataBindメソッドをオーバーライドするという方法もありますが、そうすると、ユーザーが本稿のコントロールを既定のドロップダウンリストとして使うことはもうできなくなります。DataBindメソッドの既定の動作を変更すると、ユーザーは自分のデータフェッチコードを書いたり、本稿のコントロールを既定のドロップダウンリストとして使ったりすることができなくなります。つまり、本稿のコントロールの使用は制限され、事実上、機能性や柔軟性が低下してしまいます。そこで、DataReaderをフェッチした後に親のDataBindを呼び出し、ドロップダウンリストにデータを割り当てる、という処理を行う新しいPopulate()メソッドを追加することにします。図12に、Populate()メソッドの完全なコードを示します。

図12 Populate()メソッド
図12 Populate()メソッド

 Populateメソッドのコードリストに示したとおり、親コントロールのプロパティとメソッドにアクセスするにはC#のキーワードbaseを使います。SQLのコードはすべて、try-catchブロックでラップすることができます。SQLアクセスコードがエラーをスローした場合は、Populateメソッドがfalseを返し、ErrorMsgプロパティがセットされます。

 コードの残り部分は、先ほど作成してテストしたデータアクセスコードの「テンプレート」とまったく同じです。どれをビルドしても、エラーや警告は表示されません。リリースビルドが完成したら、コントロールを使用する任意のプロジェクトの「bin」フォルダにDLLを配置します(ただし、派生コントロールのDLLがマシンのGCAに配置される場合は除きます)。

コントロールの使用

 では、最初に実装してみた、データフェッチコードを含むWebプロジェクトに戻りましょう。新しいコントロールのDLLを、アプリケーションの「bin」フォルダに配置するのを忘れないでください。「bin」フォルダに配置した後は、コントロールをVisual Studio .NETにリンクする必要があります。まず、コントロールからツールボックスへの参照を設定しましょう。このためには、次の手順を実行します。

  1. ツールボックスを右クリックした後、[Custmize Toolbox ...]をクリックします(図13)。コントロールをツールボックス内の特定の領域(たとえばWebForms、Data、Generalなど)に表示したい場合は、ツールボックスの該当するエリアを確実に右クリックしてください。
  2. 図13 ツールボックスを右クリックして[Customize Toolbox ...]をクリック
    図13 ツールボックスを右クリックして[Customize Toolbox ...]をクリック
  3. [Customize Toolbox]ダイアログボックスで[.NET Framework Components]タブをクリックし、[Browse]ボタンをクリックしてコントロールのDLLの場所を指定します(図14、図15)。
  4. 図14 [.NET Framework Components]タブの[Browse]ボタンをクリック
    図14 [.NET Framework Components]タブの[Browse]ボタンをクリック
    図15 コントロールの実行ファイルを選択
    図15 コントロールの実行ファイルを選択

 コントロールからの参照が確立できると、ツールボックス内の選択した領域にコントロールが表示されます(図16)。

図16 コントロールが表示される
図16 コントロールが表示される

 コントロールがツールボックス内に表示されるようになったので、他のコントロールを追加する場合と同様、このコントロールを任意のWebフォームに追加できるようになります。図17は、Visual Studio .NET IDEのプロパティウィンドウの[Data]セクションに、標準のドロップダウンリストコントロールのプロパティと、派生コントロールに追加した新しいプロパティが表示されている様子です。これらのプロパティは、先ほどのWebアプリケーションで手動でフェッチしたものと同じデータをドロップダウンリストに割り当てるように設定されています。

図17 プロパティウィンドウに新しいプロパティが追加されている
図17 プロパティウィンドウに新しいプロパティが追加されている

 プロパティを設定した後は、ASPXページのPage_Loadイベントに、派生コントロールにデータを割り当てるためのコードを追加する必要があります。Populateメソッドは結果を返すため、その結果をチェックし、エラーが発生したかどうかを示すErrorMsgプロパティの値を表示する必要もあります。今回の例では、ページに追加したラベルコントロールを使ってメッセージを表示することにしました。図18に、派生コントロールにデータを割り当てるために必要な新しいコードを示します(たったの2行です)。

図18 派生コントロールにデータを割り当てるコード
図18 派生コントロールにデータを割り当てるコード

 ページをコンパイルして実行すると、両方のコントロールが同じデータを横並びに表示します(図19)。

図19 既定のコントロール(左)と派生コントロール(右)の実行結果
図19 既定のコントロール(左)と派生コントロール(右)の実行結果

 最後に残ったのは、エラー処理が期待どおりに動作するかどうかを確かめることです。このことをテストするには、DataTextFieldプロパティの値を無効な値に変更し、アプリケーションを再実行します(図20)。コントロールから発されたエラーは、ページのラベルに表示されます(図21)。

図20 コントロールのエラー処理のテスト
図20 コントロールのエラー処理のテスト
図21 ラベルにエラーメッセージが表示される
図21 ラベルにエラーメッセージが表示される

まとめ

 本稿では.NETの「継承」と「サーバーコントロール」という2つの強力な機能を組み合わせて、フェッチ機能付きドロップダウンリストコントロールを作成する方法を見てきました。データ中心のWeb開発が主流になっている今日では、データドリブンのドロップダウンリストは必須要素になっています。本稿では、コードをプロジェクトごとに何度も記述してテスト、メンテナンスするという労力を大幅に削減するにはどうすればよいかを見てきました。コントロールの作成時には、エラーを呼び出し元に送り返すのではなく、それらのエラーをトラップし、処理する方法を吟味しました。さらに、名前空間の重要性や、名前空間をフル活用して企業全体での再利用が可能なコードを開発する方法も調べました。

 本稿のサンプルはごく簡単なものであり、機能を強化したり、より堅牢なエラートラップを実現したり、オプション値と表示テキストの列をユーザーが入力できるようにしたり、組み込みSQLの代わり(あるいは補助)としてストアドプロシージャをサポートするようにプロパティやメソッドを追加したりするなど、改良の余地はまだまだあります。本稿は「サーバーコントロールを拡張したり、新たに作成することによって何ができるか」という問題の表面をなぞっただけでしかありませんが、ここで作成したコンポーネントは、現実の開発ニーズを満たす、再利用可能なコンポーネントです。継承のおかげで、レンダリングや表示の状態などについては特に気にかける必要もなく、これらの細かな処理は親に任せるだけで済みました。しかし、こういった領域でこそ、サーバーコントロールは大きな力を発揮することができます。サーバーコントロールは、従来よりもはるかに機能豊富なWebアプリケーション用ユーザーインターフェイスを実装するための強力なパラダイムとなります。本稿を通じて、サーバーコントロールという領域にさらに興味を抱いてもらえれば幸いです。



  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

あなたにオススメ

著者プロフィール

  • Luther Stanton(Luther Stanton)

    Intellinet Corporation(本社:ジョージア州アトランタ)のプリンシパルコンサルタント。Intellinet社は、米国南東部では唯一、5種類のMicrosoft Gold Certified Partnerに認定されており、アプリケーションの開発およびインフラストラクチャのコンサル...

  • japan.internet.com(ジャパンインターネットコム)

    japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.com や EarthWeb.c...

バックナンバー

連載:japan.internet.com翻訳記事

もっと読む

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5