.NETでwebサービスを使う

まずは・・・はじめに

.NETではUDDI,WSDL,SOAPを用いたwebサービスとの連携が可能です. .NETでwebサービスを使うこと自体は簡単にできるのですが, ちょっと変わったことをしようと思うと,なかなか難しいものです.

ここでは,.NETを使ってwebサービスを呼び出すために, いろいろとやってみた結果を書いてみます.

何分,.NETのwebサービスに関する書籍等を参考にしたわけではなく, ヘルプとwebのドキュメントだけを頼りにしてますので, 間違い等もたくさんあると思います. 間違いを見つけたら,教えてもらえると有難いです^^;;.

開発環境は,Visual Studio .NETで,言語はC#です. 言語については,VB.NETなんかでも同じように書けるでしょうし, 相互に呼んでもOKだと思いますから,問題なしですね^^;;;. (Visual Basicは使ったことないけどね)

webサービス参照を追加する

まずは,Visual Studioからwebサービス参照を追加してみましょう. この方法だと,多くを統合環境がやってくれますので,お手軽です.

webサービスとしては何でも良いんですが, XMethodsから Currency Exchange Rate を選んでみます.なんか,英語で書いてあって大変ですが, メソッド呼ぶだけですから,何とかなるでしょう,きっと. (もちろん, WebService同好会 等で,探しても良いですよね.)

ともかく,Visual Studio .NETを起動しましょう. 新しいプロジェクトを選んで,プロジェクトを作ります. プロジェクトの種類はVisual C#プロジェクト, テンプレートはWindowsアプリケーションにします. プロジェクトを開いたら,さっそくフォームを作りましょう. 必要なのは,MainMenuとテキストボックスだけです.

screenshot1

こんな感じですかね. メニューのExitの所は,ダブルクリックしてコードを埋めておきましょう.

private void menuItem1_Click(object sender, System.EventArgs e)
{
  Application.Exit();
}

次に,web参照の追加を行います. プロジェクトメニューから, web参照の追加を選びましょう.

screenshot2

開いたダイアログのアドレスにhttp://www.xmethods.net/sd/2001/CurrencyExchangeService.wsdl を入力します.

screenshot3

あとは,Visual Studio .NETが,がしがしと処理をして, プロキシクラスを生成してくれます.

screenshot4

net.xmethods.wwwな空間が ソリューションエクスプローラに見えてますね.

クラスが追加されたら,呼び出してみましょう. まずは,Form1.csの先頭の所に,usingが並んでいますが,以降お手軽にするために, net.xmethods.wwwを追加しておきます.

using soapdoc1.net.xmethods.www;

soapdoc1というのは,プロジェクト名ですね. はじめに決めたプロジェクト名に置き換えておいて下さい. 次に,先程のメニューExitの時のように,メニューInvokeのハンドラを作ります.

private void menuItem2_Click(object sender, System.EventArgs e)
{
  CurrencyExchangeService ws=new CurrencyExchangeService();
  float rate=ws.getRate("usa","japan");
  textBox1.Text=rate.ToString();
}

最初の行で,プロキシクラスのインスタンスを生成します. これは,クラスビューで確認してもらうと良いでしょう. 本当なら,soapdoc1.net.xmethods.wwwの空間にあるのですが, usingのおかげで空間を指定しなくても済んでいます. 後は普通にメソッドを呼び出すだけです. ここでは,USAと日本円のレートを取得してみています. "どうして,メソッド名,引数,返り値が分かるの?" という方もいらっしゃるかもしれませんが,これは, XMethodsのCurrency Exchange Rateから, 下の方にあるDetailed Description,Usage Notesの所を見ると,出てくると思います.

以上,済んだら,コンパイルして実行してみましょう. Invokeを押してしばらく待つと,レートが表示されるはずです.

screenshot5

SOAP Toolkitを使ってみる

さて,Webサービス参照では,プロキシクラスを プログラムのコーディング時に生成したのですが, これだと,静的なサービス呼び出ししかできないような気がします. いや,きっちり確認したわけではないんですけどね. というわけで, 実行時に動的にサービスとのインタフェースを構築するために,Microsoft SOAP Toolkit を使ってみます.

とりあえず,SOAP ToolkitはCOM呼び出しができるようですし, COMで呼びます.というか,.NETで呼びたいのですが,分からなかったので, COMです^^;;.

SOAP Toolkitを使うのであれば,もちろん,SOAP Toolkitをインストールしなければいけません. MSDN DownloadsのSOAP Toolkit 3.0 あたりから, ダウンロード してインストールします.

次に,Visual Studio .NETを起動して,先程と同様に新しいプロジェクトを作り, フォームを作っておきます.前と同じようなフォームで,Exit等も実装しておきます.

SOAP Toolkitの参照を追加するため,プロジェクト→参照の追加と選び, COM参照のMicrosoft Soap Type Library v3.0を選択します.

screenshot6

そうすると,ソリューションエクスプローラに参照MSSOAPLib30が追加されると思います.

ではコードを追加していきましょう. 先程と同じように,usingの所に,以下を追加しておきます.

using MSSOAPLib30;
using System.Reflection;

はじめのは,SOAP Toolkitの空間ですね. 次のはリフレクションを使うためです(あっ,Reflectionの方,テスト用の方に使ってたやつだから,要らないかも.).

で,前のように,メニューInvokeのハンドラを以下のようにしましょう.

private void menuItem2_Click(object sender, System.EventArgs e)
{
  SoapClient30 sc = new SoapClient30();
  string url = "http://www.xmethods.net/sd/2001/CurrencyExchangeService.wsdl";
  object [] args = new object [] {"usa", "japan"};
  sc.MSSoapInit(url,"CurrencyExchangeService","CurrencyExchangePort","");
  Type type =sc.GetType(); 

  object o = type.InvokeMember("getRate", 
    BindingFlags.InvokeMethod,
    null,
    sc,
    args); 

  textBox1.Text=o.ToString();
}

ここで,WSDLの場所と,メソッド名は良いのですが, MSSoapInitの引数のCurrencyExchangeService,CurrencyExchangePort はどうやって分かったのか謎ですね. Currency Exchange Rate の黄色のバーの部分のAnalyze WSDLを見てみましょう. そうすると,Service [Port]という項目があり, CurrencyExchangeService [CurrencyExchangePort]と書かれています. 要するに,MSSoapInitの引数として,WSDLのURL,サービス名,ポート名を渡してるということですね. 最後の引数は,WSMLファイルの場所を渡すのですが,空文字列を渡しておいても大丈夫です. argsには,引数をobject型配列を用意しておきます.で,型を取得してInvokeMemberという手順です.

実行時にプロキシを生成してバインドする

このように,SOAP Toolkitで動的にWSDLファイルから呼び出しができました. COM使って呼び出すというのは,せっかく.NETなのに,なんだかなぁというのと, なにより,型情報の扱いが面倒です. 前の方法では,さらっとobject型を使って処理してますが, 呼び出すサービスが,クラスや配列やというものがからんでいると,どうでしょう. また,GetTypeを使って型を取得しているのですが, 何だか,どうやっても,この型にあるメソッドのはずのGetRate等が取れないのですね. InvokeMemberとかオーバーライドしてるのかなぁ.それともCOMだと,そんなものなのかなぁ.

というわけで,最後は,次を目標にしましょう.

で,これをどーやって実現するんやぁということになるわけです. ちょこちょこっと考えると,

…,考えるだけで,やですね. ですが,この面倒な部分を,さくさくっとやってくれるクラスを .NET XML Web Services Repertory にて見つけたので,それを使いましょう. Samplesの "Dynamic XML Web Services Invocation Demo" というのですが,なくなってたらごめんなさい. でも,なくなると困るので, ここにも似たようなのを置いておきます. ここにも置いておきますというわりには,内容が, .NET XML Web Services Repertory にあるものと違うんですが(似たようなのをと言ってるでしょ^^;;),変更点は, いきなりメソッドを呼ぶだけでなく,プロキシの型を取得できるように した点です.こうすることにより,リフレクションを使って, メソッド一覧とか取得できますしね. では,このファイルを使って, Webサービスを呼んでみましょう.

例によって,Visual Studio .NETでプロジェクトを作り, フォームを埋めます. また,ダウンロードしてきたファイルもプロジェクトのフォルダに コピーしておきましょう.

プロジェクトにファイルを追加してやらないといけませんが, ソリューションエクスプローラで右クリックし, 追加→既存項目の追加と選択します.

screenshot7

また,System.Web.Servicesを追加してやらないといけません. プロジェクト→参照の追加と選んでやって,.NETから, System.Web.Services.dllを追加してやります.

screenshot8

メニューIvokeの実装は以下のようになっています.

private void menuItem2_Click(object sender, System.EventArgs e)
{
  WSDLLateBinding.Client PC = new WSDLLateBinding.Client();
  WSDLLateBinding.SoapRequest SR = new WSDLLateBinding.SoapRequest();

  SR.wsdlfile="http://www.xmethods.net/sd/2001/CurrencyExchangeService.wsdl";
  SR.baseUrl = "http://www.xmethods.net/sd/2001/";
  SR.ServiceName = "CurrencyExchangeService";
  SR.dynamicNameSpace = "NS_" + SR.ServiceName;
  SR.dynFileNameSource = "Source_" + SR.ServiceName;
  SR.OperationName="getRate";
  SR.addParameter("country1","usa");
  SR.addParameter("country2","japan");
  Object obj=PC.ExecuteMethod(SR);
  textBox1.Text=obj.ToString();
}

addParameterのcountry1とcountry2は, 先程と同じように, Currency Exchange Rate の黄色のバーの部分のAnalyze WSDLから, Operation,Input Messageと選べば出てきます. ServiceNameは,さっきも出てきましたね. あとの,NSとかSourceとかは,生成するクラスの名前空間とファイルの名前を決めています.

実行して,Invokeすると,しばらく待たされた後,結果が表示されるかと思います. で,実行後,実行ファイルが置かれているフォルダを見ると, Source_CurrencyExchangeService.cs,Source_CurrencyExchangeService.dll が出きているはずです. 要するに,WSDLからcsなファイルを生成して,コンパイルしてDLLを作っているわけですね.

.NET XML Web Services Repertory にあるのとは違って,型も取れるようにしてあります. 型が取りたい場合は, ExecuteMethodのかわりに,GetMethodStubでObject型のオブジェクトを作り, そこから,GetTypeし,あとは,GetMembersやらInvokeMemberやら何やらすれば良いでしょう.