Remoting Server Object not passing properties

  • Thread starter Thread starter Denny
  • Start date Start date
D

Denny

I have noticed this weird behavior and wondered if anyone else has seen this or knows a solution. I have this class that inherits from NameObjectCollectionBase that has one public property (name):



Private _name As String

Public Property Name() As String

Get

Return _name

End Get

Set(ByVal value As String)

_name = value

End Set

End Property

Public Sub New()



End Sub

Protected Sub New(ByVal info As System.Runtime.Serialization.SerializationInfo, ByVal context As System.Runtime.Serialization.StreamingContext)

MyBase.New(info, context)

End Sub



The server object creates, sets the name property and returns it



From the server:



Inherits MarshalByRefObject

Implements IEmployee.IEmployee



Public Function GetEmployee() As Employee.Employee Implements IEmployee.IEmployee.GetEmployee

Dim TestEmployee As New Employee.Employee

TestEmployee.Name = "Harry"

Return TestEmployee

End Function



From the client:



ServerEmployee = DirectCast(Activator.GetObject(GetType(IEmployee.IEmployee), URL.ToString), IEmployee.IEmployee)



Dim Employee As New Employee.Employee

Employee = ServerEmployee.GetEmployee



The problem is when the client recieves the object, its name property = "". I have double checked this and when the object is created on the server, the property is set. I have tried it with other collections and it works as expected, the problem seems to be any classes that derive from Collections.Specialized namespace. All of the base properties retain settings. Only properties in the inherited class seem not to retain their settings.



Does anyone see something I am missing?



Thanks.
 
Hi Denny,

Welcome to the MSDN newsgroup.

From your description, I understand you have developed a custom class which
derives from "NameObjectCollectionBase" class. The class also has a custom
string property named "Name". In your .net remoting application, you use a
server object to return an instance of this custom class to client-side.
However, you found that the returned custom class instance always have
empty "Name" value, correct?

Based on the code snippet you provided, I've also done some tests by
creating a simple custom class inheriting from NameObjectCollectionBase and
I did encounter the problem you mentioned. After doing some further
research, I found that the problem is caused by the base class
"NameObjectCollectionBase". Since "NameObjectCollectionBase" class has
implemented the "ISerializable" interface, when the .net runtime
serializing the custom class instance, it will call the "GetObjectData"
method of the "NameObjectCollectionBase" class. However,
"NameObjectCollectionBase" class's "GetObjectData" method only save its
own properties, so our sub class's property values are lost. To resolve
this problem, we need to explicitly override the
"ISerializable.GetObjectData" method to store our own class's property(if
you want to persist it). In addition, we also need to retrieve the data
back from the SerializationInfo collection in the deserialization
constructor, Below is a simple test class I made, you can refer to it on
the two methods:

==========================
<Serializable()> Public Class EmployeeBase
Inherits NameObjectCollectionBase

Private _de As New DictionaryEntry

Private _name As String


Public Sub New()
End Sub

Public Sub New(ByVal d As IDictionary, ByVal bReadOnly As [Boolean])
Dim de As DictionaryEntry
For Each de In d
Me.BaseAdd(CType(de.Key, [String]), de.Value)
Next de
Me.IsReadOnly = bReadOnly
End Sub 'New


Protected Sub New(ByVal info As SerializationInfo, ByVal context As
StreamingContext)
MyBase.New(info, context)

Dim name As String

name = info.GetValue("EmployeeBase.Name", GetType(String))

_name = name
End Sub


Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property


Default Public ReadOnly Property Item(ByVal index As Integer) As
DictionaryEntry
Get
_de.Key = Me.BaseGetKey(index)
_de.Value = Me.BaseGet(index)
Return _de
End Get
End Property


Default Public Property Item(ByVal key As [String]) As [Object]
Get
Return Me.BaseGet(key)
End Get
Set(ByVal Value As [Object])
Me.BaseSet(key, Value)
End Set
End Property

Public ReadOnly Property AllKeys() As [String]()
Get
Return Me.BaseGetAllKeys()
End Get
End Property


Public ReadOnly Property AllValues() As Array
Get
Return Me.BaseGetAllValues()
End Get
End Property


Public ReadOnly Property AllStringValues() As [String]()
Get
Return
CType(Me.BaseGetAllValues(Type.GetType("System.String")), [String]())
End Get
End Property


Public ReadOnly Property HasKeys() As [Boolean]
Get
Return Me.BaseHasKeys()
End Get
End Property


Public Sub Add(ByVal key As [String], ByVal value As [Object])
Me.BaseAdd(key, value)
End Sub 'Add

Public Overloads Sub Remove(ByVal key As [String])
Me.BaseRemove(key)
End Sub 'Remove

Public Overloads Sub Remove(ByVal index As Integer)
Me.BaseRemoveAt(index)
End Sub 'Remove


Public Sub Clear()
Me.BaseClear()
End Sub 'Clear

Public Overrides Sub GetObjectData(ByVal info As
System.Runtime.Serialization.SerializationInfo, ByVal context As
System.Runtime.Serialization.StreamingContext)

MyBase.GetObjectData(info, context)

info.AddValue("EmployeeBase.Name", _name, GetType(String))
End Sub
End Class
==============================

Hope this helps.

Regards,

Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
Yes, that solution worked! Thank you for your quick response.

--
DENNY BROWNE
Steven Cheng said:
Hi Denny,

Welcome to the MSDN newsgroup.

From your description, I understand you have developed a custom class
which
derives from "NameObjectCollectionBase" class. The class also has a custom
string property named "Name". In your .net remoting application, you use a
server object to return an instance of this custom class to client-side.
However, you found that the returned custom class instance always have
empty "Name" value, correct?

Based on the code snippet you provided, I've also done some tests by
creating a simple custom class inheriting from NameObjectCollectionBase
and
I did encounter the problem you mentioned. After doing some further
research, I found that the problem is caused by the base class
"NameObjectCollectionBase". Since "NameObjectCollectionBase" class has
implemented the "ISerializable" interface, when the .net runtime
serializing the custom class instance, it will call the "GetObjectData"
method of the "NameObjectCollectionBase" class. However,
"NameObjectCollectionBase" class's "GetObjectData" method only save its
own properties, so our sub class's property values are lost. To resolve
this problem, we need to explicitly override the
"ISerializable.GetObjectData" method to store our own class's property(if
you want to persist it). In addition, we also need to retrieve the data
back from the SerializationInfo collection in the deserialization
constructor, Below is a simple test class I made, you can refer to it on
the two methods:

==========================
<Serializable()> Public Class EmployeeBase
Inherits NameObjectCollectionBase

Private _de As New DictionaryEntry

Private _name As String


Public Sub New()
End Sub

Public Sub New(ByVal d As IDictionary, ByVal bReadOnly As [Boolean])
Dim de As DictionaryEntry
For Each de In d
Me.BaseAdd(CType(de.Key, [String]), de.Value)
Next de
Me.IsReadOnly = bReadOnly
End Sub 'New


Protected Sub New(ByVal info As SerializationInfo, ByVal context As
StreamingContext)
MyBase.New(info, context)

Dim name As String

name = info.GetValue("EmployeeBase.Name", GetType(String))

_name = name
End Sub


Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property


Default Public ReadOnly Property Item(ByVal index As Integer) As
DictionaryEntry
Get
_de.Key = Me.BaseGetKey(index)
_de.Value = Me.BaseGet(index)
Return _de
End Get
End Property


Default Public Property Item(ByVal key As [String]) As [Object]
Get
Return Me.BaseGet(key)
End Get
Set(ByVal Value As [Object])
Me.BaseSet(key, Value)
End Set
End Property

Public ReadOnly Property AllKeys() As [String]()
Get
Return Me.BaseGetAllKeys()
End Get
End Property


Public ReadOnly Property AllValues() As Array
Get
Return Me.BaseGetAllValues()
End Get
End Property


Public ReadOnly Property AllStringValues() As [String]()
Get
Return
CType(Me.BaseGetAllValues(Type.GetType("System.String")), [String]())
End Get
End Property


Public ReadOnly Property HasKeys() As [Boolean]
Get
Return Me.BaseHasKeys()
End Get
End Property


Public Sub Add(ByVal key As [String], ByVal value As [Object])
Me.BaseAdd(key, value)
End Sub 'Add

Public Overloads Sub Remove(ByVal key As [String])
Me.BaseRemove(key)
End Sub 'Remove

Public Overloads Sub Remove(ByVal index As Integer)
Me.BaseRemoveAt(index)
End Sub 'Remove


Public Sub Clear()
Me.BaseClear()
End Sub 'Clear

Public Overrides Sub GetObjectData(ByVal info As
System.Runtime.Serialization.SerializationInfo, ByVal context As
System.Runtime.Serialization.StreamingContext)

MyBase.GetObjectData(info, context)

info.AddValue("EmployeeBase.Name", _name, GetType(String))
End Sub
End Class
==============================

Hope this helps.

Regards,

Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
Back
Top