テスト1:WebサービスのXMLデータを取得する
このプロジェクトでは、Webサービスを呼び出してビジネスパートナーからのデータを取得および表示します。具体的には特定のURLを要求することによって、またPOSTヘッダーを通じて日付範囲を指定することによって、このWebサービスを呼び出します。Webサービスは対象のデータを取得し、それをXMLにシリアライズされたADO.NET DataSetとして返します。
顧客から質問を受ける前は、Visual Studioが自動生成したプロキシクラスを使用して、このWebサービスにアクセスしていました。プロキシクラスは、入力として2つの日付値を取り、DataSetを返す単一のメソッドを含んでいます。以下のコードは、どうやってWebサービスを呼び出してこのデータを取得するかを示しています。プロキシクラスが、Webサービスを呼び出すという実装の複雑さをすべて隠蔽していることに注目してください。私たちは単にプロキシクラスのメソッド(この例ではGetData)を呼び出すだけでよく、後はプロキシクラスが2つの日付値をシリアライズし、HTTP要求を行い、結果のXMLをADO.NET DataSetに変換するという低レベル作業のすべてを処理してくれます。
// Get data for 2009... WebReferenceProxy proxy = new WebReferenceProxy(); DataSet performances = proxy.GetData("1/1/2009", "12/31/2009");
GetDataメソッドの実行が終わると、Webサービス呼び出しが完了したことになり、Webサービスから取得されたデータを含むDataSetオブジェクトが返されます。この時点で、グリッドへの結果表示、結果のディスク保存、結果のソートなどを行うことができます。
しかし、顧客の考えは、自動生成されたプロキシクラスを使用せず、代わりにHttpWebRequestクラスを使用して直接的にWebサービス呼び出しを行い、Webサービスによって返されたXMLペイロードをXmlDocumentオブジェクトに入れる方が効率的ではないか、というものでした。この仮説をテストするために、それだけを行うSoapCallという名前の小さく軽量なクラスを作成しました。以下は、SoapCallクラスの関連のあるコード行を示したものです。
//Prepare objects and create Web Service parameters ASCIIEncoding encoding = new ASCIIEncoding(); StringBuilder parameters = new StringBuilder(); parameters.Append("sStartDate=1/1/2008&"); parameters.Append("sEndDate=1/1/2009&"); byte[] payload = encoding.GetBytes(parameters.ToString()); string Url = @"http://<WebServiceUrl>/GetPerformances"; //Call the Web Service System.Net.HttpWebRequest wr = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(Url); wr.Method = "POST"; wr.KeepAlive = false; wr.ContentType = "application/x-www-form-urlencoded"; wr.ContentLength = payload.Length; //Retrieve the response System.Net.HttpWebResponse webResponse; System.IO.Stream wrStream = wr.GetRequestStream(); wrStream.Write(payload, 0, payload.Length); wrStream.Close(); webResponse = (System.Net.HttpWebResponse)wr.GetResponse(); //Put the response stream in an XML document Stream baseStream = webResponse.GetResponseStream(); System.IO.StreamReader sr = new System.IO.StreamReader(baseStream); System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument(); xmlDoc.LoadXml(sr.ReadToEnd());
言うまでもなく、Webサービスを直接呼び出すには、プロキシクラスを使用する場合よりずっと多くのコードが必要です。それがプロキシクラスを使用する利点の1つです。プロキシクラスは、入力パラメータのパッケージ化、HTTP要求の発行、応答の構文解析といった処理を行うために必要なすべての低レベルコードをカプセル化しているため、コーディング時間の大幅な節約に貢献します。
上記の赤字でハイライトされた1つ目の行は、HttpWebRequestオブジェクトのGetResponseメソッドの呼び出しを示しています。このメソッドは、実際にHTTP要求を送信し、HTTP応答をStreamとして返します。ハイライトされた2つ目の行では、応答をXmlDocumentオブジェクトにロードしています。WebサービスのXML応答がXmlDocumentにロードされたら、それに対してデータの列挙、(XPathによる)フィルタリング、(XSLTによる)表示用HTMLへの変換など、さまざまな面白い処理を行えます。
テスト1:結果
自動生成プロキシクラスとSoapCallクラスを使用するコードを実行しました。100回の繰り返しで、1回の要求ごとに210KBのXMLペイロードにアクセスします。勝ったのは.NETの自動生成プロキシクラスでした。テスト結果は、自動生成プロキシクラスを使用する方が、SoapCallメソッドよりも約50%速いことを示しています。
パフォーマンスに差が出た1つの理由は、SoapCallクラス内でXmlDocumentオブジェクトを使用したことです。.NETのXPathDocumentクラスは、大きなXMLドキュメントの構文解析に対して、より効率的なアプローチを提供します。しかし、それを使用するには若干多くのコードが必要になります(特にXML名前空間を取り扱う場合)。要するに、これら2つのアプローチ間のパフォーマンスの差を縮めることは可能でしょうが、そうするとSoapCallクラス内のコードがかなり増えることになります。