Object Hierarchies in Events

Jul 24, 2008 at 1:50 PM
Hi Keith,

I have a situation where the Event contains Lists of instances of some other classes as properties.  These classes don't inherit from Event.  I have inherited them from ISerializable and implemented a GetObjectData(SerializationInfo, StreamingContext) for each.

When running through the event's implementation of GetObjectData(SerializationData), it gets to the custom class and raises an "Unknown type for Value Object" WSP exception.

Is there a recommended way to do this?

DS
Coordinator
Jul 25, 2008 at 6:17 AM
I'll send you a sample piece of code on Friday when I get to work for doing your own custom serialize/deserialize. It's really pretty easy. I just wanted to have the base class handle the common simple cases. The standard binary serialization was too slow for my scenarios so I use the binary reader/writer for doing serialization. It's fast but you have to put your data into a type that it supports. This means you need to decompose your complex objects into simple properties and reconstruct them on deserialization. The sample I'll post is serializing a Dictionary and then deserializing it.
Jul 25, 2008 at 7:08 AM

Thanks.  Looking forward to it.

It's a good lib - Straightforward and reliable, so thanks for producing.

Coordinator
Jul 25, 2008 at 5:07 PM

In the GetObjectData, the data is written out as ordered KV pairs. I am iterating through the dictionary and writing out all the individual properties. You would need to do the same. If you want, you could serialize an object using standard .Net into a byte array and then just write out one byte array for the complex object.

In the Deserialize method, you would replace the if's in the foreach loop with ones appropriate for how you wrote out your properties. Leave the lines starting with "prop = " since they will set some of the header properties.

If you have any issues, send me exerpts from your code and I can help get it working. I know it would be nice if I provided a clean way to extend serialization but didn't.

Keith

 

 

public class WspWebMonitorCounterDetail

 

{

 

private string applicationName;

 

 

/// <summary>

 

 

 

 

 

/// Application name

 

 

 

 

 

/// </summary>

 

 

 

 

 

public string ApplicationName

 

{

 

get

 

 

 

 

{

 

return applicationName;

 

}

 

set

 

 

 

 

{

applicationName =

value;

 

}

}

 

private long averageTicks;

 

 

/// <summary>

 

 

 

 

 

/// AverageTicks

 

 

 

 

 

/// </summary>

 

 

 

 

 

public long AverageTicks

 

{

 

get

 

 

 

 

{

 

return averageTicks;

 

}

 

set

 

 

 

 

{

averageTicks =

value;

 

}

}

 

private long requestCounter;

 

 

/// <summary>

 

 

 

 

 

/// RequestCounter

 

 

 

 

 

/// </summary>

 

 

 

 

 

public long RequestCounter

 

{

 

get

 

 

 

 

{

 

return requestCounter;

 

}

 

set

 

 

 

 

{

requestCounter =

value;

 

}

}

 

private long errorCounter;

 

 

/// <summary>

 

 

 

 

 

/// ErrorCounter

 

 

 

 

 

/// </summary>

 

 

 

 

 

public long ErrorCounter

 

{

 

get

 

 

 

 

{

 

return errorCounter;

 

}

 

set

 

 

 

 

{

errorCounter =

value;

 

}

}

 

/// <summary>

 

 

 

 

 

/// Base constructor

 

 

 

 

 

/// </summary>

 

 

 

 

 

public WspWebMonitorCounterDetail()

 

{

AverageTicks = 0;

RequestCounter = 0;

ErrorCounter = 0;

}

}

 

public Dictionary<string, WspWebMonitorCounterDetail> CounterList;

 

 

/// <summary>

 

 

 

 

 

/// Base constructor to create a new event

 

 

 

 

 

/// </summary>

 

 

 

 

 

public WspWebMonitorCounterResponse()

 

:

base()

 

{

EventType =

new Guid(@"B4E53044-DF49-462e-AA26-3E8FE0F9E0E3");

 

CounterList =

new Dictionary<string, WspWebMonitorCounterDetail>(StringComparer.CurrentCultureIgnoreCase);

 

}

 

/// <summary>

 

 

 

 

 

/// Base constructor to create a new event from a serialized event

 

 

 

 

 

/// </summary>

 

 

 

 

 

/// <param name="serializationData">Serialized event data</param>

 

 

 

 

 

public WspWebMonitorCounterResponse(byte[] serializationData)

 

:

base(serializationData)

 

{

CounterList =

new Dictionary<string, WspWebMonitorCounterDetail>(StringComparer.CurrentCultureIgnoreCase);

 

}

 

/// <summary>

 

 

 

 

 

/// Deserializes the event

 

 

 

 

 

/// </summary>

 

 

 

 

 

public override void Deserialize(byte[] serializationData)

 

{

WspWebMonitorCounterDetail[] valuesList =

new WspWebMonitorCounterDetail[CounterList.Count];

 

 

int i = 0;

 

 

PropertyInfo prop;

 

WspWebMonitorCounterDetail counterDetail =

null;

 

SerializationData sEventIn =

new SerializationData(serializationData);

 

SerializedEvent =

new SerializationData(serializationData);

 

OriginatingRouterName = SerializedEvent.GetOriginatingRouterName();

InRouterName = SerializedEvent.GetInRouterName();

EventType = SerializedEvent.GetEventType();

 

foreach (WspKeyValuePair<string, object> kv in SerializedEvent)

 

{

 

if (kv.Key == @"1" || kv.Key == @"ApplicationName")

 

{

 

if (i < valuesList.Length)

 

{

counterDetail = valuesList[i];

counterDetail.AverageTicks = 0;

counterDetail.ErrorCounter = 0;

counterDetail.RequestCounter = 0;

i++;

}

 

else

 

 

 

 

{

counterDetail =

new WspWebMonitorCounterDetail();

 

}

CounterList[(

string)kv.ValueIn] = counterDetail;

 

counterDetail.ApplicationName = (

string)kv.ValueIn;

 

 

continue;

 

}

 

if (kv.Key == @"2" || kv.Key == @"AverageTicks")

 

{

counterDetail.AverageTicks = (

long)kv.ValueIn;

 

 

continue;

 

}

 

if (kv.Key == @"3" || kv.Key == @"RequestCounter")

 

{

counterDetail.RequestCounter = (

long)kv.ValueIn;

 

 

continue;

 

}

 

if (kv.Key == @"4" || kv.Key == @"ErrorCounter")

 

{

counterDetail.ErrorCounter = (

long)kv.ValueIn;

 

 

continue;

 

}

prop =

this.GetType().GetProperty(kv.Key, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

 

 

if (prop != null)

 

{

 

try

 

 

 

 

{

prop.SetValue(

this, kv.ValueIn, null);

 

}

 

catch

 

 

 

 

{

 

// Ignore

 

 

 

 

}

}

}

}

 

/// <summary>

 

 

 

 

 

/// Used for event serialization.

 

 

 

 

 

/// </summary>

 

 

 

 

 

/// <param name="data">SerializationData object passed to store serialized object</param>

 

 

 

 

 

public override void GetObjectData(SerializationData data)

 

{

 

foreach (WspWebMonitorCounterDetail counterDetail in CounterList.Values)

 

{

data.AddElement(

@"1", counterDetail.ApplicationName);

 

data.AddElement(

@"2", counterDetail.AverageTicks);

 

data.AddElement(

@"3", counterDetail.RequestCounter);

 

data.AddElement(

@"4", counterDetail.ErrorCounter);

 

}

}

}

Dec 10, 2008 at 4:27 PM

Hi,

I am revisiting this for another module.  Thanks for the code.

Would I be correct in assuming that the following are the list of serialisable datatypes?  If not, then is there a complete list documented anywhere?  If so, then am I right in assuming that the only arrays that can be passed across the wire are Byte and Char arrays?

  • String
  • Boolean
  • Int16
  • Int32
  • Int64
  • UInt16
  • UInt32
  • UInt64
  • Double
  • Decimal
  • Byte
  • Byte[]
  • ByteArray
  • SByte
  • Char
  • Char[]
  • CharArray
  • Version
  • DateTime
  • Guid
  • Single
  • System.Net.IPAddress
  • Uri
  • System.Collections.Generic.Dictionary
Coordinator
Dec 10, 2008 at 4:43 PM
The list you show are the only types which have support for serialization. You can create a property which you only use as a proxy for serializing complex objects. Meaning, you could create a Byte[] complexObject. In its Get accessor, you could serialize a complex object into a byte array and return that array. In its Set accessor, you could deserialze the byte array back into your object. In the GetObjectData, you would only specify this proxy property.

If this approach still won't work then you can drop down even lower and take total control of the serialization. I wouldn't recommend this unless absolutely necessary. If you need to let me know and I'll give you some sample code.

Dec 10, 2008 at 7:35 PM
No - that's cool - it's what I thought.  Good tip on the accessors - I've been writing conversion methods, but it's much neater to slap it into the accessors.

It's nice you see you are getting mentioned around the web now.  I was a little worried this thing would get abandoned through lack of interest, but it seems to be picking up slowly.

Have a happy Christmas - I don't expect to sign in again this year, so good luck to you for 02009.

Best,  DS.