Newtonsoft JsonSerializer - Lower case properties and dictionary [duplicate] - c#

This question already has answers here:
Keep casing when serializing dictionaries
(4 answers)
Closed 7 years ago.
I'm using json.net (Newtonsoft's JsonSerializer). I need to customize serialization in order to meet following requirements:
property names must start with lower case letter.
Dictionary must be serialized into jsonp where keys will be used for property names. LowerCase rule does not apply for dictionary keys.
for example:
var product = new Product();
procuct.Name = "Product1";
product.Items = new Dictionary<string, Item>();
product.Items.Add("Item1", new Item { Description="Lorem Ipsum" });
must serialize into:
{
name: "Product1",
items : {
"Item1": {
description : "Lorem Ipsum"
}
}
}
notice that property Name serializes into "name", but key Item1 serializes into "Item1";
I have tried to create CustomJsonWriter to serialize property names, but it changes also dicionary keys.
public class CustomJsonWriter : JsonTextWriter
{
public CustomJsonWriter(TextWriter writer) : base(writer)
{
}
public override void WritePropertyName(string name, bool escape)
{
if (name != "$type")
{
name = name.ToCamelCase();
}
base.WritePropertyName(name, escape);
}
}

You could try using the CamelCasePropertyNamesContractResolver.
var serializerSettings = new JsonSerializerSettings();
serializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
var json = JsonConvert.SerializeObject(product, serializerSettings);
I'm just not sure how it'll handle the dictionary keys and I don't have time right this second to try it. If it doesn't handle the keys correctly it's still worth keeping in mind for the future rather than writing your own custom JSON writer.

You can use a JsonProperty to change how something is serialized/deserialized. When you define your object add the property items to the fields you would like represented differently in the JSON. This only works with NewtonsoftJSON. Other libraries may do it differently.
public class Product
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("items")]
public Dictionary<string, Item> Items { get; set; }
}
public class Item
{
[JsonProperty("description")]
public string Description { get; set; }
}

Related

How to avoid JsonConvert.PopulateObject enqueue on lists [duplicate]

This question already has answers here:
Json.Net PopulateObject Appending list rather than setting value
(1 answer)
How to apply ObjectCreationHandling.Replace to selected properties when deserializing JSON?
(1 answer)
Closed 1 year ago.
I have this silly class:
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
public int Age { get; set; }
public List<int> NumbersList { get; set; }
}
And I have this two jsons (the second one coming out from a conditional serialization trough ShouldSerialize)
var json1 = "{\"Name\":\"Joe\",\"Surname\":\"Satriani\",\"Age\":40,\"NumbersList\":[10,20,30]}";
var json2= "{\"Name\":\"Mike\",\"NumbersList\":[40,50,60]}";
Also, I have a silly class to display the results:
private void showResult(object theClass)
{
var result = JsonConvert.SerializeObject(theClass);
Debug.WriteLine("result: " + result);
}
Now, I create a class with the first json:
var myPerson = JsonConvert.DeserializeObject<Person>(json1);
And everything is fine: the class gets all the values it should:
showResult(myPerson);
result: {"Name":"Joe","Surname":"Satriani","Age":40,"NumbersList":[10,20,30]}
Now, I want to apply the second json to the already existing class instance:
JsonConvert.PopulateObject(json2, myPerson);
But... this is what I get:
showResult(myPerson);
result: {"Name":"Mike","Surname":"Satriani","Age":40,"NumbersList":[10,20,30,40,50,60]}
So, as far as I understand, the PopulateObject correctly rewrites, as expected, the standard field properties (because I don't get "JoeMike" as Name, I get only "Mike" and this if fine), however, it appends list/indexed ones, because I don't obtain "40,50,60" but "10,20,30,40,50,60"...
So, my question is: is there a way to avoid PopulateObject to deliberately append List/Index/Enumerable objects ?
In the JsonSerializerSettings class, set the ObjectCreationHandling value to ObjectCreationHandling.Replace. With this setting, the information is no longer appended but copied.
JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings()
{
ObjectCreationHandling = ObjectCreationHandling.Replace
};
JsonConvert.PopulateObject(json2, myPerson, jsonSerializerSettings);
ObjectCreationHandling setting

How do I use the generated JsonProperty Name = name from JSON file to access a single element in a corresponding C# Class

How do I use the (generated) JsonProperty Name = name from JSON file to access a single element in a corresponding C# Class?
Here is what I am trying to do …
I have a Xamarin “classic” Newtonsoft application where I load a JSON file into a C# class MagicTime.
Here is the first part of my class - This was generated automatically by the newtonsoft web site using my JSON file
public partial class MagicTime
{
[JsonProperty("Accel Delay")]
public long AccelDelay { get; set; }
[JsonProperty("Accel Period")]
public long AccelPeriod { get; set; }
[JsonProperty("Alt DT Step")]
public long AltDtStep { get; set; }
[JsonProperty("Beep On Command")]
public bool BeepOnCommand { get; set; }
[JsonProperty("Bunt Step")]
public long BuntStep { get; set; }
[JsonProperty("Bunt Timeout")]
This is how load/deserialize an instant where loadp is string variable containing the contents of the JSON file
MagicTime MT = JsonConvert.DeserializeObject<MagicTime>(loadp );
This works fine
In the application I modify the values of some data element e.g
Looking at the above – MT.AccelDelay = 21;
I then reverse the process and write /Serialize I out
That work too.
Now I have an new requirement to use the JsonProperty name to access the corresponding C# data item
It the example above I want to use [JsonProperty("Accel Delay")] to access the corresponding c# element MT.AccelDelay.
I have seen examples where a JSON string is loaded into JObject to do this but not my case where is no (that I can see) JObject
You can use Newtonsoft's ContractResolver for this purpose, as it defines how Json.NET maps from c# objects to JSON objects.
First, define the following extension method:
public static partial class JsonExtensions
{
static readonly IContractResolver defaultResolver = new JsonSerializer().ContractResolver;
public static T GetJsonPropertyValue<T>(object obj, string propertyName, IContractResolver resolver = null)
{
resolver = resolver ?? defaultResolver;
var contract = resolver.ResolveContract(obj.GetType());
if (contract is JsonObjectContract objectContract)
{
var property = objectContract.Properties.GetClosestMatchProperty(propertyName);
if (property == null)
throw new JsonException(string.Format("Unknown property {0}", propertyName));
return (T)property.ValueProvider.GetValue(obj);
}
throw new JsonException(string.Format("Invalid contract {0}", contract));
}
}
And now you can do:
var accelDelay = JsonExtensions.GetJsonPropertyValue<long>(MT, "Accel Delay");
If you don't know the type in advance, you can just do:
var accelDelay = JsonExtensions.GetJsonPropertyValue<object>(MT, "Accel Delay");
And if you are using camel casing, do:
var resolver = new CamelCasePropertyNamesContractResolver();
var accelDelay = JsonExtensions.GetJsonPropertyValue<object>(MT, "Accel Delay", resolver);
Notes:
If the incoming obj maps to something other than a JSON object (e.g. an array or primitive) then GetJsonPropertyValue() will throw an exception. It will also throw if the property is set-only.
If you need a way to discover all the JSON property names for a given type, see Get a list of JSON property names from a class to use in a query string, especially this answer.
Demo fiddle here.

Throw exception when deserialize to custom object using newtowsoft when extra field are found [duplicate]

This question already has answers here:
Detect if deserialized object is missing a field with the JsonConvert class in Json.NET
(5 answers)
Closed 5 years ago.
I have simple class:
public class TestObject {
public string Label { get; set; } = string.Empty;
public double Number { get; set; } = 0;
}
I would like to get an instance of TestObject from json. The trick is to allow Label and Number properties be optional, but throw exception if any extra field are added (to avoid mistake like "Lebel").
Code below alway convert to TestObject:
var correctInput = $"{{\"Label\":\"a\", \"Number\":5 }}";
var incorrectInput = $"{{\"Labell\":\"a\", \"Numberr\":5 }}";
JToken obj1 = JsonConvert.DeserializeObject<dynamic>(correctInput);
JToken obj2 = JsonConvert.DeserializeObject<dynamic>(incorrectInput);
var correctResult = obj1.ToObject<TestObject>();
var incorrectResult = obj2.ToObject<TestObject>();
Console.WriteLine($"Label: {correctResult.Label} Number: {correctResult.Number}");
Console.WriteLine($"Label: {incorrectResult.Label} Number: {incorrectResult.Number}");
The output of it will be:
Label: a Number: 5
Label: Number: 0
Only solution which comes to my mind is to define extra field with property [JsonExtensionData] and throw exception to set accessor:
[JsonExtensionData]
private IDictionary<string, JToken> _extraStuff {
get { return _extraStuff1; }
set { throw new Exception("cannot do it");}
}
But it is quite ugly hack.
I think you need to set MissingMemberHandling = MissingMemberHandling.Error
In case Label property in JSON is misspeled as 'Labell'
var incorrectInput = $"{{\"Labell\":\"a\", \"Numberr\":5 }}";
JsonConvert.DeserializeObject<TestObject>(
incorrectInput,
new JsonSerializerSettings() { MissingMemberHandling = MissingMemberHandling.Error });
that will force to throw JsonSerializationException:
'Could not find member 'Labell' on object of type 'TestObject'.
Refer to the Newtonsoft docs for more information # https://www.newtonsoft.com/json/help/html/DeserializeMissingMemberHandling.htm

Deserialize first property not matching any target object's properties into specific property [duplicate]

This question already has answers here:
Deserialize json with known and unknown fields
(5 answers)
Closed 6 years ago.
I'm doing some web API integration with Newtonsoft.Json, and as always, I have to do dumb stunts to properly deserialize what they're sending back.
In this case, the API will send responses resembling this kind of structure:
{ "contacts": [ ... ], "has-more": true, "offset": 38817 }
The "has-more" and "offset" properties are pretty much constant on the different method responses, and have been defined accordingly on the response object that I'm deserializing into. The response object looks something like this:
public class APIResponse {
public JContainer Result { get; set; }
[JsonProperty("has-more")]
public bool HasMore { get; set; }
[JsonProperty("offset")]
public int Offset { get; set; }
}
That first "contacts" property is what can vary; for some methods, I might get "contacts", some might get "companies", and others might get who-knows-what. I also don't have any way to be certain that every response will have such a "variable" property, nor that it will be the first one, positionally speaking.
For this example, what I would like to happen is the deserializer looks at the Json and says, "Let's see, I don't see anything mapping to 'contacts', so we'll put that into 'Result', and then I can see from the JsonProperty attributes that 'has-more' and 'offset' go into HasMore and Offset. Okay, all set, here's your object."
I suspect this involves some tricks with a custom JsonConverter or IContractResolver, but I'm just not connecting the dots here. I tried doing a simple custom contract resolver, but it appears to use contract resolvers to resolve object property names into property names to look for in the JSON text, not vice-versa.
You can use a base class + derivations for each response type.
public class APIResponseBase {
[JsonProperty("has-more")]
public bool HasMore { get; set; }
[JsonProperty("offset")]
public int Offset { get; set; }
}
public class ContactsResponse : APIResponseBase {
public IEnumerable<Contact> Contacts { get; set; }
}
public class CompaniesResponse : APIResponseBase {
public IEnumerable<Company> Companies { get; set; }
}
var contactsResponse = JsonConvert.Deserialize<ContactsResponse>(json);
IEnumerable<Contact> contacts = contactsResponse.Contacts

Serializing published content in umbraco

I am currently writing an api for a custom application my company is writing. Part of this involves getting published content out in JSON format. When I try serializing ipublishedcontent directly it obviously attempts to serialize all of the umbraco data and relations that I simply don't need (in fact it fails with a stack overflow). Is there a way to get just the custom properties from an item of content without specifying the fields?
I am using webapi and passing it objects to serialize itself and I'm using a dynamic to manually specify the fields. The Product type which I'm initially selecting into is from modelsbuilder. My code currently looks a little like this:
public object Get(string keywords = "")
{
// Get Data from Umbraco
var allProducts = Umbraco.TypedContent(1100).Children.Select(x => new Product(x));
if (keywords != "")
{
allProducts = allProducts.Where(x => x.Name.Contains(keywords));
}
return allProducts.Select(x => new
{
id = x.Id,
name = x.Name,
price = x.Price
});
}
It seems to me that there should be a simple way to do this without having to create a dynamic with just the fields I want but I can't work it out. I just don't want to have to change my code every time the document type in umbraco changes!
You can use Ditto to map your data into an object.
Create an object with properties that match the alias's of your fields (case insensitive)
public class Product{
public int id {get;set;}
public string name {get;set;}
public string price {get;set;}
}
Then map a single or collection of IPublishedContent objects using .As
return allProducts.As<Product>();
You can use the UmbracoProperty attribute to specify the alias too if it is different than you need for your json or use the JsonProperty attribute to change the name on serialize.
Take a look at the code in the MemberListView - it does a similar thing while retrieving Members without knowing in advance what the properties on the MemberType will be:
https://github.com/robertjf/umbMemberListView/blob/master/MemberListView/Models/MemberListItem.cs
For example:
[DataContract(Name = "content", Namespace = "")]
public class MemberListItem
{
// The following properties are "known" - common to all IPublishedContent
[DataMember(Name = "id")]
public int Id { get; set; }
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "contentType")]
public IContentType ContentType { get; set; }
// This one contains a list of all other custom properties.
private Dictionary<string, string> properties;
[DataMember(Name = "properties")]
public IDictionary<string, string> Properties
{
get
{
if (properties == null)
properties = new Dictionary<string, string>();
return properties;
}
}
}
MemberListView converts to this from a list of SearchResult using AutoMapper, but you could just as easily map it from IPublishedContent.

Categories

Resources