- PR -

XML WebService でのデータ圧縮で困ってます

投稿者投稿内容
ドルビー
常連さん
会議室デビュー日: 2006/07/11
投稿数: 21
投稿日時: 2007-02-22 09:21
masa さん、いろいろアドバイスありがとうございます。

masa さんのおっしゃる形でコーディングしてみました。
一時的に MemoryStream を作って、そこに圧縮された内容が書かれていく、
という形です。
そして、その MemoryStream を、ChainStream()メソッドで引数で渡された
ストリームに出力するようにしました。

しかし、サーバ側のデシリアライズのステップで不具合が生じているらしく、
SOAP Toolkit でモニタリングをしてみると、以下の例外がスローされていることが
判明しました。これを見てみると、XmlTextReaderでXmlを読み込もうとしている、
ということは伺えますが、SoapExtension の継承クラスが実行される形跡はありません。
(そこがおかしい?)

ちなみに、SoapVersion は SoapVersion12 を指定しています。


<以下、例外の内容>
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<soap:Fault>
<soap:Code>
<soap:Value>soap:Receiver</soap:Value>
</soap:Code>
<soap:Reason>
<soap:Text xml:lang="ja">System.Web.Services.Protocols.SoapException: サーバーは要求を処理できませんでした。 --->
  System.Xml.XmlException: 指定されたエンコードに無効な文字があります。
  行 1、位置 1 です。
  場所 System.Xml.XmlTextReaderImpl.Throw(Exception e)
  場所 System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
  場所 System.Xml.XmlTextReaderImpl.InvalidCharRecovery(Int32& bytesCount, Int32& charsCount)
  場所 System.Xml.XmlTextReaderImpl.GetChars(Int32 maxCharsCount)
  場所 System.Xml.XmlTextReaderImpl.ReadData()
  場所 System.Xml.XmlTextReaderImpl.SwitchEncoding(Encoding newEncoding)
  場所 System.Xml.XmlTextReaderImpl.ParseXmlDeclaration(Boolean isTextDecl)
  場所 System.Xml.XmlTextReaderImpl.Read()
  場所 System.Xml.XmlTextReader.Read()
  場所 System.Web.Services.Protocols.SoapServerProtocol.SoapEnvelopeReader.Read()
  場所 System.Xml.XmlReader.MoveToContent()
  場所 System.Web.Services.Protocols.SoapServerProtocol.SoapEnvelopeReader.MoveToContent()
  場所 System.Web.Services.Protocols.SoapServerProtocolHelper.GetRequestElement()
  場所 System.Web.Services.Protocols.Soap12ServerProtocolHelper.RouteRequest()
  場所 System.Web.Services.Protocols.SoapServerProtocol.RouteRequest(SoapServerMessage message)
  場所 System.Web.Services.Protocols.SoapServerProtocol.Initialize()
  場所 System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing)
  --- 内部例外スタック トレースの終わり ---</soap:Text></soap:Reason><soap:Detail /></soap:Fault></soap:Body></soap:Envelope>
masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 2007-02-23 09:28
引用:

masaさんの書き込み (2007-02-21 19:17) より:

http://www.ogis-ri.co.jp/otc/hiroba/technical/AxisDotNet/index.html

このページと同じようなことをしようとしているわけですよね?
(この例では相手がJavaですが)




ChainStream のシグネチャが .NET Remoting でのストリーム操作の部分と似ていたものですから直感で ChainStream というメソッドを挙げてしまいました。
XML WebService 自体は経験がないものですから、かえって混乱させてしまっているかもしれません。

このサイトで紹介されている CompressSoapExtension クラスを見ると ProcessMessage でメッセージに対して圧縮展開処理を行うことは間違っていないのではないかと思えます。

.NET Remoting では、SoapExtension に対応するのは ChannelSink ではないかと思われるのですが、私は圧縮処理を行うシンクはクライアント・サーバー側で同じものを使用しています。ですから圧縮処理と展開処理が結果的に対になっています。
SoapExtension の場合は、クライアント・サーバー側別々の実装となるのでしょうか?
masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 2007-02-23 09:43
引用:

masaさんの書き込み (2007-02-23 09:28) より:

.NET Remoting では、SoapExtension に対応するのは ChannelSink ではないかと思われるのですが、私は圧縮処理を行うシンクはクライアント・サーバー側で同じものを使用しています。ですから圧縮処理と展開処理が結果的に対になっています。




厳密に言うと「圧縮・展開を行うクラスが同じもの」でした。
圧縮・展開は次のメソッドで行っています。
引数にはネットワークストリームが送られてきます。
ChannelSink では "レスポンスヘッダー" のようなディクショナリを使って、
圧縮を行うかどうか・行われているかどうかを判定し、
必要であればこれらのメソッドを呼び出しています。
このあたりは .NET Remoting 固有の考え方も強いと思います。

単純にメッセージの圧縮・展開をするだけならこれでできるかもしれません。
何かの参考になれば。。

 /// <summary>
 /// 圧縮処理のバッファサイズ
 /// </summary>
 internal readonly static int CompressBufferSize = 1000;

 /// <summary>
 /// 指定されたデータストリームを格納した圧縮ストリームを取得します。
 /// </summary>
 /// <param name="inStream">データストリーム</param>
 /// <returns>圧縮ストリーム</returns>
 public Stream GetCompressedStream( Stream inStream ) {

  Stream outStream = new System.IO.MemoryStream();

  // クローズしてもデータストリームは開いたまま
  using ( System.IO.Compression.DeflateStream compressStream = new System.IO.Compression.DeflateStream( outStream, System.IO.Compression.CompressionMode.Compress, true ) ) {

  byte[] buf = new Byte[CompressBufferSize];

  int cnt = inStream.Read( buf, 0, CompressBufferSize );

  while ( cnt > 0 ) {
   compressStream.Write( buf, 0, cnt );
   cnt = inStream.Read( buf, 0, CompressBufferSize );
  }

  compressStream.Flush();

  // クローズしないとデータストリームの解析に失敗する
  compressStream.Close();

  }

  return outStream;

 }

 /// <summary>
 /// 指定された圧縮データストリームを格納した圧縮解除ストリームを取得します。
 /// </summary>
 /// <param name="inStream">圧縮データストリーム</param>
 /// <returns>圧縮解除ストリーム</returns>
 public Stream GetDecompressedStream( Stream inStream ) {

  // クローズしたときにデータストリームも閉じる
  Stream outStream = new System.IO.Compression.DeflateStream( inStream, System.IO.Compression.CompressionMode.Decompress, false );

  return outStream;

 }
ドルビー
常連さん
会議室デビュー日: 2006/07/11
投稿数: 21
投稿日時: 2007-02-25 18:29
masa さん、返事が遅れました。

いろいろアドバイスありがとうございました。
圧縮の方法に付いては、ご教授いただいた内容と
殆ど同じなのですが、SOAP 1.2 という規格なんですが、
SOAP 1.1 という規格から大きく変更されているようで、
そのへんを調査していたのですが、結論は得られず…。

そもそも XML 形式のデータ全体を圧縮する、ということは
SOAP という規格から逸脱してしまう、ということが
わかりました。

しかしながら、通信内容を減らすためにも、
やはり圧縮というのは必要不可欠と思いますが、
IISのHTTP圧縮機能を使う意外に、
.NET Framework 2.0 だけで圧縮を制御する事、
というのは、技術的にも可能なのかどうか、
という結論に達しました。
なかなかサンプルもなく、困っていますが、
ご教授のほど、宜しくお願いします。

今、通信内容の圧縮や暗号化をする、
もしくはバイナリデータを添付する、
というのを実現したいのですが、
情報が乏しく頓挫しかけています。
rvmx
大ベテラン
会議室デビュー日: 2002/09/26
投稿数: 184
お住まい・勤務地: 愛媛県
投稿日時: 2007-02-25 20:25
今日は

やられようとしている事がいまいち分かりませんが、
SOAP全体の圧縮とは?、圧縮してもSOAPエンベロップの形式を維持している必要が有ります。
データを普通にバイナリ配列で受け渡し、必要ならそれに対して圧縮・解凍すれば何も問題ないと思います、普通によく使っていますが。
ドルビー
常連さん
会議室デビュー日: 2006/07/11
投稿数: 21
投稿日時: 2007-02-26 08:27
rvmx さん、回答ありがとうございます。

SOAP全体の圧縮なんですけど、ChainStream でストリームが入ってきますが、
そこで取得したストリームを GZipStream を使って圧縮をする、ということです。
そうしてしまいますと、SOAPエンベロップの内容までもが圧縮されてしまい、
XML 形式とは異なります。

rvmx さんのおっしゃる、「バイナリ配列で受け渡し」ということですが、
WebService の引数、復帰値を全て byte[] で行なう、ということでしょうか?
普通に行なわれているとのことですが、どこか参考にできるサイトなど、
ございますでしょうか?

やりたいこととしては、SOAP メッセージの圧縮と暗号化、およびバイナリデータの添付です。
rvmx
大ベテラン
会議室デビュー日: 2002/09/26
投稿数: 184
お住まい・勤務地: 愛媛県
投稿日時: 2007-02-26 13:04
今日は

WebService の引数、復帰値のうち必要なもののみbyte[]で受け渡ししています。
byte[]を圧縮と暗号化すれば良いと思います。
現在出張先の為、詳しくは覚えていませんが。

masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 2007-02-27 13:05
CodeProject を見ていたらこんな記事がありました。
デモソースを見たりはしていませんが、やろうとしていることは似ていませんか?

Adding a zip filter to web services

http://www.codeproject.com/cs/webservices/WebServiceZipFilter.asp

スキルアップ/キャリアアップ(JOB@IT)