3
votes

Does protobuf-net support nested classes ?

Are the attributes type names and order correct ?

as the code below, using alternative attribute XmlType/XmlElement instead ProtoContract/ProtoInclude

     using System.Xml.Serialization;

    [XmlType("Person")]
    public class Person
    {
      [XmlElement(ElementName = "Display Name",Order = 1)]
      public string Name { get; set; }

      [XmlElement(ElementName = "Age", Order = 2)]
      public byte  Age { get; set; }

      [XmlType("Person.Address")]
      public class Address
      {
          [XmlElement(ElementName = "Street",Order = 1)] 
           // before I had  Order=3 to be unique, but as Mark says 
           // the "Order  only needs to be unique inside a single type"
          public string Street { get; set; }

          [XmlElement(ElementName = "ZIP",Order =2)]
          public string Zip { get; set; }

      }        
   }

Update, in my answer below, I wrote the final class, implementing a ServiceStack service with protobuf.

1
It should do - are you seeing a problem? If so: exactly what? Note that the "Order" only needs to be unique inside a single type - it could be 1 and 2 in Address, as Address doesn't share anything with Person.Marc Gravell♦
I did not test it yet. Sorry I asked before try. I agree about the Order in Address class. By the way, as I prepare to test it in a few, 2 relevant questions, if you can please. 1. the name of XmlType should follow some rules ? 2. What is the difference (If any) between ProtoContact and XmlType attribute ? except the obvious in Inheritance [ProtoInclude(7, typeof(SomeDerivedType)]. BRB with my test.stefan2410
Protobuf-net doesn't use names at all unless you use GetSchema. The difference is that the XML attributes don't force protobuf dependencies into the DTO, but the protobuf attributes give you more specific control over serialization.Marc Gravell♦
Marc, I updated my test, in my answer for wiki. It works fine. Only I had problem with ServiceStack 3.9.71 and the protobuf-net version, check my question there, if you have time.stefan2410

1 Answers

2
votes

With Marc Gravell's help, I understood how nested classes work in protobuf.

I tested it with a ServiceStack (ver. 3.9.71) service, and it works fine.

here is the model.

using System.Xml.Serialization;

[XmlType("Person")]
public class Person
{
     [XmlElement(ElementName = "Display Name", Order = 1)]
     public string Name { get; set; }

     [XmlElement(ElementName = "Age", Order = 2)]
     public byte Age { get; set; }

     [XmlElement(ElementName = "Contact Address", Order =3)] // the address instance
     public Address ContactAddress { get; set; }

     [XmlElement(ElementName = "Person Id", Order = 4)]
     public int  Id { get; set; }

        [XmlType("Person.Address")]
        public class Address
        {
          [XmlElement(ElementName = "Street", Order = 1)]
          // before I had  Order=5 to be unique, but as Mark says 
          // the "Order  only needs to be unique inside a single type"
          public string Street { get; set; }

         [XmlElement(ElementName = "ZIP", Order = 2)]
         public string Zip { get; set; }

       }
}

the ServiceStack Requests

     public class PersonRequest
      {
        public string Zip { get; set; }
        public byte Age { get; set; }
        public int Id { get; set; }
      }
     public class AddressRequest
     {
       public string Zip { get; set; }

     }

the ServiceStack Routes in AppHost.Configure. ( self-hosted service)

   Routes        
      .Add<PersonRequest>("/Person/{Id}", "GET, OPTIONS")
      .Add<PersonRequest>("/Persons/{Zip}", "GET, OPTIONS")

      .Add<AddressRequest>("/Addresses/{Zip}", "GET, OPTIONS");

the services

First case, we ask a list of Persons with Contact Address using Zip filter

Second case, a list of Addresses using Zip filter, unrelated to Persons

public List<Person>  Get(PersonRequest request)
{
  List<Person> persons=new List<Person>();
  persons.Add(new Person()
  { Name = "stefan", ContactAddress = new Person.Address(){Street="North Pole"}});
    return  persons;
}
public List<Person.Address>  Get(AddressRequest request)
{    // it returns only addresses filtered by Zip
  List<Person.Address> addresses=new List<Person.Address>();         
  addresses.Add( new Person.Address() { Street = "North Pole" }  );
  return  addresses;
}

the ServiceStack client code, using the ProtoBufServiceClient

 using ServiceStack.Plugins.ProtoBuf;
        ...
 var client = new ProtoBufServiceClient(serverUri);
 List<Person> persons = client.Get<List<Person>>(serverUri + @"/Persons/600617");
 List<Person.Address> addresses = 
               client.Get<List<Person.Address>>(serverUri + @"/Addresses/600617");

thanks a lot, Marc.