C# class generated with Protoc not deserializing a "Oneof" field

Zest4Quest 41 Reputation points
2021-08-10T21:22:16.697+00:00
  1. I have a proto file which contains the below in it
    message OuterMessage{
                 oneof instanceOrGroup {  
                                       string PropertyA = 10;  
                                       string PropertyB = 60;  
                                    }  
                 }  
    
  2. I generated C# class using protoc and on an instance of that class I set its first property as below.
  3. Then I serialized/de-serialized the class using NewtonSoft.Json as below
    ProtoGenCSharpClass obj = ....
    obj.PropertyA = "abc"

string jsonConvertStr = NewtonSoft.Json.JsonConvert.SerializeObject(obj);
ProtoGenCSharpClass deserialzedObj = NewtonSoft.Json.JsonConvert.DeserializeObject<ProtoGenCSharpClass>(jsonConvertStr);

at this point i see that the value set on the "PropertyA" property got wiped out.

What am I missing here? Do i need to write a custom converter or something? Or is there an issue in the proto file?

Original issue i was having was when I convert this object into a json string and then sent that as a StringContent to rest api
//Calling code
var content = new StringContent(JsonConvert.SerializeObject(obj), Encoding.UTF8, "application/json");
HttpResponseMessage response = await Task.Run(async () => await serviceClient.PostAsync(queryString, content));

   //Web api  
    [HttpPost]  
    [Route("saveOrder")]  
    [Route("saveOrder/{Id}")]  
    public async Task SaveOrder([FromUri] string Id, [FromBody] ProtoGenCSharpClass  myObj)  

{....
// at this point the myObj.PropertyA is emtpy
}

===================================

Please see the attached sample application files... I have used "Google.protobuf" and "Newtonsoft.Json" as nuget packages.

122806-simplified-cs.txt122746-program-cs.txt122739-simplified-proto.txt

Please advice.
Thanks
Jay

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
11,297 questions
{count} votes

2 answers

Sort by: Most helpful
  1. Viorel 119.9K Reputation points
    2021-08-12T17:57:00.787+00:00

    I think that you must find a way to not include “Algo”=”” when there is an “Instance”=”someInstanceValue” in JSON, because in will overwrite the value of Instance on deserialization. One of approaches is using a Contract Resolver:

    public class MyContractResolver : DefaultContractResolver
    {
       protected override IList<JsonProperty> CreateProperties( Type type, MemberSerialization memberSerialization )
       {
          var list = base.CreateProperties( type, memberSerialization );
    
          foreach( var p in list.Where( p => p.PropertyName == "Algo" || p.PropertyName == "Instance" ) )
          {
             p.DefaultValue = "";
             p.DefaultValueHandling = DefaultValueHandling.Ignore;
             p.NullValueHandling = NullValueHandling.Ignore;
          }
    
          return list;
       }
    }
    

    Usage:

    JsonSerializerSettings opt = new JsonSerializerSettings
    {
       ContractResolver = new MyContractResolver( ),
    };
    
    string jsonConvertStr = JsonConvert.SerializeObject( request, opt );
    Request requestJsonConvert = JsonConvert.DeserializeObject<Request>( jsonConvertStr, opt );
    

    Perhaps it can be improved, or there are more appropriate ways. (Maybe there is a forum, which is dedicated to these aspects).

    1 person found this answer helpful.
    0 comments No comments

  2. Karen Payne MVP 35,551 Reputation points
    2021-08-10T21:47:02.91+00:00

    Here is a basic do nothing example that writes to the console, no different than writing to a file.

    122113-f1.png

    using System;  
    using System.Collections.Generic;  
    using Newtonsoft.Json;  
      
    namespace ConsoleApp1  
    {  
        class Program  
        {  
            static void Main(string[] args)  
            {  
                var i1 = new Item  
                {  
                    Id = 1,  
                    Name = "test1",  
                    Value = "result1"  
                };  
      
                var i2 = new Item  
                {  
                    Id = 2,  
                    Name = "test2",  
                    Value = "result2"  
                };  
      
                ReturnData returnData = new ReturnData();  
      
                var items = new List<Item> { i1, i2 };  
      
      
                returnData.Id = 10;  
                returnData.Type = "type1";  
                returnData.Items = items;  
      
                var json = JsonConvert.SerializeObject(returnData, Formatting.Indented);  
      
                Console.WriteLine(json);  
                Console.ReadLine();  
      
            }  
        }  
      
        class ReturnData  
        {  
            public int Id { get; set; }  
            [JsonProperty]  
            public string Type { get; set; }  
            [JsonProperty]  
            public List<Item> Items { get; set; }  
        }  
      
        public class Item  
        {  
            public int Id { get; set; }  
            public string Name { get; set; }  
            public string Value { get; set; }  
        }  
    }  
      
    

    Here we also can deserialize

    using System;  
    using System.Collections.Generic;  
    using Newtonsoft.Json;  
      
    namespace ConsoleApp1  
    {  
        class Program  
        {  
            static void Main(string[] args)  
            {  
                var i1 = new Item  
                {  
                    Id = 1,  
                    Name = "test1",  
                    Value = "result1"  
                };  
      
                var i2 = new Item  
                {  
                    Id = 2,  
                    Name = "test2",  
                    Value = "result2"  
                };  
      
                ReturnData returnData = new ReturnData();  
      
                var items = new List<Item> { i1, i2 };  
      
      
                returnData.Id = 10;  
                returnData.Type = "type1";  
                returnData.Items = items;  
      
                var json = JsonConvert.SerializeObject(returnData, Formatting.Indented);  
      
                Console.WriteLine(json);  
      
                var results = JsonConvert.DeserializeObject<ReturnData>(json);  
                Console.ReadLine();  
      
            }  
        }  
      
        public class ReturnData  
        {  
            public int Id { get; set; }  
            [JsonProperty]  
            public string Type { get; set; }  
            [JsonProperty]  
            public List<Item> Items { get; set; }  
        }  
      
        public class Item  
        {  
            public int Id { get; set; }  
            public string Name { get; set; }  
            public string Value { get; set; }  
        }  
    }  
      
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.