toATwork
toATwork

Reputation: 1357

Serializing an Array in WCF with protobuf-net

I am trying to serialize an array of my dataobjects through WCF with protobuf-net.

If I serialize the Array of my dataobjects manually, it works successfully:

var proto = Serializer.CreateFormatter<DataType[]>();

which is way faster and smaller than the ordinary binary xml DataContractSerializer - thats why I wanna use it!

The 'DataType' class is just an example - I have many of those. When the reponse of my service is just a single object, everything works just fine.

But when my service returns an Array of objects it seems it does not know what to do and uses the ordinary DataContractSerializer.

The ProtoBehavior is applied:

endpoint.Behaviors.Add(new ProtoBuf.ServiceModel.ProtoEndpointBehavior());

My dataobject is more or less like that:

[Serializable]
[DataContract]
[ProtoContract]
public class DataType
{
    [DataMember(EmitDefaultValue = false, Name = "K")]
    [ProtoMember(1)]
    public string Key { get; set; }

    // many more to come
}

and that's basically my service:

[ServiceContract(CallbackContract = typeof(IBaseDataObjectUpdate), SessionMode = SessionMode.Required)]
[ServiceKnownType("GetKnownTypes", typeof(KnownTypesProvider))]
public interface IDataTypeService
{
    [OperationContract]
    DataType[] Load(Filter[] filter, Guid clientGuid);

    // some more
}

I could track it down to the TryCreate in the XmlProtoSerializer. The call:

int key = GetKey(model, ref type, out isList);

does not return a valid key, therefore no XmlProtoSerializer is created.

That explains the behavior, but what are my options here?

I found an old answer of Marc Gravell where he suggests the creation of an object which consists of the Array. But as it is from 2011 it might be outdated: https://stackoverflow.com/a/6270267/2243584

Or can I add the model to protobuf-net somehow manually? As mentioned above the manual serialization is working.

Any comment is appreciated!

Upvotes: 2

Views: 846

Answers (1)

toATwork
toATwork

Reputation: 1357

OK, so far I have come up with 2 solutions.

  1. Do not use Arrays! It works with any other collection. Which caused me to investigate and leaded to solution:
  2. Support Arrays in protobuf-net

I have adapted the method internal static Type GetListItemType(TypeModel model, Type listType) in the TypeMode class as follows:

if (listType.IsArray)  // NEW
{
  if (listType.GetElementType() == typeof(byte))
    return null;
}
if (listType == model.MapType(typeof(string)) // || listType.IsArray // CHANGED!!!
  || !model.MapType(typeof(IEnumerable)).IsAssignableFrom(listType)) return null;

I think I did figure out why arrays are excluded. Because if you support byte[], you get some problems when finally sending the data to the wire. At least I got some Assert and exception in the encode factory when dealing with byte[].

As I have no idea on the side effects of solution Nr. 2 - I stick with solution Nr. 1.

Nevertheless I am quite keen on a comment from Marc - of course, everybody is welcome!

Upvotes: 2

Related Questions