C# Serialize JSON object within JSON objects - c#

I have these entities:
public class Product
{
public string Code {get;set;}
public string Name {get;set;}
public ICollection<Pack> Packs {get;set;}
}
public class Pack
{
public string Colour {get;set;}
public string Moq {get;set;}
}
my json object:
var products = [{
code: 1243123,
name: "Gel",
packs: [{
color: "blue",
moq: 10
}]
}];
note the naming differences, i.e. case and american spelling of color. Will the JavaScriptConvert.DeserializeObject() deserialise that correctly?
Or will I have to do it another way?
If I can just have an object where I can access those names directly and there values that would be great!

If you use something like JSON.NET, then you can use attributes to control serialization, such as:
public class Pack
{
[JsonProperty("color")]
public string Colour {get;set;}
[JsonProperty("moq")]
public string Moq {get;set;}
}
Also, given your expected output, your Product class should look like this I think:
public class Product
{
[JsonProperty("code")]
public long Code {get;set;}
[JsonProperty("name")]
public string Name {get;set;}
[JsonProperty("packs")]
public Pack[] Packs {get;set;}
}
Note Code and Packs type.

If you use DataContractJsonSerializer instead, you can put attributes to your properties, giving them different names in generated/parsed JSON:
[DataContract]
public class Pack
{
[DataMember(Name = "color")]
public string Colour {get;set;}
[DataMember(Name = "moq")]
public string Moq {get;set;}
}

Related

Custom Serialization/Deserialization in RestSharp 108

In updating from RestSharp 106 to 108 I've been unable to come up with an elegant replacement for the following. I've looked at the migration documentation to no avail. There is a good chance I've missed something obvious.
Existing code that works in v106, which covered both XML and JSON
Class A
using RestSharp.Deserializers;
[DeserializeAs(Name = "response")]
public class ACertainResponse
{
public string SomeProp {get; set;}
//Etc
}
//JSON Payload {"response" : {"SomeProp" : "Some Value"}}
Class B
using RestSharp.Serializers;
[SerializeAs(Name = "request")]
public class SomeRequest
{
public string SomeProp {get; set;}
//Etc
}
//Resulting in :
//{"request" : { "SomeProp" : "A Value" } }
I've found [JsonPropertyName("customName")], however, as the name suggests that is for properties only.
Whilst I was unable to find a one size fits all solution as previouslt provided I was able to get it working by setting attributes for XML or JSON serialization explicitly. These attributes cover bother serialization and deserialization:
JSON
using System.Text.Json.Serialization;
[JsonSerializable(typeof(LeadspediaRequest), TypeInfoPropertyName = "response")]
public class ACertainResponse
{
public string SomeProp {get; set;}
//Etc
}
XML
using System.Xml.Serialization;
[XmlRoot(ElementName = "response")]
[XmlType("response")]
public class SomeRequest
{
public string SomeProp {get; set;}
//Etc
}

Deserialize an array inside a json object using JsonConvert.DeserializeObject()

I have a requirement where I have incoming json object of the following format:
{
"CustomerList": {
"Customer": [{
"CustomerCode" : "C123",
"CustomerName" : "Peter"
},
{
"CustomerCode" : "C456",
"CustomerName" : "John"
}]
}
}
And I have the my C# object of the following Format:
[System.Xml.Serialization.XmlArrayItemAttribute(IsNullable = "false")]
public Customer[] CustomerList
{
get; set;
}
[System.Xml.Serialization.XmlTypeAttribute()]
public class Customer
{
public string CustomerCode {get; set;}
public string CustomerName {get; set;}
}
During Deserialization using JsonConvert.DeserializeObject(), I get the following error:
Cannot deserialize the current JSON object into type Customer[], because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
On my side the limitation is that I cannot change the incoming JSON object and neither can I modify the C# object structure. So the ask is that, is there a way to map the Customer node in the incoming Json, to the CustomerList C# array directly, without needing to rename or change the structure of either?
Based on the JSON you have shared, you need to have following class structure.
public class Customer {
public string CustomerCode { get; set; }
public string CustomerName { get; set; }
}
public class CustomerList {
public List<Customer> Customer { get; set; }
}
public class RootObject {
public CustomerList CustomerList { get; set; }
}
and then you need to deserizalize the JSON as following.
RootObject obj = JsonConvert.DeserializeObject<RootObject>(jsonString);
Here jsonString is the string variable which has the JSON string.
I hope you this will help you resolve your issue.
To deserialize the JSON object you need to create a similar C# class.
public class JsonObjectTest {
[JsonPropertyName("CustomerList")]
public Customer CustomerPreList {get;set;}
}
public class Customer {
public List<CustomerObject> Customer {get;set;}
}
public class CustomerObject {
public string CustomerCode { get; set; }
public string CustomerName { get; set; }
}
Afterwards you deserialize the JSON object:
CustomerList xmlData = JsonConvert.DeserializeObject<JsonObjectTest>(jsonObjectString).Select(data =>
new CustomerList = data.CustomerPreList.toArray());
Unfortunately I could not ask you if you have a permission to create new classes (I need more points). If this is the case try AutoMapper to create a mapping policy for this specific case.
Happy coding :)
If you cannot (or do not want to) add new classes, the last two lines of GetCustomers() below should do what you want. Just assign it to the CustomerList property.
public class Customer
{
public string? CustomerCode { get; set; }
public string? CustomerName { get; set; }
}
public Customer[] GetCustomers()
{
string json = #"{
'CustomerList':
{
'Customer': [{
'CustomerCode' : 'C123',
'CustomerName' : 'Peter'
},
{
'CustomerCode' : 'C456',
'CustomerName' : 'John'
}]
}
}";
dynamic? contentObj = JsonConvert.DeserializeObject(json);
return (contentObj?.CustomerList.Customer.ToObject<IList<Customer>>())?.ToArray() ?? new List<Customer>().ToArray();
}
I am working with .NET 6.0 so working with string? but for earlier versions of c# string should do the same. Play with the null handling as required.

Convert a JSON object A to JSON B object where B is a strict subset of A. Both governed by two json schemas. In .net core

I got a bunch of conversions to make where I am converting a JSON data structure from a superset to a subset. EX:
A :
{
Name {
first: bob
middle: john
last : bobster
}
}
B :
{
Name {
first: bob
last : bobster
}
}
Both have a json schema describing their structure, and structure is exactly the same, is that B is simply missing some properties from A
Any ideas for an easy way to map A to B (essentially stripping A of properties that do not exist in B)? I am wondering if there is some library or C# language capabilities that could make this trivial.
Using C# and .NET Core.
Create an object for the subset like:
public class Name{
public string first{get;set;}
public string last {get;set;}
}
Deserialize the json to the subset object:
var test = JsonConvert.DeserializeObject<Name>(superset);
Then you can use this to convert back to json if needed:
JsonConvert.SerializeObject(subset)
You can use inheritance to cast objects from a subclass to another class.
Given the following json
{
"Name":
{
"first": "bob",
"middle": "john",
"last" : "bobster"
}
}
You can create some C# classes that match the json structure as follows:
public class Model
{
public FullName Name { get; set; }
}
public class Name
{
[JsonProperty("first")]
public string First { get; set; }
[JsonProperty("last")]
public string Last { get; set; }
}
public class FullName : Name
{
[JsonProperty("middle")]
public string Middle { get; set; }
}
Please note that:
FullName inherits from Name
class Model has a property of type FullName (i.e. the most specific object)
You can deserialize an object of type Model and then cast the Name property as follows:
string json = #"{
""Name"":
{
""first"": ""bob"",
""middle"": ""john"",
""last"" : ""bobster""
}
}";
Model model = JsonConvert.DeserializeObject<Model>(json);
Name name = model.Name as Name;
Edit
As an alternative, you can create a generic class as follows
public class Model<TName> where TName : Name
{
public TName Name { get; set; }
}
Deserializing the json:
string json = #"{
""Name"":
{
""first"": ""bob"",
""middle"": ""john"",
""last"" : ""bobster""
}
}";
var fullName = JsonConvert.DeserializeObject<Model<FullName>>(json);
var name = JsonConvert.DeserializeObject<Model<Name>>(json);

Base Class For JSON Data

I'm creating objects to store the JSON data I will be receiving and cannot figure out the right way to structure the objects. Basically, I can be receiving two different objects that only have differences in the body, so I wish to make a base class.
public class SampleBase
{
public string url { get; set; }
public string resource { get; set; }
public string Body body { get; set; }
}
This is an example of the base, with the Body object declared below
public abstract class Body{ }
I then have two separate files for the versions of the base object I can receive, with an example below:
public class SampleObject : SampleBase
{
public class Body
{
public string bodyproperty { get; set; }
}
}
I am doing this just to be efficient with the classes since they share some properties. The SampleBase class will never be called, instead incoming json will be deserialized into SampleObject. Is this best practice?
Edit: Going by this example, the JSON is received as
{
"url": "xxxxxxxxxx",
"resource": "xxxxxxx",
"body": {
"bodyproperty": "xxxx",
}
}
Your class structure can heavily depend on your choice of serializer. For example, the DataContractJsonSerializer can technically handle inherited classes, but it does it in somewhat of a clunky way. You need to define all the known inheritors of your base type on the base type.
Personally, I would use composition rather than inheritance in your case. Here's an example using the DataContractJsonSerializer:
[DataContract]
public class Wrapper<T> where T : Body
{
[DataMember(Name = "url")]
public string Url { get; set; }
[DataMember(Name = "resource")]
public string Resource { get; set; }
[DataMember(Name = "body")]
public string T Body { get; set; }
}
[DataContract]
public class Body
{
[DataMember(Name = "bodyproperty")]
public string BodyProperty { get; set; }
}
Then you'd use the class like any other generic.
Wrapper<Body> obj = new Wrapper<Body>();
Edit: Since this is a MVC application, you'll likely be working with the JavascriptSerializer. The DataContract and DataMember can be ignored but the structure of the classes is still relevant.
var serializer = new JavaScriptSerializer();
var data = serializer.Deserialize<Wrapper<Body>>(json);

ServiceStack.Text JSON parsing on .Net 4.0

H chaps,
I am trying to use ServiceStack.Text for JSON parsing (it seems to be performing better than JSON.Net in various benchmarks I have seen). But I am not getting the results I am expecting. The class I am attempting to deserialize looks like this:
[DataContract]
public class RpcRequest<T>
{
[JsonProperty("id")]
[DataMember(Name="id")]
public String Id;
[JsonProperty("method")]
[DataMember(Name="method")]
public String Method;
[JsonProperty("params")]
[DataMember(Name="params")]
public T Params;
[JsonIgnore]
[IgnoreDataMember]
public Policy Policy;
}
And I am invoking the parser like this
public static class Json
{
public static T Deserialize<T>(string serialized)
{
return TypeSerializer.DeserializeFromString<T>(serialized);
}
}
...
RpcRequest<Params> myRequeset = Json.Deserialize(packet);
However I am getting an instance back from that call which has none of the values set. ie Id, Method and Params are all null. Am I using this API correctly?
It seems that ServiceStack does not support public fields, only public properties. So if I change my model object to the following it all works.
[DataContract]
public class RpcRequest<T>
{
[JsonProperty("id")]
[DataMember(Name="id")]
public String Id { get; set; }
[JsonProperty("method")]
[DataMember(Name="method")]
public String Method { get; set; }
[JsonProperty("params")]
[DataMember(Name="params")]
public T Params { get; set; }
[JsonIgnore]
[IgnoreDataMember]
public Policy Policy { get; set; }
}
Note the addition of getters and setters to each property.
I think you want JsonSerializer instead of TypeSerializer.
TypeSerializer is a new-fangled JSV format that Mr Mythz details on his blog here: http://www.servicestack.net/mythz_blog/?p=176

Categories

Resources