#title(SOAPを使ったWebサービスにアクセスする) #navi(.NET プログラミング研究) #contents *.NETプログラミング研究 第72号 [#p41a66dd] **.NET Tips [#qe425db3] DOBON.NETのWikiサイト「DoboWiki」では新たな試みとして、現在公開されている有用なWebサービス(XML Webサービス)に関する情報の収集と紹介を始めました。 -[[DoboWiki>http://wiki.dobon.net/]] -[[Webサービス紹介>http://wiki.dobon.net/index.php?%BC%AB%CD%B3%B6%E8%2FWeb%A5%B5%A1%BC%A5%D3%A5%B9%BE%D2%B2%F0]] そこで今回は、.NET FrameworkによるプログラミングでWebサービスにアクセスする方法を具体例を挙げて紹介します。 **SOAPを使ったWebサービスにアクセスする [#s2389c78] 現在の一般的なWebサービスのほとんどはSOAPかRESTどちらかのインターフェイスを採用しています。まずは.NET Frameworkでの扱いが比較的簡単なSOAPを使ったWebサービスにアクセスする方法を紹介します。 MSDNではこれに関して、以下のページ等で解説されています。 -[[マネージ コードを使用した XML Web サービスへのアクセス>http://msdn2.microsoft.com/ja-jp/library/7sxekx3f.aspx]] -[[XML Web サービス クライアントの構築>http://msdn2.microsoft.com/ja-jp/library/w3h45ebk.aspx]] ここでは具体例として、Googleの提供するWebサービスである、Google SOAP Search APIを使用してみましょう。 -[[Google SOAP Search API>http://www.google.com/apis/]] ***準備 [#mf381755] Google SOAP Search APIサービスは登録しないと使用できません。まずは以下のページでアカウントを作成し、サービスの利用に必要なキーを取得します。 -[[Create a Google Account>https://www.google.com/accounts/NewAccount?continue=http://api.google.com/createkey&followup=http://api.google.com/createkey]] 次にDeveloper's Kitをダウンロードし、書庫を展開しておきます。WSDLファイルや、C#やVB.NETのサンプルが含まれています。 -[[Download the Google SOAP Search API Developer's Kit>http://www.google.com/apis/download.html]] ***プロキシクラスを作成する [#ta1048dc] 準備が整ったところで、本番に入ります。まずは、Webサービスに簡単にアクセスできるようにするためのプロキシクラスを作成します。 Visual Studioをご利用の方は、Webサービスを使用するプロジェクトをソリューションエクスプローラで右クリックし、コンテキストメニューから「Web参照の追加」を選択します。すると「Web参照の追加」ダイアログが表示されますので、この「URL」に先ほどダウンロードした「Google SOAP Search API Developer's Kit」内にあるWSDLファイル(ファイル名は「GoogleSearch.wsdl」)のフルパスを入力し、「移動」ボタンをクリックします。しばらくしてから、「このURLで見つかったWebサービス」に「1個のサービスが見つかりました - GoogleSearch」と表示されるはずです。「Web参照名」に名前空間となる文字列を入力し(名前空間が不要であれば空白でも構いません)、「参照の追加」ボタンをクリックします。ここでは「Web参照名」を「Google」としておきましょう。このようにして作成されたプロキシクラスは、「Google.GoogleSearch」となります。 Visual Studioを使用できない場合は、.NET FrameworkツールのWsdl.exeを使用してプロキシクラスを作成できます(C++の場合は、SPROXY.EXEを使用します)。 -[[Web サービス記述言語ツール (Wsdl.exe)>http://msdn.microsoft.com/library/ja/cptools/html/cpgrfwebservicesdescriptionlanguagetoolwsdlexe.asp]] -[[ネイティブ Web サービス プロキシ ジェネレータ>http://msdn.microsoft.com/library/ja/vccore/html/vcconSProxyexe.asp]] Wsdl.exeを使って作成されたプロキシクラスは、プロジェクトに追加して使用します。 補足:Visual Studioも内部ではWsdl.exeを使っていますので、Wsdl.exeがパラメータを指定できるという点を除けば同じといえます。 ***プロキシクラスを使用してWebサービスにアクセスする [#ta2fc2ae] 上記のようにして作成したプロキシクラスを使用すれば、Webサービスへのアクセスは驚くほど簡単です。プロキシクラスのインスタンスを作成して、適当なメソッドを呼び出すだけで済みます。 まずは具体例を示しましょう。以下にGoogle SOAP Search APIを使用して文字列をウェブ検索するWebアプリケーションのサンプルを紹介します。テキストボックスに入力した文字列を検索し、結果を最大10件表示しています。 #code(vbnet){{ <%@ Page Language="VB" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script runat="server"> Protected Sub Button1_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) 'キーを指定。必ず変更すること。 Dim key As String = "XXXXXXXXXXXXXXXXXXXXXXXXXX" '結果の開始インデックス Dim startIndex As Integer = 0 '取得する結果の最大値 Dim maxResults As Integer = 10 'プロキシクラスのインスタンスを作成 Dim gs As New Google.GoogleSearchService() Dim res As Google.GoogleSearchResult = Nothing Try '検索する res = gs.doGoogleSearch( _ key, _ TextBox1.Text, _ startIndex, _ maxResults, _ True, _ "", _ False, _ "", _ "", _ "") Catch ex As System.Web.Services.Protocols.SoapException Label1.Text = "エラー:" + Server.HtmlEncode(ex.Message) Return End Try If res Is Nothing Then Label1.Text = "エラー:結果を取得できませんでした。" Return End If '結果表示 Label1.Text = "" Label1.Text += "<b>" + Server.HtmlEncode(res.searchQuery) + _ "</b> の検索結果 約 " + _ res.estimatedTotalResultsCount.ToString() + _ "件中 " + res.startIndex.ToString() + " - " + _ res.endIndex.ToString() + " 件目 (" + _ res.searchTime.ToString() + " 秒)<br />" 'ヒットした検索結果 If Not (res.resultElements Is Nothing) AndAlso _ res.resultElements.Length > 0 Then Label1.Text += "<ul>" Dim element As Google.ResultElement For Each element In res.resultElements Label1.Text += "<li><a href=""" + element.URL + """>" + _ element.title + "</a>" Next element Label1.Text += "</ul>" End If End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <title>Google SOAP Search APIのサンプル</title> </head> <body> <form id="form1" runat="server"> <div> <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox> <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="検索開始" /><br /> <br /> <asp:Label ID="Label1" runat="server" EnableViewState="False"> </asp:Label></div> </form> </body> </html> }} #code(csharp){{ <%@ Page Language="C#" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script runat="server"> protected void Button1_Click(object sender, EventArgs e) { //キーを指定。必ず変更すること。 string key = "XXXXXXXXXXXXXXXXXXXXXXXXXX"; //結果の開始インデックス int startIndex = 0; //取得する結果の最大値 int maxResults = 10; //プロキシクラスのインスタンスを作成 Google.GoogleSearchService gs = new Google.GoogleSearchService(); Google.GoogleSearchResult res = null; try { //検索する res = gs.doGoogleSearch( key, TextBox1.Text, startIndex, maxResults, true, "", false, "", "", ""); } catch (System.Web.Services.Protocols.SoapException ex) { Label1.Text = "エラー:" + Server.HtmlEncode(ex.Message); return; } if (res == null) { Label1.Text = "エラー:結果を取得できませんでした。"; return; } //結果表示 Label1.Text = ""; Label1.Text += "<b>" + Server.HtmlEncode(res.searchQuery) + "</b> の検索結果 約 " + res.estimatedTotalResultsCount.ToString() + "件中 " + res.startIndex.ToString() + " - " + res.endIndex.ToString() + " 件目 (" + res.searchTime.ToString() + " 秒)<br />"; //ヒットした検索結果 if (res.resultElements != null && res.resultElements.Length > 0) { Label1.Text += "<ul>"; foreach (Google.ResultElement element in res.resultElements) { Label1.Text += "<li><a href=\"" + element.URL + "\">" + element.title + "</a>"; } Label1.Text += "</ul>"; } } </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Google SOAP Search APIのサンプル</title> </head> <body> <form id="form1" runat="server"> <div> <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox> <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="検索開始" /><br /> <br /> <asp:Label ID="Label1" runat="server" EnableViewState="False"> </asp:Label></div> </form> </body> </html> }} 補足:上記のコードは分かりやすさを優先しているため、あまり良いとはいえない書き方があるかもしれません。例えば、文字列の連結は上記のようにするよりもStringBulderクラスを使った方が効率的でしょう。 このように、プロキシクラスGoogleSearchServiceのインスタンスを作成し、doGoogleSearchメソッドを呼び出しているだけです(パラメータがやたらと多いですが)。サーバーから返される結果も、自分で解析する必要がなく、GoogleSearchResultオブジェクトとして取得できます。 補足:Webサービスへのアクセスに認証が必要な時は、プロキシクラスのCredentialsプロパティを設定します。 補足:上記のdoGoogleSearchメソッドは同期的に行われますが、BegindoGoogleSearchとEnddoGoogleSearchなどを使って非同期的に行うこともできます。非同期アクセスについては、MSDNの次のページが参考になります。 -[[XML Web サービスとの非同期通信>http://msdn2.microsoft.com/ja-jp/library/tz4bkcx2.aspx]] .NET Framework 2.0ではイベントドリブンの非同期パターンを使用することもできます。これについては、次に示すページが参考になります。 -[[方法 : ASP.NET 2.0 を使用してイベント ドリブン非同期 Web サービス クライアントを実装する>http://msdn2.microsoft.com/ja-jp/library/ms230194.aspx]] ***Google SOAP Search APIの使い方 [#ba9ae175] Google SOAP Search APIの使い方をさらに詳しく説明します。Google SOAP Search APIのリファレンスは、「Google SOAP Search API Reference」にあります。これは先ほどダウンロードしたDeveloper's Kitにも含まれています。 -[[Google SOAP Search API Reference>http://www.google.com/apis/reference.html]] 注意:Google SOAP Search APIは現在ベータ版です。また、将来仕様が変更される可能性があります。 Google SOAP Search APIには主に3つの機能 - ウェブ検索、キャッシュの取得、スペルチェック - が用意されています。まずはウェブ検索機能について説明します。 ***ウェブ検索機能 [#o4b357f4] 早速ですが、先ほどのサンプルを書き直し、検索オプションを追加してみます。具体的には、「類似の結果を隠す」「日本語のページのみ検索する」「日本のサイトのみ検索する」「アダルトコンテンツを除外する」という項目を追加します。さらに、結果もより詳しく表示します。 #code(vbnet){{ <%@ Page Language="VB" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script runat="server"> Protected Sub Button1_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) 'キーを指定。必ず変更すること。 Dim key As String = "XXXXXXXXXXXXXXXXXXXXXXXXXX" '結果の開始インデックス Dim startIndex As Integer = 0 '取得する結果の最大値 Dim maxResults As Integer = 10 '検索の対象にする言語 Dim lr As String = "" If langJapanese.Checked Then lr = "lang_ja" End If '国などを指定 Dim restricts As String = "" If countryJapan.Checked Then restricts = "countryJP" End If '入力、出力文字コード。現在は指定不可。 Dim inputEncoding As String = "" Dim outputEncoding As String = "" 'プロキシクラスのインスタンスを作成 Dim gs As New Google.GoogleSearchService() Dim res As Google.GoogleSearchResult = Nothing Try '検索する res = gs.doGoogleSearch( _ key, _ TextBox1.Text, _ startIndex, _ maxResults, _ autoFiltering.Checked, _ restricts, _ safeSearch.Checked, _ lr, _ inputEncoding, _ outputEncoding) Catch ex As System.Web.Services.Protocols.SoapException Label1.Text = "エラー:" + Server.HtmlEncode(ex.Message) Return End Try If res Is Nothing Then Label1.Text = "エラー:結果を取得できませんでした。" Return End If '結果表示 Label1.Text = "" Label1.Text += "<b>" + Server.HtmlEncode(res.searchQuery) + _ "</b> の検索結果 約 " + _ res.estimatedTotalResultsCount.ToString() + "件中 " + _ res.startIndex.ToString() + " - " + _ res.endIndex.ToString() + " 件目 (" + _ res.searchTime.ToString() + " 秒)<br />" 'コメントがあるときは表示 If Not (res.searchComments Is Nothing) AndAlso _ res.searchComments.Length > 0 Then Label1.Text += "<br />" + res.searchComments + "<br />" End If 'Tipsがあるときは表示 If Not (res.searchTips Is Nothing) AndAlso _ res.searchTips.Length > 0 Then Label1.Text += "<br />" + res.searchTips + "<br />" End If 'カテゴリがあるときは表示 If Not (res.directoryCategories Is Nothing) AndAlso _ res.directoryCategories.Length > 0 Then Label1.Text += "<br /><b>カテゴリ:</b><br />" Label1.Text += "<ul>" Dim categories As Google.DirectoryCategory For Each categories In res.directoryCategories Label1.Text += "<li>" + categories.fullViewableName Next categories Label1.Text += "</ul>" Label1.Text += "<br />" End If 'ヒットした検索結果 If Not (res.resultElements Is Nothing) AndAlso _ res.resultElements.Length > 0 Then Label1.Text += "<ul>" Dim element As Google.ResultElement For Each element In res.resultElements 'タイトルの表示(リンク付き) Label1.Text += "<li><a href=""" + element.URL + """>" If Not (element.title Is Nothing) AndAlso _ element.title.Length > 0 Then Label1.Text += element.title Else Label1.Text += element.URL End If Label1.Text += "</a>" 'ヒットした箇所の周辺を表示 If Not (element.snippet Is Nothing) AndAlso _ element.snippet.Length > 0 Then Label1.Text += "<br />" + element.snippet End If Label1.Text += "<br /><small>" + element.URL 'キャッシュのサイズを表示 Label1.Text += " - " + element.cachedSize '関連ページの有無を表示 If element.relatedInformationPresent Then Label1.Text += " - 関連ページあり" End If Label1.Text += "</small>" + ControlChars.Lf Next element Label1.Text += "</ul>" End If End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <title>Google SOAP Search APIのサンプル</title> </head> <body> <form id="form1" runat="server"> <div> <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox> <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="検索開始" /><br /> <asp:CheckBox ID="autoFiltering" runat="server" Text="類似の結果を隠す" /><br /> <asp:CheckBox ID="langJapanese" runat="server" Text="日本語のページのみ検索する" /><br /> <asp:CheckBox ID="countryJapan" runat="server" Text="日本のサイトのみ検索する" /><br /> <asp:CheckBox ID="safeSearch" runat="server" Text="アダルトコンテンツを除外する" /><br /> <br /> <asp:Label ID="Label1" runat="server" EnableViewState="False"> </asp:Label></div> </form> </body> </html> }} #code(csharp){{ <%@ Page Language="C#" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script runat="server"> protected void Button1_Click(object sender, EventArgs e) { //キーを指定。必ず変更すること。 string key = "XXXXXXXXXXXXXXXXXXXXXXXXXX"; //結果の開始インデックス int startIndex = 0; //取得する結果の最大値 int maxResults = 10; //検索の対象にする言語 string lr = ""; if (langJapanese.Checked) lr = "lang_ja"; //国などを指定 string restricts = ""; if (countryJapan.Checked) restricts = "countryJP"; //入力、出力文字コード。現在は指定不可。 string inputEncoding = ""; string outputEncoding = ""; //プロキシクラスのインスタンスを作成 Google.GoogleSearchService gs = new Google.GoogleSearchService(); Google.GoogleSearchResult res = null; try { //検索する res = gs.doGoogleSearch( key, TextBox1.Text, startIndex, maxResults, autoFiltering.Checked, restricts, safeSearch.Checked, lr, inputEncoding, outputEncoding); } catch (System.Web.Services.Protocols.SoapException ex) { Label1.Text = "エラー:" + Server.HtmlEncode(ex.Message); return; } if (res == null) { Label1.Text = "エラー:結果を取得できませんでした。"; return; } //結果表示 Label1.Text = ""; Label1.Text += "<b>" + Server.HtmlEncode(res.searchQuery) + "</b> の検索結果 約 " + res.estimatedTotalResultsCount.ToString() + "件中 " + res.startIndex.ToString() + " - " + res.endIndex.ToString() + " 件目 (" + res.searchTime.ToString() + " 秒)<br />"; //コメントがあるときは表示 if (res.searchComments != null && res.searchComments.Length > 0) Label1.Text += "<br />" + res.searchComments + "<br />"; //Tipsがあるときは表示 if (res.searchTips != null && res.searchTips.Length > 0) Label1.Text += "<br />" + res.searchTips + "<br />"; //カテゴリがあるときは表示 if (res.directoryCategories != null && res.directoryCategories.Length > 0) { Label1.Text += "<br /><b>カテゴリ:</b><br />"; Label1.Text += "<ul>"; foreach (Google.DirectoryCategory categories in res.directoryCategories) { Label1.Text += "<li>" + categories.fullViewableName; } Label1.Text += "</ul>"; Label1.Text += "<br />"; } //ヒットした検索結果 if (res.resultElements != null && res.resultElements.Length > 0) { Label1.Text += "<ul>"; foreach (Google.ResultElement element in res.resultElements) { //タイトルの表示(リンク付き) Label1.Text += "<li><a href=\"" + element.URL + "\">"; if (element.title != null && element.title.Length > 0) Label1.Text += element.title; else Label1.Text += element.URL; Label1.Text += "</a>"; //ヒットした箇所の周辺を表示 if (element.snippet != null && element.snippet.Length > 0) Label1.Text += "<br />" + element.snippet; Label1.Text += "<br /><small>" + element.URL; //キャッシュのサイズを表示 Label1.Text += " - " + element.cachedSize; //関連ページの有無を表示 if (element.relatedInformationPresent) Label1.Text += " - 関連ページあり"; Label1.Text += "</small>\n"; } Label1.Text += "</ul>"; } } </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Google SOAP Search APIのサンプル</title> </head> <body> <form id="form1" runat="server"> <div> <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox> <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="検索開始" /><br /> <asp:CheckBox ID="autoFiltering" runat="server" Text="類似の結果を隠す" /><br /> <asp:CheckBox ID="langJapanese" runat="server" Text="日本語のページのみ検索する" /><br /> <asp:CheckBox ID="countryJapan" runat="server" Text="日本のサイトのみ検索する" /><br /> <asp:CheckBox ID="safeSearch" runat="server" Text="アダルトコンテンツを除外する" /><br /> <br /> <asp:Label ID="Label1" runat="server" EnableViewState="False"> </asp:Label></div> </form> </body> </html> }} まずはGoogleSearchService.doGoogleSearchメソッドのパラメータについて説明しましょう。doGoogleSearchメソッドの構文は次の通りです。 #pre{{ public GoogleSearchResult doGoogleSearch( string key, string q, int start, int maxResults, bool filter, string restrict, bool safeSearch, string lr, string ie, string oe ) }} それぞれのパラメータの意味は次のようなものです。 :key|Googleから与えられた、Webサービスを使用するために必要なキー。 :q|検索する語句(クエリー)。 :start|取得する結果の開始インデックス番号。0から始まる。 :maxResults|取得する結果の最大数。10以下とする。 :filter|類似した結果や、同じWebホストの結果を隠すかどうか。 :restrict|国(トップレベルドメイン名と、IPアドレスの地理的位置を考慮して判断される)などを指定する。日本ならば、"countryJP"。 :safeSearch|アダルトコンテンツを除外するか。 :lr|検索の対象にする言語を指定する。日本語ならば、"lang_ja"。 :ie|入力文字コードを指定する。ただし、現在は無視され、必ずUTF-8となる。 :oe|出力文字コードを指定する。ただし、現在は無視され、必ずUTF-8となる。 doGoogleSearchメソッドによる検索の結果はGoogleSearchResultオブジェクトとして取得されます。GoogleSearchResultクラスのプロパティは次のようなものです。 :documentFiltering|フィルタリング(類似した、あるいは同一Webホストの結果を隠す)されたか。 :searchComments|「"???"は使用されませんでした。」のようなコメントだと思われる。 :estimatedTotalResultsCount|ヒットした結果のおおよその総数。 :estimateIsExact|estimatedTotalResultsCountが正確な値かどうか。 :resultElements|結果が格納された配列。 :searchQuery|GoogleSearchServiceのq。 :startIndex|検索結果で取得した始めの位置。1がはじめ。 :endIndex|検索結果で取得した最後の位置。 searchTips : Googleの使い方のヒント。多分「もしかして:???」や「ヒント:日本語 の結果のみを検索」だと思われる。 :directoryCategories|該当するODPディレクトリのカテゴリの配列。 :searchTime|検索にかかった時間(秒)。 ヒットしたページの情報が格納されるresultElementsプロパティはResultElementクラスの配列となります。ResultElementクラスのプロパティは次の通りです。 :summary|結果がODPディレクトリにある場合、ODPディレクトリの概要が格納される。 :URL|結果のURL。 :snippet|結果のページ内でヒットした部分の周囲の文。ヒットした部分は<B>タグで括られる。 :title|結果のタイトル。ヒットした部分があれば<B>タグで括られる。 :cachedSize|キャッシュのサイズ。"100k"のような文字列となる。 :relatedInformationPresent|「関連ページ」があるかどうか。 :hostName|同一ホストの結果がフィルタリングされた場合、2番目の結果にホスト名が格納される。 :directoryCategory|結果がODPディレクトリにある場合、そのカテゴリ情報。 :directoryTitle|結果がODPディレクトリにある場合、ディレクトリでのタイトル。 GoogleSearchResult.directoryCategoriesプロパティやResultElement.directoryCategoryプロパティではDirectoryCategoryクラスが使われます。DirectoryCategoryクラスのプロパティは次の通りです。 :fullViewableName|ODPカテゴリのODPディレクトリ名。 :specialEncoding|ディレクトリ情報のエンコーディングスキームを指定する。 ***その他の機能 [#z90a0595] Google SOAP Search APIのキャッシュの取得、スペルチェック機能の使い方はさらに簡単です。それぞれプロキシクラスのdoGetCachedPage、doSpellingSuggestionメソッドを呼び出せばよいのです。 これらのサンプルについては、ここに載せるには長すぎますので、DoboWikiにて公開する予定です。 -[[Google SOAP Search API>http://wiki.dobon.net/index.php?%BC%AB%CD%B3%B6%E8%2FWeb%A5%B5%A1%BC%A5%D3%A5%B9%BE%D2%B2%F0%2FGoogle%20SOAP%20Search%20API]] **コメント [#sc432d8e] #comment //これより下は編集しないでください #pageinfo([[:Category/.NET]],2006-08-25 (金) 06:00:00,DOBON!,2010-03-23 (火) 03:00:49,DOBON!) |