.NETプログラミング研究 第72号 †
.NET Tips †
DOBON.NETのWikiサイト「DoboWiki」では新たな試みとして、現在公開されている有用なWebサービス(XML Webサービス)に関する情報の収集と紹介を始めました。
そこで今回は、.NET FrameworkによるプログラミングでWebサービスにアクセスする方法を具体例を挙げて紹介します。
SOAPを使ったWebサービスにアクセスする †
現在の一般的なWebサービスのほとんどはSOAPかRESTどちらかのインターフェイスを採用しています。まずは.NET Frameworkでの扱いが比較的簡単なSOAPを使ったWebサービスにアクセスする方法を紹介します。
MSDNではこれに関して、以下のページ等で解説されています。
ここでは具体例として、Googleの提供するWebサービスである、Google SOAP Search APIを使用してみましょう。
準備 †
Google SOAP Search APIサービスは登録しないと使用できません。まずは以下のページでアカウントを作成し、サービスの利用に必要なキーを取得します。
次にDeveloper's Kitをダウンロードし、書庫を展開しておきます。WSDLファイルや、C#やVB.NETのサンプルが含まれています。
プロキシクラスを作成する †
準備が整ったところで、本番に入ります。まずは、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を使用します)。
Wsdl.exeを使って作成されたプロキシクラスは、プロジェクトに追加して使用します。
補足:Visual Studioも内部ではWsdl.exeを使っていますので、Wsdl.exeがパラメータを指定できるという点を除けば同じといえます。
プロキシクラスを使用してWebサービスにアクセスする †
上記のようにして作成したプロキシクラスを使用すれば、Webサービスへのアクセスは驚くほど簡単です。プロキシクラスのインスタンスを作成して、適当なメソッドを呼び出すだけで済みます。
まずは具体例を示しましょう。以下にGoogle SOAP Search APIを使用して文字列をウェブ検索するWebアプリケーションのサンプルを紹介します。テキストボックスに入力した文字列を検索し、結果を最大10件表示しています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
| | <%@ 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>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
| | <%@ 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の次のページが参考になります。
.NET Framework 2.0ではイベントドリブンの非同期パターンを使用することもできます。これについては、次に示すページが参考になります。
Google SOAP Search APIの使い方 †
Google SOAP Search APIの使い方をさらに詳しく説明します。Google SOAP Search APIのリファレンスは、「Google SOAP Search API Reference」にあります。これは先ほどダウンロードしたDeveloper's Kitにも含まれています。
注意:Google SOAP Search APIは現在ベータ版です。また、将来仕様が変更される可能性があります。
Google SOAP Search APIには主に3つの機能 - ウェブ検索、キャッシュの取得、スペルチェック - が用意されています。まずはウェブ検索機能について説明します。
ウェブ検索機能 †
早速ですが、先ほどのサンプルを書き直し、検索オプションを追加してみます。具体的には、「類似の結果を隠す」「日本語のページのみ検索する」「日本のサイトのみ検索する」「アダルトコンテンツを除外する」という項目を追加します。さらに、結果もより詳しく表示します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
| | <%@ 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 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>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
| | <%@ 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 />";
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メソッドの構文は次の通りです。
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
- ディレクトリ情報のエンコーディングスキームを指定する。
その他の機能 †
Google SOAP Search APIのキャッシュの取得、スペルチェック機能の使い方はさらに簡単です。それぞれプロキシクラスのdoGetCachedPage、doSpellingSuggestionメソッドを呼び出せばよいのです。
これらのサンプルについては、ここに載せるには長すぎますので、DoboWikiにて公開する予定です。
コメント †