brucezhang80 / protobuf-net

Automatically exported from code.google.com/p/protobuf-net
Other
0 stars 0 forks source link

No parameterless constructor support as with DataContractSerializer #399

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
As a Migrator from DataContractSerializer to ProtoBuf
Given that compatibility of both is partially done in ProtoBuf
I want that ProtoBuf support case of "No parameterless constructor" as 
DataContractSerializer  does

Original issue reported on code.google.com by Dzmitry....@gmail.com on 17 Jul 2013 at 1:51

GoogleCodeExporter commented 9 years ago
[TestFixture]
    public class SerializersCompatibilityTests
    {

        [DataContract]
        public class EventMessage
        {
            public EventMessage(string sender, string data, Guid id)
            {
                Sender = sender;
                Data = data;
                Id = id;
                Timestamp = DateTime.Now;
            }

            [DataMember(Order = 4)]
            public DateTime Timestamp { get; private set; }

            [DataMember(Order = 1)]
            public Guid Id { get; private set; }

            [DataMember(Order = 2)]
            public string Sender { get; private set; }

            [DataMember(Order = 3)]
            public string Data { get; private set; }

        }

        [Test]
        public void SerializeNoPublicEmptyConstructor()
        {
            var msg = new EventMessage("sender","data",Guid.NewGuid());
            var proto = ProtoBuf.Meta.TypeModel.Create();
            proto.Add(typeof(EventMessage), true);
            proto.CompileInPlace();
            var xml = new DataContractSerializer(typeof(EventMessage));
            xml.WriteObject(new MemoryStream(), msg);
            proto.Serialize(new MemoryStream(), msg);
        }

        [Test]
        public void DeSerializeNoPublicEmptyConstructor()
        {
            var msg = new EventMessage("sender", "data", Guid.NewGuid());
            var proto = ProtoBuf.Meta.TypeModel.Create();
            proto.Add(typeof(EventMessage), true);
            proto.CompileInPlace();
            var xml = new DataContractSerializer(typeof(EventMessage));
            var xmlStream = new MemoryStream();
            xml.WriteObject(xmlStream, msg);
            xmlStream.Position = 0;
            var protoStream = new MemoryStream();
            proto.Serialize(protoStream, msg);
            protoStream.Position = 0;

           var fromXml = xml.ReadObject(xmlStream) as EventMessage;
            Assert.AreEqual("sender",fromXml.Sender);

            proto.Deserialize(protoStream, null, typeof (EventMessage));

        }
    }

Original comment by Dzmitry....@gmail.com on 17 Jul 2013 at 1:51

GoogleCodeExporter commented 9 years ago
protobuf-net 2.0.0.640 .NET 4.0 NUnit  Win7 SP2

Original comment by Dzmitry....@gmail.com on 17 Jul 2013 at 1:51

GoogleCodeExporter commented 9 years ago
ProtoBuf.ProtoException : No parameterless constructor found for EventMessage
   at ProtoBuf.Meta.TypeModel.ThrowCannotCreateInstance(Type type) in c:\Dev\protobuf-net\protobuf-net\Meta\TypeModel.cs: line 1368
   at proto_2(Object, ProtoReader)
   at ProtoBuf.Meta.TypeModel.DeserializeCore(ProtoReader reader, Type type, Object value, Boolean noAutoCreate) in c:\Dev\protobuf-net\protobuf-net\Meta\TypeModel.cs: line 683
   at ProtoBuf.Meta.TypeModel.Deserialize(Stream source, Object value, Type type, SerializationContext context) in c:\Dev\protobuf-net\protobuf-net\Meta\TypeModel.cs: line 582
   at ProtoBuf.Meta.TypeModel.Deserialize(Stream source, Object value, Type type) in c:\Dev\protobuf-net\protobuf-net\Meta\TypeModel.cs: line 561
   at NDceRpc.ServiceModel.IntegrationTests.SerializersCompatibilityTests.DeSerializeNoPublicEmptyConstructor() in SerializersCompatibilityTests.cs: line 77

Original comment by Dzmitry....@gmail.com on 17 Jul 2013 at 1:51

GoogleCodeExporter commented 9 years ago
Specify SkipConstructor=true on the ProtoContractAttribute

Original comment by marc.gravell on 17 Jul 2013 at 3:58

GoogleCodeExporter commented 9 years ago
Thank you. Next helps (I not want new attrs on types):
           var metaType = proto.Add(typeof (NoParameterlessConstructorWithPivateSetter), true);
            metaType.UseConstructor = false;

Original comment by Dzmitry....@gmail.com on 17 Jul 2013 at 6:25

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
Next patch fixed problem. I d like to convince you that when DataContract is 
alone, then proto should behave as DataContractSerilizer. Will not confuse 
newcomers migrating to protobuf.

Index: MetaType.cs
===================================================================
--- MetaType.cs (revision 645)
+++ MetaType.cs (working copy)
@@ -623,6 +623,9 @@
                 if (fullAttributeTypeName == "System.Runtime.Serialization.DataContractAttribute")
                 {
                     if (name == null && item.TryGet("Name", out tmp)) name = (string)tmp;
+                    // this is default behaviour of DataContractSerializer, 
make proto behave the same when DataContractAttribute is alone
+                    if (family == AttributeFamily.DataContractSerialier)
+                        UseConstructor = false; 
                 }
                 if (fullAttributeTypeName == "System.Xml.Serialization.XmlTypeAttribute")
                 {

Original comment by Dzmitry....@gmail.com on 17 Jul 2013 at 6:30

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
namespace ProtoBuf.unittest.Meta
{
    [TestFixture]
    public class ConstuctorTests
    {
        [DataContract]
        public class NoParameterlessConstructorWithPivateSetter
        {
            public NoParameterlessConstructorWithPivateSetter(string data,string fieldData)
            {
                Data = data;
                FieldData = fieldData;
            }

            [DataMember(Order = 2)]
            private string FieldData;

            public string GetFieldValue()
            {
                return FieldData;
            }

            [DataMember(Order = 1)]
            public string Data { get; private set; }

        }

        [Test]
        public void SerializeNoPublicEmptyConstructor()
        {
            var msg = new NoParameterlessConstructorWithPivateSetter("data","field");
            var proto = ProtoBuf.Meta.TypeModel.Create();
            proto.Add(typeof(NoParameterlessConstructorWithPivateSetter), true);
            proto.CompileInPlace();
            var xml = new DataContractSerializer(typeof(NoParameterlessConstructorWithPivateSetter));
            xml.WriteObject(new MemoryStream(), msg);
            proto.Serialize(new MemoryStream(), msg);
        }

        [Test]
        public void DeSerializeNoPublicEmptyConstructor()
        {
            var msg = new NoParameterlessConstructorWithPivateSetter("data","field");
            var proto = ProtoBuf.Meta.TypeModel.Create();
            var metaType = proto.Add(typeof (NoParameterlessConstructorWithPivateSetter), true);
            //metaType.UseConstructor = false;//default behaviour of NoParameterlessConstructorWithPivateSetter
            proto.CompileInPlace();
            var xml = new DataContractSerializer(typeof(NoParameterlessConstructorWithPivateSetter));
            var xmlStream = new MemoryStream();
            xml.WriteObject(xmlStream, msg);
            xmlStream.Position = 0;
            var protoStream = new MemoryStream();
            proto.Serialize(protoStream, msg);
            protoStream.Position = 0;

            var fromXml = xml.ReadObject(xmlStream) as NoParameterlessConstructorWithPivateSetter;
            Assert.AreEqual("data", fromXml.Data);
            Assert.AreEqual("field", fromXml.GetFieldValue());

            var fromProto = proto.Deserialize(protoStream, null, typeof(NoParameterlessConstructorWithPivateSetter)) as NoParameterlessConstructorWithPivateSetter;
            Assert.AreEqual("data", fromProto.Data);
            Assert.AreEqual("field", fromProto.GetFieldValue());
        }
    }
}

Original comment by Dzmitry....@gmail.com on 17 Jul 2013 at 6:40

GoogleCodeExporter commented 9 years ago
Can you make AttributeFamily public in API used above to allow conditional 
UseConstructor  like is done in my patch shown earlier?

Original comment by Dzmitry....@gmail.com on 6 Aug 2013 at 9:50