question

Zest4Quest-7608 avatar image
0 Votes"
Zest4Quest-7608 asked Viorel-1 edited

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

  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


dotnet-csharp
· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

@Zest4Quest-7608
Could you please share with us the generated C# class?
Logically speaking, this shouldn't happen, we need more complete information to analyze this problem.

0 Votes 0 ·

will get back with a sample app soon Timon.

0 Votes 0 ·

Hi Timon, I have attached the proto file, C# file generated using "protoc" compiler and the sample application code.

0 Votes 0 ·
karenpayneoregon avatar image
0 Votes"
karenpayneoregon answered AgaveJoe edited

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; }
     }
 }




f1.png (6.2 KiB)
· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thanks for the reply Karen. But the issue I am having is not with a class that I manually typed. But one generated using google's protoc compiler where the proto member is marked as "OneOf". Unfortunately your reply does not seem related.

0 Votes 0 ·

oneof is not a C# keyword. I assume you wrote the protocol buffer in a different language and expect the community to magically figure out what you're doing.

Anyway, if you have the JSON stream then you can use Visual Studio to create a C# type that represents the JSON stream. It's very simple.
Copy the JSON data, select "Edit" in visual Studio, "Paste Special", "Paste JSON as Classes".

Typically, there is little reason to manually serialize/deserialize C# types. The framework handles serialization using the type in the return and input parameters.

0 Votes 0 ·
Viorel-1 avatar image
1 Vote"
Viorel-1 answered Viorel-1 edited

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).

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.