[RESOLVED] How to transmit a CLASS to another app (serialize?)
I've got this class
Code:
Public Class FSObject
Private _FileString As String
Public Property FileString As String
Get
Return _FileString
End Get
Set(ByVal value As String)
_FileString = value
End Set
End Property
Private _FileId As String
Public Property FileId As String
Get
Return _FileId
End Get
Set(ByVal value As String)
_FileId = value
End Set
End Property
Private _FileIndex As String
Public Property FileIndex As String
Get
Return _FileIndex
End Get
Set(ByVal value As String)
_FileIndex = value
End Set
End Property
And I just added this FILECONTENT property
Code:
Private _FileContent As Byte()
Public Property FileContent As Byte()
Get
Return _FileContent
End Get
Set(ByVal value As Byte())
ReDim _FileContent(value.Length)
_filecontent = value
End Set
End Property
End Class
Important thing to note is the FILECONTENT property - it will be a huge byte array of the file contents.
I create the object like this
Code:
For Each file As String In files
Dim MyThread As Thread ' simple new thread
Dim newFS As FSObject = New FSObject() 'new FSObject which is a file object I made up
' used because i needed to keep the name and index matched so the callback function had something to work with
newFS.FileString = file 'this is just the name of it
newFS.FileIndex = FileList.Count 'this is the objects position in the array, so the callback function knows where it is
Using fs As New FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read)
length = fs.Length
Dim buffer(length) As Byte
length = fs.Read(buffer, 0, length)
newFS.FileContent = buffer
End Using
FileList.Add(newFS) 'just adding NewFS to file List so work function knows about it and the draw function knows about it
MyThread = New Thread(AddressOf CallQuery) 'Standard Thread Stuff, Giving it the address of a function which is the function that calls the HTTPApp
MyThread.Start(newFS) 'And starting the thread. The newFS is an object the thread will pass to the called function - can only be one argument
Next
Now in the CALLQUERY function I used to just send the filename - now I want to send the entire class object - since it has the file contents - to the receiving app
Code:
Private Sub CallQuery(ByVal FSOb As FSObject)
Dim prefixes() As String = {"http://localhost:8080/HttpListener/"}
Dim request As WebRequest = WebRequest.Create(prefixes(0))
request.Method = "POST"
request.ContentType = "application/x-www-form-urlencoded"
Dim bytes() As Byte
Dim sendString As String = FSOb.FileString + "|" + FSOb.FileIndex
bytes = System.Text.Encoding.ASCII.GetBytes(sendString)
request.ContentLength = bytes.Length
Try
Dim outputstream As Stream = request.GetRequestStream()
outputstream.Write(bytes, 0, bytes.Length)
Dim response As WebResponse = request.GetResponse()
Dim datastream As Stream = response.GetResponseStream()
Dim reader As New StreamReader(datastream)
Dim responseFromServer As String = reader.ReadToEnd()
outputstream.Close()
reader.Close()
response.Close()
AnswerBack(responseFromServer) 'calling the callback function with the response from the server
'As far as i understand this calls the AnswerBack function with the InvokeRequired set true and nothing else fance or weird.
Catch ex As Exception
MessageBox.Show(ex.Message, "GetRequestStream")
End Try
End Sub
Instead of sending SENDSTRING - I would like to send the entire FSOb object.
Can I serialize this object and then make it materialize again in the receiving app??
Re: How to transmit a CLASS to another app (serialize?)
Sure you can :-)
here is a link which is a good intro:
http://vbnetsample.blogspot.com/2007...s-to-file.html
1 Attachment(s)
Re: How to transmit a CLASS to another app (serialize?)
Wow - that was going so well. I serialized the object - all looked good in the "sending" app.
And the receiving app got the data - but it's unhappy that it doesn't know about the "program that sent it"
I added the same CLASS to the receiving app (HttpApp.exe)
PicDragDrop.exe is the sending app. See the image below.
Re: How to transmit a CLASS to another app (serialize?)
That's not sufficient, and it won't work in this case as it stands. The problem is that there is more serialized into that thing than just the class information. The Assembly information is in there, and it can't be deserialized by any other assembly. Therefore, you would serialize with one program and find that you couldn't deserialize with another program.
I had this issue for some robot code because the brain was distributed as different programs on different computers. The messages flying (via UDP) between the different apps that made up the brain contained some complicated data. Therefore, I wanted to be able to transmit serialized classes, but I couldn't do it because what was serialized from one brain app couldn't be deserialized by a different part of the brain.
The solution was to build a class library that contains the serialization and deserialization code, along with the classes that I wanted to send. Then any app could reference this dll and do whatever serialization and deserialization was needed, because it was the dll assemblage information that was being included into the serialization package. Of course, having all the classes declared in the same class library was just a convenience for that situation, because all brain apps would need to know about those types so that they could deal with the data. The same might be true for you, or you might find some other arrangement of definitions in class libraries that will work, but you can't simply serialize in one app and deserialize in a different one because of the assemblage information contained in the serialized bytes.
EDIT: Crossed up your post, but this still answers the question fairly well.
Re: How to transmit a CLASS to another app (serialize?)
[edit] I see we cross posted - were you suggesting this wasn't going to work even before I got the exact error you described??? [/edit]
Ok - so I would need to partition this stuff into a class in and of itself - with the code to do the serialization and deserialization within that class - returning the FSOb object out to main code? And taking the streams (either file or request.inputstream) as properties to work on?
And then make that a dll and have both app's reference it?
Seems simple enough - but before I go hog wild here.
Is the serialization adding a lot of BYTES to the size of this transmission? I could certainly transmit two POST's to the receiving app - one with the filename as TEXT and one with the FILECONTENTS as a stream.
Am I going overboard for no good reason here?
Re: How to transmit a CLASS to another app (serialize?)
Yeah, I think that would be going overboard. I forget the exact size of that extra stuff, but I did go look at it when I was working on that robot code. There isn't much there. I was concerned because UDP packets have to be fairly small, and I was afraid that some of my classes were getting too large, so I looked at the packets byte by byte prior to deserialization. While I forget the size of that extra stuff, I seem to remember that it was a matter of one or two dozen bytes, or so. Trivial, in any case.
EDIT: Oh, and I should add that my last post was written without seeing the post where you got that exact error.
Re: How to transmit a CLASS to another app (serialize?)
@shaggy_hiker - just to clarify you think IT IS A GOOD IDEA to serialize this CLASS for transmission as opposed to doing a double POST of filename and then file contents??
Re: How to transmit a CLASS to another app (serialize?)
The addition of those few bytes is trivial. Whether it is a good idea in your case, I can't quite say. The serialization in a dll technique works, and the total size may well be lower than what you would get with two posts. Of course, it does mean creating a dll and referencing it on both sides. Therefore, it is a transmission technique that requires shared knowledge between the two apps (the contents of the dll is available to both, so you can't very well change one without changing the other). If that is a price you are willing to pay, then the size of the serialized packet will probably be smaller and the serialization/deserialization faster, than any alternative.
Re: How to transmit a CLASS to another app (serialize?)
Thank you so much - this has worked out perfectly.
Created this as a class library project - my original class for holding the data
Code:
<System.Serializable()> _
Public Class FSObject
' Empty constructor required for serialization.
Public Sub New()
End Sub
Private _FileString As String
Public Property FileString As String
Get
Return _FileString
End Get
Set(ByVal value As String)
_FileString = value
End Set
End Property
Private _FileId As String
Public Property FileId As String
Get
Return _FileId
End Get
Set(ByVal value As String)
_FileId = value
End Set
End Property
Private _FileIndex As String
Public Property FileIndex As String
Get
Return _FileIndex
End Get
Set(ByVal value As String)
_FileIndex = value
End Set
End Property
Private _FileContent As Byte()
Public Property FileContent As Byte()
Get
Return _FileContent
End Get
Set(ByVal value As Byte())
ReDim _FileContent(value.Length)
_FileContent = value
End Set
End Property
End Class
And a new class within the class library to do the serialization/deserialization
Code:
Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary
Public Class Class2
Public Sub Serialize(ByRef FSOb As FSObject, ByRef ms As MemoryStream)
Dim bf As New BinaryFormatter()
bf.Serialize(ms, FSOb)
End Sub
Public Sub Deserialize(ByRef FSOb As FSObject, ByRef st As Stream)
Dim bf As New BinaryFormatter()
FSOb = bf.Deserialize(st)
End Sub
End Class
Compile that into a DLL and referenced it in both the SENDING and RECEIVING apps
The sending app CallQuery function now looks like this
Code:
Private Sub CallQuery(ByVal FSOb As FSObject)
Dim prefixes() As String = {"http://localhost:8080/HttpListener/"}
Dim request As WebRequest = WebRequest.Create(prefixes(0))
request.Method = "POST"
request.ContentType = "application/x-www-form-urlencoded"
Dim ms As New MemoryStream()
Dim cl2 As New Class2
cl2.Serialize(FSOb, ms)
request.ContentLength = ms.Length
Try
Dim outputstream As Stream = request.GetRequestStream()
'outputstream.Write(bytes, 0, bytes.Length)
outputstream.Write(ms.ToArray, 0, ms.Length)
Dim response As WebResponse = request.GetResponse()
Dim datastream As Stream = response.GetResponseStream()
Dim reader As New StreamReader(datastream)
Dim responseFromServer As String = reader.ReadToEnd()
outputstream.Close()
reader.Close()
response.Close()
AnswerBack(responseFromServer) 'calling the callback function with the response from the server
'As far as i understand this calls the AnswerBack function with the InvokeRequired set true and nothing else fance or weird.
Catch ex As Exception
MessageBox.Show(ex.Message, "GetRequestStream")
End Try
End Sub
And the receiving app does this to get the data back out
Code:
Private Sub GetContextCallBack(ByVal result As IAsyncResult)
'Dim listener As HttpListener = CType(result.AsyncState, HttpListener)
m_asyncCount += 1
Dim acHold As Integer = m_asyncCount
Console.WriteLine("In Callback with " & m_asyncCount.ToString & "...")
If m_listener.IsListening Then
Dim context As HttpListenerContext = m_listener.EndGetContext(result)
m_listener.BeginGetContext(New AsyncCallback(AddressOf GetContextCallBack), Nothing)
Dim request As HttpListenerRequest = context.Request
Dim response As HttpListenerResponse = Nothing
Try
Dim requestContext = ""
Dim returnString = ""
Dim blnPost As Boolean = False
If context.Request.HttpMethod = "POST" Then
blnPost = True
Dim inputstream As Stream = context.Request.InputStream()
Dim cl2 As New Class2
Dim FSOb As New FSObject
cl2.Deserialize(FSOb, inputstream)
'returnString = Mid(requestContext, InStr(requestContext, "|") + 1)
returnString = FSOb.FileIndex.ToString
Using fs As New FileStream("D:\ACS Desktop\Doc Management\testcopy.doc", FileMode.Create, FileAccess.ReadWrite, FileShare.None)
fs.Write(FSOb.FileContent, 0, FSOb.FileContent.Length)
End Using
I even created a TESTCOPY.DOC file with the STREAM to make sure I could open the document in WORD - worked exactly as I hoped.
I can't even believe that I just sent a WORD document - serialized with a bunch of metadata - through an HTTP post and re-created it as a WORD document on the receiving side!
It's like I just built a Star Trek transporter!
This forum is GREAT!!!!