- PR -

Webサービスのパラメータについて

投稿者投稿内容
まゆりん
ぬし
会議室デビュー日: 2002/08/12
投稿数: 539
お住まい・勤務地: よこはま
投稿日時: 2003-01-08 17:12
Jittaさん、お忙しいところお付き合い頂き有難うございました。
結局WebアプリでXMLファイルを作成し、それをWebサービス側で取得する
という形で進めることに致しました。

あともう少しで出来そうなので、その際はこちらに載せますね♪
まゆりん
ぬし
会議室デビュー日: 2002/08/12
投稿数: 539
お住まい・勤務地: よこはま
投稿日時: 2003-01-20 15:27
こんにちは、まゆりんです。

遅くなりましたが、なんとかXMLファイルでオブジェクトの受け渡しが出来ました。
(結構前に出来ていたのですが、忙しかったので・・・今更で申し訳ないです・・・)

【変数】FileName 【クラス】SampleClass
宣言部は省略しています。

コード:
Web Application--------------------------------------------


If File.Exists(FileName) = False Then
''オブジェクト情報をXMLシリアル化して保存
objSerial = New XmlSerializer(GetType(SampleClass))
XmlWriter = New StreamWriter(FileName)
objSerial.Serialize(XmlWriter, SampleClass)
XmlWriter.Close()
End If


Web Service------------------------------------------------

''XMLファイルを取得する。
objSerial = New XmlSerializer(GetType(SampleClass))
GetStream = New FileStream(FileName, FileMode.Open)
Reader = New StreamReader(GetStream)
''サービス側のオブジェクトに格納
objSample = CType(objSerial.Deserialize(Reader), SampleClass)
rootSt = UBound(objStep.opSho_stepno)

If File.Exists(FileName) Then
''ファイルを削除
Reader.Close()
File.Delete(FileName)
End If



※オブジェクト情報を受け取った後、ファイルを削除しています。

ただし、渡す側のクラス名と受ける側のクラス名が同じでないと
エラーが発生してしまうようです。(上記の場合はSampleClass)
もちろん、内容も一緒でないと受け取る際にエラーになります。

あとは、ファイル操作を行っていますのでアクセス権限に注意することですね。
特に例外の処理とか・・・。

何かのお役に立って頂ければ幸いです。


#今頃になってCODEタグのミスを発見・・・。

[ メッセージ編集済み 編集者: まゆりん 編集日時 2005-01-22 01:23 ]
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2003-02-18 09:23
古いのを引っ張り出してきます。

 時間ができたので、お勉強をかねてじっくり拝見させて頂きました。また、VS.NETのヘルプの方とも格闘(←この言葉がピッタリだと思ってしまう)しました。そこで気がつきました。なんと、XMLシリアル化では、Privateなプロパティはアウトプットされないというのです!!
MSDNライブラリ「.NET開発→.NET Framework→.NET Frameworkを使用したプログラミング→オブジェクトのシリアル化→XMLシリアル化およびSOAPシリアル化」
引用:

XML シリアル化によって、パブリック プロパティおよびパブリック フィールドを含むクラスの型が厳密に指定され、それらのパブリック メンバは格納または転送できるようにシリアル形式 (この場合は XML) に変換されます。



 私がやりたいことは、そしておそらくまゆりんさんのされたいことも、クラスが持っている全ての情報を(つまり「クラス」として)Webサービスに転送することですが、XMLシリアル化では無理…なのかなぁ?
 そこで、もう一つのシリアル化である、バイナリシリアル化を見てみたのですが、こちらでは型情報をそのまま転送し、再構成することができるということです。参照も、シリアライザが解決してくれるそうです。
MSDNライブラリ「.NET開発→.NET Framework→.NET Frameworkを使用したプログラミング→オブジェクトのシリアル化→バイナリシリアル化→シリアル化の概念→永続ストレージ」
引用:

オブジェクトがシリアル化されるときは、クラスの名前、アセンブリ、およびそのクラス インスタンスのすべてのデータ メンバがストレージに書き込まれます。オブジェクトのメンバ変数には、ほかのインスタンスへの参照が格納されていることがよくあります。クラスがシリアル化されるときは、シリアル化エンジンは既にシリアル化されているすべての参照先オブジェクトを追跡し、同じオブジェクトが複数回シリアル化されないようにします。


これは「バイナリ」なのですが、XMLはテキストであり、テキストも一種のバイナリですよね。ということで、テキストとしてシリアル化するSoapFomatterというものがありました。これを使えば、元の情報がそのまま復元できそうです。サンプルではPrivateメンバがシリアル化されています。
べーちゃん
大ベテラン
会議室デビュー日: 2002/07/21
投稿数: 121
投稿日時: 2003-02-22 04:36
昨日あったマイクロソフトのディベロッパーズカンファレンスで扱われていた
WebServiceのサンプルを見ていて思ったのですがDataSetを使った受け渡しは
どうなんでしょうか。
クライアントはVB.NETでサービス側はC#で書いています

クライアント側コード(VB.NET)

Dim ds As New DataSet()
Dim cSvcTest As localhost.WebSvc01 = Application("WebSvc01")

ds.Tables.Add()
Dim dcCode As New System.Data.DataColumn("MyCode")
dcCode.DataType = System.Type.GetType("System.Int32")
ds.Tables(0).Columns.Add(dcCode)
Dim dcName As New System.Data.DataColumn("MyName")
dcName.DataType = System.Type.GetType("System.String")
ds.Tables(0).Columns.Add(dcName)
Dim dcOther As New System.Data.DataColumn("MyOther")
dcOther.DataType = System.Type.GetType("System.Decimal")
ds.Tables(0).Columns.Add(dcOther)
Dim dr(2) As Object
dr(0) = 123
dr(1) = "TestX"
dr(2) = 9876.54
ds.Tables(0).Rows.Add(dr)

TextBox1.Text = cSvcTest.PutDataSet(ds)

Webサーバー側(C#)
[WebMethod]
public string PutDataSet(DataSet ds)
{
string filename = "myXmlDoc.xml";
// Create the FileStream to write with.
System.IO.FileStream myFileStream = new System.IO.FileStream
(filename, System.IO.FileMode.Create);
// Create an XmlTextWriter with the fileStream.
System.Xml.XmlTextWriter myXmlWriter =
new System.Xml.XmlTextWriter(myFileStream, System.Text.Encoding.Unicode);
// Write to the file with the WriteXml method.
ds.WriteXml(myXmlWriter);
myXmlWriter.Close();

return "PutDataSet";
}

一応XMLファイルに保存されている内容を見たところ正しくわたっているのを
確認しています。


[ メッセージ編集済み 編集者: べーちゃん 編集日時 2003-02-22 04:40 ]

[ メッセージ編集済み 編集者: べーちゃん 編集日時 2003-02-22 04:40 ]
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2003-02-24 09:13
こんにちは。

>>WebServiceのサンプルを見ていて思ったのですがDataSetを使った受け渡しは
>>どうなんでしょうか。

 もう少し調べてからポストしようと思っていたのですが、GAC(かな?)に登録されているクラスについては、関数の引数に指定できるようです。

 例えば、1つのソリューションにサービス、アプリ、クラスライブラリのプロジェクトを作ります。クラスライブラリを他の2つのプロジェクトで参照します。これでクラスライブラリのクラスを引数に指定できるかというと、そうではないのです。アプリ側では、「サービス(が提供する)クラス」と指定しなければなりません。おそらく、サービスがデータを提供する相手は「不特定多数」なので、いくらクラスを通知しても相手がクラスを知らなければ再生できないから、なのでしょう。この辺で、私は考え違いをしていたようです。

 DataSetはMSが提供するクラスのなので、相手に.NET Frameworkがインストールされていれば、相手もクラスを知っているはず、です。このためにDataSetを引数として受け渡しができます。また、DataSetで通常アクセスするものは全てパブリックなプロパティです。パブリックなのでXMLシリアル化でXMLとしてはき出されます。XMLはテキストなので、XMLとする以上、誰にでも読めてしまいます。プライベート、すなわち隠しておきたいモノをテキスト化するのは、セキュリティの問題となるでしょう。ここも、思い違いをしていたようです。


 ちょっと時間的な都合で止まっているのですが、バイナリシリアル化で、プライベートメンバも含めてXML化できます。ヘルプの例ではファイルに落としていますが、メモリストリームを使えばファイルを経由せずにStringにできそうです。引数をStringにすることで、クラスそのものを引き渡すことができそうです。
まゆりん
ぬし
会議室デビュー日: 2002/08/12
投稿数: 539
お住まい・勤務地: よこはま
投稿日時: 2003-03-19 16:21
すみません・・・古いものを引っ張ってきました。

引用:

Jittaさんの書き込み (2003-02-24 09:13) より:

 ちょっと時間的な都合で止まっているのですが、バイナリシリアル化で、プライベートメンバも含めてXML化できます。ヘルプの例ではファイルに落としていますが、メモリストリームを使えばファイルを経由せずにStringにできそうです。引数をStringにすることで、クラスそのものを引き渡すことができそうです。



こ、これは・・・願ってもない方法ですね!
早速試してみたい所ですが・・・現在運用中でプログラムに
全く触れられない状態なので当分先になりそうです(汗)。

お忙しい中色々と調べて(もとい、格闘して)頂き有難うございました。
私も時間に余裕が出来たら格闘してみたいと思います。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2003-05-22 18:29
これでやっと終われそう。

引用:

Jittaさんの書き込み (2003-02-24 09:13) より:
 DataSetはMSが提供するクラスのなので、相手に.NET Frameworkがインストールされていれば、相手もクラスを知っているはず、です。このためにDataSetを引数として受け渡しができます。


 DataSetがシリアル化できるクラスだから、なんだろうな、きっと。だとすると、Serializableなら直接送れるかも・・・でも、せっかく書いたのでポストする。


 長いこと放っていた宿題です。クラスのシリアル化がだいぶんわかってきたので報告します。

 シリアル化には、バイナリシリアル化と、XMLシリアル化の2つがあります。XMLシリアル化では、クラスのパブリックなプロパティだけが出力されます。対して、バイナリシリアル化ではクラスの全てのプロパティが出力されます。バイナリシリアル化を使用すれば、オブジェクトをアプリケーションの外部に転送することが可能になります。たとえば、Formをバイナリシリアル化して保存し、アプリケーションを終了すれば、後から(通信していたなど、特殊な場合を除いて)状況をそのまま再現することも可能、ということです。
 今回調べ始めた目的は、「Webサービスに対し、クラスのオブジェクトを渡すこと」です。


 結局、シリアル化は、シリアル化したいクラスに<Serialize>属性を付けるだけで可能でした。

Imports System.Runtime.Serialization
<Serialize()> Public Class SerializableClass
(略)
End Class


使い方は、

Imports System.Runtime.Serialization.Formatters
' シリアライズ
Sub Output(ByRef FileName As String, ByRef obj As SerializableClass)
Dim fs As New FileStream(FileName, FileMode.Create)
Dim formatter As New Binary.BinaryFormatter()
' ここで、FormatterをSoap.SoapFormatterにすれば、XMLファイルになる
formatter.Serialize(fs, obj)
fs.Close()
End Sub

' デシリアライズ
Function Input(ByRef FileName As String) As SerializableClass
fs = New FileStream(FileName, FileMode.Open)
formatter = New BinaryFormatter()
' SoapFomatterで出力したら、ここはSoapFormatterにする
Input = CType(formatter.Deserialize(fs), SerializableClass)
fs.Close()
End Function


難しいことをする割に、使い方は簡単。これだけで、全てのメンバの全ての参照をたどってシリアル化します。

 ところが、この方法でシリアル化すると、クラスの中身を変更できません。クラスの構造とファイルから再現されるクラスの構造に不一致があると、例外が発生します。そこで登場するのがISerializableインターフェースです。これでシリアル化の手順を指定します。

Imports System.Runtime.Serialization
<Serialize()> Public Class SerializableClass
Implements ISerializable

Protected Sub New(ByVal info As SerializationInfo, _
ByVal context As StreamingContext)
' このコンストラクタは、クラスがSealされていない限りProtected
' プロパティ = info.Get?("名前")
' 継承したクラスの場合、必ず親クラスのコンストラクタを呼ぶ
End Sub

Public Sub GetObjectData(ByVal info As SerializationInfo, _
ByVal context As StreamingContext) _
Implements ISerializable.GetObjectData
' このメソッドはPublic
' シリアル化のときに使われる
' info.AddValue("名前", プロパティ, 型)
End Sub
(略)
End Class

 詳細はSerializationInfoのヘルプを見て頂くとして、AddValueというメソッドを使い、シリアル化したいプロパティをinfoに追加していきます。デシリアライズは反対に、Get?というメソッドを使い、プロパティに値を取り出します。このとき、必要ならNothingをチェックして、デフォルト値を放り込んでやるなどの処理が入ります。


 次に、当初の目的である、XMLシリアル化した文字列として取り出して、またオブジェクトに戻す方法です。MemoryStreamという、おあつらえ向きのクラスがあります。メモリであろうがファイルであろうが、ストリームという意味なら同じはずなのです。

#ただし、このコードは動作させていません!
#暗号化で同じようなロジックを使っているので、動くはず

Function OutputToString(ByRef Obj As SerializableClass)
Dim strm As New MemoryStream()
Dim formatter As New Soap.SoapFormatter()
formatter.Serialize(strm, Obj)
strm.Flush()
strm.Seek(0, SeekOrigin.Begin)
Dim reader As New StreamReader(strm)
OutputToString = reader.ReadToEnd()
reader.Close()
strm.Close()
End Function

Function InputFromString(ByRef StreamString As String) As SerializableClass
Dim strm As New MemoryStream(System.Text.ASCIIEncoding.ASCII.GetBytes(StreamString))
Dim formatter As New Soap.SoapFormatter()
InputFromString = CType(formatter.Deserialize(strm), SerializableClass)
strm.Close()
End Function


(おまけ)
 Soapシリアル化をすると、プライベートであったはずのプロパティも見えてしまいますから、「そいつはセキュリティ上まずい」ということであれば、暗号化してしまいます。DES_KEYとDES_IVは、必ず8バイトです。

#このコードは動作させています

Imports System.Xml.Serialization
Imports System.Text.ASCIIEncoding
Imports System.Security.Cryptography

<XmlIgnore()> Private Shared ReadOnly DES_KEY() As Byte = {8バイト}
<XmlIgnore()> Private Shared ReadOnly DES_IV() As Byte = {8バイト}

Public Shared Function Crypto(ByVal PlaneString As String) As String
Dim plane() As Byte = ASCII.GetBytes(PlaneString)
Dim mem As New MemoryStream()
Dim des As New DESCryptoServiceProvider()

des.Padding = PaddingMode.PKCS7

Dim transformer As ICryptoTransform = des.CreateEncryptor(DES_KEY, DES_IV)
Dim strm As New CryptoStream(mem, transformer, CryptoStreamMode.Write)

strm.Write(plane, 0, plane.Length)
strm.FlushFinalBlock()
strm.Flush()
mem.Seek(0, SeekOrigin.Begin)
Crypto = Convert.ToBase64String(mem.ToArray())
strm.Close()
mem.Close()
End Function

Public Shared Function Decrypto(ByVal CryptedString As String) As String
Dim crypted() As Byte = Convert.FromBase64String(CryptedString)
Dim mem As New MemoryStream()
Dim des As New DESCryptoServiceProvider()

des.Padding = PaddingMode.PKCS7

Dim transformer As ICryptoTransform = des.CreateDecryptor(DES_KEY, DES_IV)
Dim crypto As New CryptoStream(mem, transformer, CryptoStreamMode.Write)

crypto.Write(crypted, 0, crypted.Length)
crypto.FlushFinalBlock()
crypto.Flush()
mem.Seek(0, SeekOrigin.Begin)

Dim plane() As Byte = mem.ToArray()

crypto.Close()
mem.Close()

Return ASCII.GetString(plane, 0, plane.Length)
End Function
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2005-01-21 22:39
 え〜またまた古いものを持ち上げてきました。
 Webサービスの戻り値に独自クラスを…という質問がGDNJにあり、このスレッドを紹介したところ、XMLシリアライズして別のクラスに作成し直すという方法を思いつかれた、ということです。それを見て青柳さんが、そんなことしなくてもいい方法を思いつかれました。

ということでリンク張っておきます。→GDNJ
張り替えた

[ メッセージ編集済み 編集者: Jitta 編集日時 2007-06-22 20:35 ]

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