How to Serialize and Deserialize a giant Trie? [duplicate] - c#

I recently upgraded a solution to be all .NET Core 3 and I have a class that requires the class variables to be fields. This is a problem since the new System.Text.Json.JsonSerializer doesn't support serializing nor deserializing fields but only handles properties instead.
Is there any way to ensure that the two final classes in the example below have the same exact values?
using System.Text.Json;
public class Car
{
public int Year { get; set; } // does serialize correctly
public string Model; // doesn't serialize correctly
}
static void Problem() {
Car car = new Car()
{
Model = "Fit",
Year = 2008,
};
string json = JsonSerializer.Serialize(car); // {"Year":2008}
Car carDeserialized = JsonSerializer.Deserialize<Car>(json);
Console.WriteLine(carDeserialized.Model); // null!
}

In .NET Core 3.x, System.Text.Json does not serialize fields. From the docs:
Fields are not supported in System.Text.Json in .NET Core 3.1. Custom converters can provide this functionality.
In .NET 5 and later, public fields can be serialized by setting JsonSerializerOptions.IncludeFields to true or by marking the field to serialize with [JsonInclude]:
using System.Text.Json;
static void Main()
{
var car = new Car { Model = "Fit", Year = 2008 };
// Enable support
var options = new JsonSerializerOptions { IncludeFields = true };
// Pass "options"
var json = JsonSerializer.Serialize(car, options);
// Pass "options"
var carDeserialized = JsonSerializer.Deserialize<Car>(json, options);
Console.WriteLine(carDeserialized.Model); // Writes "Fit"
}
public class Car
{
public int Year { get; set; }
public string Model;
}
For details see:
How to serialize and deserialize (marshal and unmarshal) JSON in .NET: Include fields.
Issues #34558 and #876.

If you want this for all MvcControllers in API project you can do similar to this in setup:
builder.Services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.IncludeFields = true;
});

Please try this library I wrote as an extension to System.Text.Json to offer missing features: https://github.com/dahomey-technologies/Dahomey.Json.
You will find support for fields.
using System.Text.Json;
using Dahomey.Json
public class Car
{
public int Year { get; set; } // does serialize correctly
public string Model; // will serialize correctly
}
static void Problem() {
JsonSerializerOptions options = new JsonSerializerOptions();
options.SetupExtensions(); // extension method to setup Dahomey.Json extensions
Car car = new Car()
{
Model = "Fit",
Year = 2008,
};
string json = JsonSerializer.Serialize(car, options); // {"Year":2008,"Model":"Fit"}
Car carDeserialized = JsonSerializer.Deserialize<Car>(json);
Console.WriteLine(carDeserialized.Model); // Fit
}

Related

How to use class fields with System.Text.Json.JsonSerializer?

I recently upgraded a solution to be all .NET Core 3 and I have a class that requires the class variables to be fields. This is a problem since the new System.Text.Json.JsonSerializer doesn't support serializing nor deserializing fields but only handles properties instead.
Is there any way to ensure that the two final classes in the example below have the same exact values?
using System.Text.Json;
public class Car
{
public int Year { get; set; } // does serialize correctly
public string Model; // doesn't serialize correctly
}
static void Problem() {
Car car = new Car()
{
Model = "Fit",
Year = 2008,
};
string json = JsonSerializer.Serialize(car); // {"Year":2008}
Car carDeserialized = JsonSerializer.Deserialize<Car>(json);
Console.WriteLine(carDeserialized.Model); // null!
}
In .NET Core 3.x, System.Text.Json does not serialize fields. From the docs:
Fields are not supported in System.Text.Json in .NET Core 3.1. Custom converters can provide this functionality.
In .NET 5 and later, public fields can be serialized by setting JsonSerializerOptions.IncludeFields to true or by marking the field to serialize with [JsonInclude]:
using System.Text.Json;
static void Main()
{
var car = new Car { Model = "Fit", Year = 2008 };
// Enable support
var options = new JsonSerializerOptions { IncludeFields = true };
// Pass "options"
var json = JsonSerializer.Serialize(car, options);
// Pass "options"
var carDeserialized = JsonSerializer.Deserialize<Car>(json, options);
Console.WriteLine(carDeserialized.Model); // Writes "Fit"
}
public class Car
{
public int Year { get; set; }
public string Model;
}
For details see:
How to serialize and deserialize (marshal and unmarshal) JSON in .NET: Include fields.
Issues #34558 and #876.
If you want this for all MvcControllers in API project you can do similar to this in setup:
builder.Services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.IncludeFields = true;
});
Please try this library I wrote as an extension to System.Text.Json to offer missing features: https://github.com/dahomey-technologies/Dahomey.Json.
You will find support for fields.
using System.Text.Json;
using Dahomey.Json
public class Car
{
public int Year { get; set; } // does serialize correctly
public string Model; // will serialize correctly
}
static void Problem() {
JsonSerializerOptions options = new JsonSerializerOptions();
options.SetupExtensions(); // extension method to setup Dahomey.Json extensions
Car car = new Car()
{
Model = "Fit",
Year = 2008,
};
string json = JsonSerializer.Serialize(car, options); // {"Year":2008,"Model":"Fit"}
Car carDeserialized = JsonSerializer.Deserialize<Car>(json);
Console.WriteLine(carDeserialized.Model); // Fit
}

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.

AddNewtonsoftJson is not overriding System.Text.Json

I have upgraded my version of .Net Core from preview 2 to preview 6 which has broken a couple of things. Most significant is that I cannot use newtonsoft JSON anymore.
AddNewtonsoftJson in ConfigureServices seemingly does nothing, and the new Json serializer seems to work on properties only, not fields. It does not see the JSONIgnoreAttribute.
In ConfigureServices (in Startup) I have the line
services.AddMvc(x => x.EnableEndpointRouting = false).AddNewtonsoftJson();
which doesn't seem to be doing what it should. In my application, only properties are serialized, not fields, and the [JSONIgnore] attribute does nothing.
The lack of fields I can work around by promoting all the public fields I need to be properties, but I need to be able to ignore some.
Has anyone else had this? How do I either get the new JSON serializer to ignore some properties and serialize public fields, or go back to Newtonsoft?
System.Text.Json has a JsonIgnore attribute, please see How to ignore properties with System.Text.Json.
In order for it to work you will need to remove the dependency on Newtonsoft.Json and change the namespaces in relevant files to System.Text.Json.Serialization;
Sytem.Text.Json can include fields, but only public ones.
using System.Text.Json;
using System.Text.Json.Serialization;
var json = JsonSerializer.Serialize(new O(), new JsonSerializerOptions() { WriteIndented = true});
Console.WriteLine(json);
class O {
[JsonInclude]
public int publicField = 1;
//[JsonInclude]
//This won't work and throws an exception
//'The non-public property 'privateField' on type 'O' is annotated with 'JsonIncludeAttribute' which is invalid.'
private int privateField = 2;
[JsonIgnore]
public int P1 { get; set;} = 3;
public int P2 { get; set; } = 4;
}
This results in:
{
"P2": 4,
"publicField": 1
}
Alternatively you can use IncludeFields
var json = JsonSerializer.Serialize(new O(), new JsonSerializerOptions() { IncludeFields = true});
(Reference: Include fields)

Newtonsoft JsonSerializer - Lower case properties and dictionary [duplicate]

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

How to send correct JSON to Sharepoint 2013?

I'm new to the REST/JSON interface.
I'm working in VS 2013 C#, Framework is 4.5.
Right now I've successfully created items on a list in Sharepoint, using a JSON payload similar to this:
{ '__metadata': { 'type': 'SP.Data.ABCs_x0020_for_x0020_TAC_x0020_SiebelListItem' },
'Priority':'A',
'Requirements_x0020_Status':'Fully Documented',
'Status':'Under Consideration',
'Description':'This is a test',
'ABC_x0020_Type':'Enhancement',
'Title':'Testing: 921253434',
'Business_x0020_Unit_x0020_Affect':'TAC',
'AssignedToId':'1',
'Submitted_x0020_by':'sdsd',
'Applies_x0020_To':'Screens/Views',
'Screen_x002f_View_x002f_Module':'CSR'}
I was manually creating the JSON payload and decided to try out some objects that might help with the Serialization/Deserialization.
Here is the code:
ABCItem item = new ABCItem();
item.Title = "Testing " + ran.Next();
item.ABC_x0020_Type = "Enchancement";
item.Applies_x0020_To = "Screens/View";
item.Priority = "A";
item.Requirements_x0020_Status = "Fully Documented";
item.Screen_x002f_View_x002f_Module = "CSR";
item.Business_x0020_Unit_x0020_Affect = "TAC";
item.Submitted_x0020_by = "Brian Hintze";
item.Status = "Under Consideration";
item.AssignedToId = 1;
item.Description = "The quick brown fox jumped over the lazy dog and then drank a pint of beer.";
string json = JsonConvert.SerializeObject(item);
Unfortunately I can't figure out how to get the __metadata part of the JSON payload to get added correctly. I've tried this
item.__metadata = "{ 'type': 'SP.Data.ABCs_x0020_for_x0020_TAC_x0020_SiebelListItem' }";
But that didn't work.
I've tried fiddling around the MetaDataSettings, but so far I can't figure out the right combination.
string json = JsonConvert.SerializeObject(item,new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
// $type no longer needs to be first
MetadataPropertyHandling = MetadataPropertyHandling.Default
});
Any help would be appreciated. I'm sure it is something fairly basic that I'm missing.
thanks,
lee
The JSON serializer will convert objects to JavaScript objects.
Instead of making item.__metadata a string value, try making it an object with a member property called Type that equals "SP.Data.ABCs_x0020_for_x0020_TAC_x0020_SiebelListItem".
You probably want to make the property __metadata be a reference to its own class. After all, this is a complex json object.
Using json2csharp.com 1 you can see that your ABCItem class should look like
public class Metadata
{
public string type { get; set; }
}
public class ABCItem
{
public Metadata __metadata { get; set; }
public string Priority { get; set; }
(...)
}

Categories

Resources