- 追加された行はこの色です。
- 削除された行はこの色です。
#title(XML-RPCを使ったWebサービスにアクセスする)
#navi(.NETプログラミング研究)
#contents
*.NETプログラミング研究 第74号 [#q8960d7b]
**.NET Tips [#xd9d44ce]
***XML-RPCを使ったWebサービスにアクセスする [#v9fa81fa]
**XML-RPCを使ったWebサービスにアクセスする [#v9fa81fa]
今回はXML-RPCによるWebサービスにアクセスする方法について説明します。XML-RPCはHTTPのPOSTでXMLデータを送信し、XMLデータとして結果を取得します。なおXML-RPCの仕様については、「XML-RPC 仕様書」をご覧ください。
-[[XML-RPC 仕様書>http://lowlife.jp/yasusii/stories/9.html]]
現在公に公開されているWebサービスでは、XML-RPCを使用したサービスは少ないようです。しかし、XML-RPCはブログ関係のAPIとしてはよく使われてきました。ブログへの投稿や、記事の更新、削除、情報の取得などを行うためのAPIであるBlogger APIや、Pingサーバーにブログの更新を伝えるためのWeblogs.Com XML-RPC interfaceなどはXML-RPCです。
-[[Weblogs.Com XML-RPC interface>http://www.xmlrpc.com/weblogsCom]]
そこでここでは、XML-RPCクライアントを作成する例として、Blogger APIを使用する方法を紹介します。
***Blogger APIを使う [#z8c18df0]
前述した通り、Blogger APIは、ブログへの投稿や、記事の更新、削除、さらに投稿された記事の情報の取得等を可能にするAPIです。さらにBlogger APIを拡張したmetaWeblog APIやMovable Type独自の拡張であるMovableType APIもよく知られています。Blogger APIはMovable Typeをはじめ多くのブログアプリケーションや、ホスティング型のブログサービスで利用できます。
-[[Movable Type 3.3 マニュアル - XML-RPC API>http://www.sixapart.jp/movabletype/manual/3.3/03_blog_username_guide/customizing_blogs/xmlrpc_api.html]]
-[[MovableType で使える XML-RPC API>http://www.na.rim.or.jp/~tsupo/program/blogTool/mt_xmlRpc.html]]
早速ですが、Blogger APIを使用する具体例として、blogger.getRecentPostsメソッドを呼び出して一番最近投稿した記事の内容(content)を取得し表示するサンプルを紹介します。POST送信するXMLデータの作成や、結果として返されたXMLデータの解析は手抜きですが(faultが返された時の処理も省略しています)、大雑把にはこんな感じです。
#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)
'リクエストURL
Dim requestUrl As String = _
"http://localhost/mt/mt-xmlrpc.cgi"
'メソッド名
Dim methodName As String = "blogger.getRecentPosts"
'ブログのID
Dim blogID As String = "1"
'ユーザー名とパスワード
Dim userName As String = "username"
Dim password As String = "password"
'取得する投稿の数
Dim numberOfPosts As Integer = 1
'POST送信するXMLを作成
Dim postData As String = "<?xml version=""1.0""?>" _
+ "<methodCall>" _
+ "<methodName>{0}</methodName>" _
+ "<params>" _
+ "<param><value><string>{1}</string></value></param>" _
+ "<param><value><string>{2}</string></value></param>" _
+ "<param><value><string>{3}</string></value></param>" _
+ "<param><value><string>{4}</string></value></param>" _
+ "<param><value><i4>{5}</i4></value></param>" _
+ "</params>" _
+ "</methodCall>"
postData = String.Format(postData, _
methodName, _
"", _
blogID, _
userName, _
password, _
numberOfPosts)
Dim postDataBytes As Byte() = _
System.Text.Encoding.UTF8.GetBytes(postData)
'HttpWebRequestの作成
Dim request As System.Net.HttpWebRequest = _
CType(System.Net.WebRequest.Create(requestUrl), _
System.Net.HttpWebRequest)
'POST
request.Method = "POST"
request.ContentType = "text/xml"
request.ContentLength = postDataBytes.Length
Dim reqStream As System.IO.Stream = request.GetRequestStream()
reqStream.Write(postDataBytes, 0, postDataBytes.Length)
reqStream.Close()
Dim response As System.Net.HttpWebResponse = Nothing
Dim doc As New System.Xml.XmlDocument()
Try
'レスポンスの取得
response = CType(request.GetResponse(), _
System.Net.HttpWebResponse)
Dim strm As System.IO.Stream = response.GetResponseStream()
'XmlDocumentに読込む
doc.Load(strm)
Catch ex As Exception
Label1.Text = "エラー:" + Server.HtmlEncode(ex.Message)
Return
Finally
If Not (response Is Nothing) Then
response.Close()
End If
End Try
'結果を解析する
Dim paramsNode As System.Xml.XmlNode = _
doc.SelectSingleNode("/methodResponse/params")
If paramsNode Is Nothing Then
Label1.Text += "該当する投稿が見つかりませんでした。"
Return
End If
Dim node As System.Xml.XmlNode
For Each node In paramsNode.SelectNodes("//member")
If node.SelectSingleNode("name").InnerText = "content" Then
Label1.Text += node.SelectSingleNode("value").InnerText _
+ "<hr />"
End If
Next node
End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Blogger APIのサンプル</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<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)
{
//リクエストURL
string requestUrl =
"http://localhost/mt/mt-xmlrpc.cgi";
//メソッド名
string methodName = "blogger.getRecentPosts";
//ブログのID
string blogID = "1";
//ユーザー名とパスワード
string userName = "username";
string password = "password";
//取得する投稿の数
int numberOfPosts = 1;
//POST送信するXMLを作成
string postData = @"<?xml version=""1.0""?>
<methodCall>
<methodName>{0}</methodName>
<params>
<param>
<value>
<string>{1}</string>
</value>
</param>
<param>
<value>
<string>{2}</string>
</value>
</param>
<param>
<value>
<string>{3}</string>
</value>
</param>
<param>
<value>
<string>{4}</string>
</value>
</param>
<param>
<value>
<i4>{5}</i4>
</value>
</param>
</params>
</methodCall>";
postData = string.Format(postData,
methodName,
"",
blogID,
userName,
password,
numberOfPosts);
byte[] postDataBytes = System.Text.Encoding.UTF8.GetBytes(postData);
//HttpWebRequestの作成
System.Net.HttpWebRequest request =
(System.Net.HttpWebRequest)System.Net.WebRequest.Create(
requestUrl);
//POST
request.Method = "POST";
request.ContentType = "text/xml";
request.ContentLength = postDataBytes.Length;
System.IO.Stream reqStream = request.GetRequestStream();
reqStream.Write(postDataBytes, 0, postDataBytes.Length);
reqStream.Close();
System.Net.HttpWebResponse response = null;
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
try
{
//レスポンスの取得
response = (System.Net.HttpWebResponse)request.GetResponse();
System.IO.Stream strm = response.GetResponseStream();
//XmlDocumentに読込む
doc.Load(strm);
}
catch (Exception ex)
{
Label1.Text = "エラー:" + Server.HtmlEncode(ex.Message);
return;
}
finally
{
if (response != null)
response.Close();
}
//結果を解析する
System.Xml.XmlNode paramsNode =
doc.SelectSingleNode("/methodResponse/params");
if (paramsNode == null)
{
Label1.Text += "該当する投稿が見つかりませんでした。";
return;
}
foreach (System.Xml.XmlNode node in
paramsNode.SelectNodes("//member"))
{
if (node.SelectSingleNode("name").InnerText == "content")
{
Label1.Text += node.SelectSingleNode("value").InnerText
+ "<hr />";
}
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Blogger APIのサンプル</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<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>
}}
リクエストを送信するURLは、Movable Typeの場合、mtフォルダ内にあるmt-xmlrpc.cgiとなります。また、XML-RPCには文字コードに関する明確な規定がないようですが、送信するリクエストは適当な文字コード(多分ブログで使用している文字コードとなるでしょう)で送受信する必要があるようです。
***XML-RPC.NETを使用する [#z8ce0572]
上記の例はかなり手を抜きましたが、それでも結構大変です。ちゃんとしたものを作るとなると、なおさらです。ありがたい事に、XML-RPCを実装するためのオープンソースのライブラリが存在します。それがXML-RPC.NETです。
-[[XML-RPC.NET>http://www.xml-rpc.net/]]
先と同じようにblogger.getRecentPostsメソッドを今度はXML-RPC.NETを使って呼び出してみましょう。
まずはDLLをプロジェクトの参照に追加します。XML-RPC.NETには2つのDLLがあります。CookComputing.XmlRpc.dllは.NET Frameworkのすべてのバージョンで使用できますが、CookComputing.XmlRpcV2.dllは2.0以上でしか使用できません。ここではすべてのバージョンで使用できるCookComputing.XmlRpc.dllを使います。
次に下に示すような構造体を宣言します。呼び出すメソッドのパラメータや戻り値に構造体が含まれないのであればその必要はありませんが、blogger.getRecentPostsメソッドの場合は、戻り値が構造体の配列となりますので、これに対応する構造体を宣言する必要があります(「Movable Type 3.3 マニュアル - XML-RPC API」をご覧ください)。なぜこのような構造体になるのかについては簡単にお分かりいただけると思いますので、特に説明の必要は無いでしょう。ただ、ISO.8601はDateTime型となります。これは、「XML-RPC.NET FAQ」で説明されています。
-[[XML-RPC.NET FAQ>http://www.xml-rpc.net/faq/xmlrpcnetfaq.html#1.9]]
#code(vbnet){{
Imports System
Namespace BloggerAPI
Public Structure Post
Public dateCreated As DateTime
Public userid As String
Public postid As String
Public content As String
End Structure
End Namespace
}}
#code(csharp){{
using System;
namespace BloggerAPI
{
public struct Post
{
public DateTime dateCreated;
public string userid;
public string postid;
public string content;
}
}
}}
次に、IXmlRpcProxyを継承した以下のようなインターフェイスを宣言します。XmlRpcMethod属性で対応するXML-RPCのメソッドを指定します。ここではblogger.getRecentPostsメソッドしかありませんが、その他のメソッドを記述してももちろんOKです。もしリクエスト先のURLが固定されているならば、インターフェイスにXmlRpcUrl属性を付けることもできます。
#code(vbnet){{
Imports System
Imports CookComputing.XmlRpc
Namespace BloggerAPI
Public Interface IBlogger
Inherits IXmlRpcProxy
<XmlRpcMethod("blogger.getRecentPosts")> _
Function getRecentPosts( _
ByVal appkey As String, _
ByVal blogid As String, _
ByVal username As String, _
ByVal password As String, _
ByVal numberOfPosts As Integer) As Post()
End Interface
End Namespace
}}
#code(csharp){{
using System;
using CookComputing.XmlRpc;
namespace BloggerAPI
{
public interface IBlogger : IXmlRpcProxy
{
[XmlRpcMethod("blogger.getRecentPosts")]
Post[] getRecentPosts(
string appkey,
string blogid,
string username,
string password,
int numberOfPosts);
}
}
}}
ここまでできればあとは実に簡単です。XmlRpcProxyGen.Createメソッドでプロキシクラスのインスタンスを作成し、getRecentPostsメソッドを呼び出すだけです。実際のコードは以下のようになります。
#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 proxy As BloggerAPI.IBlogger = _
CType(CookComputing.XmlRpc.XmlRpcProxyGen.Create( _
GetType(BloggerAPI.IBlogger)), BloggerAPI.IBlogger)
'URLを指定
proxy.Url = "http://localhost/mt/mt-xmlrpc.cgi"
Dim ps() As BloggerAPI.Post
Try
'blogger.getRecentPostsを呼び出す
ps = proxy.getRecentPosts("", "1", "username", "password", 1)
Catch ex As Exception
Label1.Text = "エラー:" + Server.HtmlEncode(ex.Message)
Return
End Try
'結果を表示する
If ps Is Nothing Or ps.Length = 0 Then
Label1.Text = "該当する投稿が見つかりませんでした。"
Return
End If
Label1.Text = ""
Label1.Text += "<ul>"
Dim p As BloggerAPI.Post
For Each p In ps
'contentを表示
Label1.Text += "<li>" + p.content
Next p
Label1.Text += "</ul>"
End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Blogger APIのサンプル</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<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)
{
//プロキシクラスのインスタンスを作成
BloggerAPI.IBlogger proxy = (BloggerAPI.IBlogger)
CookComputing.XmlRpc.XmlRpcProxyGen.Create(
typeof(BloggerAPI.IBlogger));
//URLを指定
proxy.Url = "http://localhost/mt/mt-xmlrpc.cgi";
BloggerAPI.Post[] ps;
try
{
//blogger.getRecentPostsを呼び出す
ps = proxy.getRecentPosts(
"",
"1",
"username",
"password",
1);
}
catch (Exception ex)
{
Label1.Text = "エラー:" + Server.HtmlEncode(ex.Message);
return;
}
//結果を表示する
if (ps == null || ps.Length == 0)
{
Label1.Text = "該当する投稿が見つかりませんでした。";
return;
}
Label1.Text = "";
Label1.Text += "<ul>";
foreach (BloggerAPI.Post p in ps)
{
//contentを表示
Label1.Text += "<li>" + p.content;
}
Label1.Text += "</ul>";
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Blogger APIのサンプル</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<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>
}}
ちなみにCookComputing.XmlRpcV2.dllを使用する場合は、次のようにしてプロキシクラスのインスタンスを作成します。
#code(vbnet){{
'プロキシクラスのインスタンスを作成
Dim proxy As BloggerAPI.IBlogger = _
CookComputing.XmlRpc.XmlRpcProxyGen.Create( _
Of BloggerAPI.IBlogger)()
}}
#code(csharp){{
//プロキシクラスのインスタンスを作成
BloggerAPI.IBlogger proxy =
CookComputing.XmlRpc.XmlRpcProxyGen.Create<BloggerAPI.IBlogger>();
}}
**コメント [#bb82a49c]
#comment
//これより下は編集しないでください
#pageinfo(,2010-03-19 (金) 02:59:54,DOBON!,2010-03-19 (金) 02:59:54,DOBON!)
#pageinfo([[:Category/.NET]],2006-09-25 (月) 06:00:00,DOBON!,2010-03-23 (火) 03:17:53,DOBON!)