連載

.NETで簡単XML

第14回 オブジェクトをXMLでシリアライズ(6)

株式会社ピーデー 川俣 晶
2004/02/18
Page1 Page2 Page3 Page4

XML Webサービス経由で使われるシリアライズの種類

 Visual Studio .NET(以下VS.NET)を使うと、XML Webサービスをいともたやすく作成することができる。しかし、整数や文字列だけをサーバとクライアントの間で受け渡しているうちはよいのだが、オブジェクトを受け渡そうとすると、いろいろと悩ましいことが出てくる。もちろん、オブジェクトを受け渡すことができないわけではない。ネットワークを経由して生のオブジェクトをそのまま渡すことができず、一度シリアライズされるところに、意図しないトラブルが紛れ込む悩ましい領域が生じるわけである。

 XML Webサービスについてはこの連載では大きく取り上げないが、クラスをシリアライズ可能にする方法については、連載の範囲である。実際に、どのようにオブジェクトがシリアライズされるか、サンプル・プログラムを書いて試してみよう。

 ここでは、シリアライズに関する前回の最初のサンプル・ソースのPersonクラスを、そのままXML WebサービスのWebメソッド(WebMethod属性を指定した、ネットワーク経由で呼び出されるメソッド)の戻り値として使ってみよう。

 VS.NETで「ASP.NET Webサービス」のプロジェクトを作成後、Personクラスの定義をソース内に追加してから、以下のコードをPersonクラス内に追加する。

<WebMethod()> _
Public Function GetPerson() As Person
  Dim person As Person = New Person
  person.Name = "山田太郎"
  person.Age = 17
  person.SetTemporaryID(DateTime.Now.ToString())
  Return person
End Function
サンプル・プログラム3:ASP.NET Webサービスに追加するソース・コード(VB.NET版C#版

 これを実行し、書き込んだメソッドを起動するためにXML Webサービスのテスト・ページ(.asmxファイル)で「GetPerson」をクリックし、そこに表示されるSOAPメッセージの下部分(応答の書式)を見てみよう。

XML Webサービスのテスト・ページ
GetPersonメソッドのSOAP要求の書式(SOAPメッセージの上の部分)と応答の書式(下の部分)を表示したところ。

 いま注目しているメッセージ部分を抜き出すと次のようになっている。

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetPersonResponse xmlns="http://tempuri.org/VBSample021/Service1">
      <GetPersonResult>
        <Age>int</Age>
        <Name>string</Name>
      </GetPersonResult>
    </GetPersonResponse>
  </soap:Body>
</soap:Envelope>
XML WebサービスのGetPersonメソッドの実行結果

 このGetPersonResult要素の内容部分が、Personクラスのオブジェクトをシリアライズした結果である。

 この結果を見て驚いた人がいるかもしれない。XML Webサービスといえば、SOAPが中核技術の1つとして使われている。そして、この実行例は、紛れもなくSOAPを通してオブジェクトをやりとりしているはずである。それなのに、この結果は、まるで、SoapFormatterクラスを使ったシリアライズではなく、XmlSerializerクラスを使ったシリアライズ結果に見える。すべてのフィールドがシリアライズされず、パブリックなメンバとプロパティがシリアライズされているところは、まさにXmlSerializerクラスを使ったシリアライズ結果そのものである。

 かなり分かりにくいことではあるが、実は、XML Webサービスによって受け渡されるオブジェクトは、XmlSerializerクラスを使ったシリアライズによって行われていて、SoapFormatterクラスを使ったシリアライズではないのである。SOAPを使って転送されているにもかかわらず、SoapFormatterクラスでシリアライズされてはいないのである。

 しかし、ここでもう1つの選択がある。何も指定しなければ、Webメソッドは、「リテラル・パラメータ書式指定スタイル」というものが使われるのだが、これとは別に、「エンコードされたパラメータ書式指定スタイル」というものがある。これを使っても結果は同じだろうか。

 これを試すには、以下の指定をソース・コード先頭に付け加える。

Imports System.Web.Services.Protocols
Imports System.Web.Services.Description
サンプル・プログラム4:XML Webサービスのソースの先頭に追加するコード(VB.NET版C#版

 そして、WebMethod属性の行に、もう1つSoapDocumentMethodAttribute属性を以下のように書き加える。

<WebMethod(), SoapDocumentMethodAttribute(Use:=SoapBindingUse.Encoded)> _
サンプル・プログラム5:SoapDocumentMethodAttribute属性を追加するコード(VB.NET版C#版

 これを同じ手順で実行して、「GetPerson」をクリックし、そこに表示されるSOAPメッセージの下部分(応答の書式)を見てみよう。

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://tempuri.org/VBSample021a/Service1" xmlns:types="http://tempuri.org/VBSample021a/Service1/encodedTypes" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <types:GetPersonResponse xsi:type="types:GetPersonResponse">
      <GetPersonResult href="#id1" />
    </types:GetPersonResponse>
    <types:Person id="id1" xsi:type="types:Person">
      <Age xsi:type="xsd:int">int</Age>
      <Name xsi:type="xsd:string">string</Name>
    </types:Person>
  </soap:Body>
</soap:Envelope>
エンコードされたパラメータ書式指定スタイルを使った場合の実行結果

 これを見て分かるとおり、かなりSOAPらしくなってきた。id属性やxsi:type属性による型指定が付加されているあたりは、確かにSOAPっぽい感じである。しかし、実際にシリアライズされた値を見ると、依然として、XmlSerializerクラスを使ったシリアライズと同じであることが分かる。もし、SoapFormatterクラスを使ったシリアライズであれば、すべてのフィールドがそのままシリアライズされるはずである。しかし、Age、Nameという順に2つだけ値がシリアライズされるのは、XmlSerializerクラスを使ったシリアライズと同じ結果である。

 一見SOAP形式でシリアライズされているように見えるにもかかわらず、SoapFormatterクラスを使用した場合とは異なる結果になるのはなぜだろうか。

 その秘密は、次で説明する。


 INDEX
  .NETで簡単XML
  第14回 オブジェクトをXMLでシリアライズ(6)
    1.ISerializableインターフェイスを用いたシリアライズ制御
    2.ISerializableインターフェイスを使ったクラスの継承
  3.XML Webサービス経由で使われるシリアライズの種類
    4.XmlSerializerを使ってSOAP形式でシリアライズする方法
 
インデックス・ページヘ  「連載 :.NETで簡単XML」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間