I am trying to deserialize JSON into an object so I can add it to elastic search. JSON can be of many different object types in the project so I would like the function to be dynamic.
First I am serializing the Data that I get from EF Core context
var serializedObject = JsonConvert.SerializeObject(document, Formatting.None,
new JsonSerializerSettings()
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});
Next I would like to deserialize to an object. For example if I have
public class EValues
{
public dynamic values { get; set; }
}
var test = JsonConvert.DeserializeObject<EValues>(serializedObject.ToString());
I would like the JSON to be deserialized to the below:
{
"values":{
"StudentId":"60712555-ff1d-4a3e-8c81-08d9c2fc4423",
"Student":{
"Name":"string",
"Country":"string",
"Street":"string"
}
}
}
The serializedObject JSON I am actually trying to deserialize:
{
"StudentId":"60712555-ff1d-4a3e-8c81-08d9c2fc4423",
"Student":{
"Name":"string",
"Country":"string",
"Street":"string"
}
}
You can just do:
var test = new EValues {
values = JsonConvert.DeserializeObject<dynamic>(serializedObject)
};
The JSON that would correspond to EValues would have an extra level of nesting { "values" : {} } not present in your serializedObject JSON.
I'm consuming some simple stock data in the form of JSON and plotting it on a chart. All works fine, except that some entries return NULL values because at that particular minute in time no trades were taken and therefore no price data is available. This creates gaps on the chart line.
So if the "close" value is null, I want to exclude the entire block including the "minute" and "volume" from being added into the ObservableCollection, and just move on to include the next one whose values are not null. Example JSON:
{
"minute": "10:21",
"close": null,
"volume": 0,
},{
"minute": "10:22",
"close": 47.56,
"volume": 6,
}
I have created a jsonSettings property which I have seen people talk about and claim work, yet it is not working. The code looks like this:
var jsonSettings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
MissingMemberHandling = MissingMemberHandling.Ignore
};
string content = await _client.GetStringAsync(url);
var json_Data = JsonConvert.DeserializeObject<ObservableCollection<ChartData>>(content,jsonSettings);
viewModel.LineData = json_Data;
And here are my models:
public class ChartData
{
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string minute { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public double? close { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public int volume { get; set; }
}
public class ViewModel
{
public ObservableCollection<ChartData> LineData { get; set; }
public ViewModel()
{
LineData = new ObservableCollection<ChartData>();
}
}
I have tried numerous similar examples posted here and there and yet the null-value entries remain within the json_Data. Any ideas how to make it work?
Thanks!
NullValueHandling.Ignore will ignore null values for the relevant property of your model when serializing.
When deserialzing, you might consider deserializing to an IEnumerable<ChartData> then using Linq to filter out the objects you don't want, based on what is, after all, custom logic: "exclude objects that have close == null".
E.g. (untested air code):
var data = JsonConvert.DeserializeObject<IEnumerable<ChartData>>(content,jsonSettings)
.Where(cd => cd.close != null)
;
var observableData = new ObservableCollection<ChartData>(data);
I believe the serialize settings are more applicable when you're "serializing", and you want to not generate JSON for properties of a class when the value is null. In this case you're deserializing, so the JSON is as it is.
Regardless, if you need to exclude this entire object because "close" is null, it doesn't matter if the property is excluded or not, you still need to check for it. What I would do as #Jason was eluding to, would be to filter separately. Something like this:
JArray json = JArray.Parse(#"
[{
""minute"": ""10:21"",
""close"": null,
""volume"": 0,
},{
""minute"": ""10:22"",
""close"": 47.56,
""volume"": 6,
}]
");
var filteredJson = json.Where(j => j["close"].Value<double?>() != null);
I deserialize JSON file into my Entity Classes. for simplify, Let's assume these are my classes
public class Result{
...
public List<Sens> senses { get; set; }
}
public class Sens{
...
public Object definition { get; set; }
}
After I deserialize my JSON into a Result Object I insert to database. There is no error and I can insert Result and Senses with no conflict. But when I call Result from the database with LINQ query like this I get the Result object but my senses come null.
Question 1 Why and how can I solve it
var results =(from r in db.Results
where r.headword == Id
select r).ToList();
I try to add my senses to Result like this
foreach (Result item in resultmodel.Results)
{
item.senses = (from s in db.Senses
join r in db.Results on s.res equals r
where r.Id_ == item.Id_
select s).ToList();
}
I can add but when I try to show senses from my view I get
System.Collections.Generic.List`1[System.String]
But I am waiting it would be a string
Question 2 what is wrong with my approach.
There will be no problem if you convert your JSON string to the c# object. But in return, you want to map a string to object. What is that object? What are the properties? C# doesn't know anything about it.
One of my projects, I had a similar issue while writing and reading from Redis Cache server.
I added type definitions while serializing the object and deserialized with these types.
Serialize:
var jsonString = JsonConvert.SerializeObject(item, _settings);
return Encoding.UTF8.GetBytes(jsonString);
Deserialize:
JsonConvert.DeserializeObject<T>(jsonString, _settings);
Settings:
private static readonly JsonSerializerSettings _settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
Formatting = Formatting.None,
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
}
I hope this helps.
Given the following classes:
class Report {
public Report() {
this.Fields=new List<Field>();
}
[JsonProperty("fields")]
public IList<Field> Fields { get; private set; }
}
class Field {
[JsonProperty("identifier")]
public Guid Identfier { get;set; }
[JsonProperty("name")]
public string Name { get;set; }
}
and the following test method set up:
var report = new Report();
report.Fields.Add(new Field { Identifier = new Guid("26a94eab-3d50-4330-8203-e7750abaa060"), Name = "Field 1" });
report.Fields.Add(new Field { Identifier = new Guid("852107db-b5d1-4344-9f71-7bd90b96fec0"), Name = "Field 2" });
var json = "{\"fields\":[{\"identifier\":\"852107db-b5d1-4344-9f71-7bd90b96fec0\",\"name\":\"name changed\"},{\"identifier\":\"ac424aff-22b5-4bf3-8232-031eb060f7c2\",\"name\":\"new field\"}]}";
JsonConvert.PopulateObject(json, report);
Assert.IsTrue(report.Fields.Count == 2, "The number of fields was incorrect.");
How do I get JSON.Net to know that the field with identifier "852107db-b5d1-4344-9f71-7bd90b96fec0" should apply to the existing field with the same identifier?
Also, is it possible to get JSON.Net to remove items that do not exist within the given JSON array, (specifically the field with identifier "26a94eab-3d50-4330-8203-e7750abaa060" should be removed because it does not exist in the given json array.
If there is a way to manually code or override the way that JSON analyses a list then that would be better because I could write the code to say "this is the item you need" or "use this newly created item" or just "don't do anything to this item because I have removed it". Anyone know of a way I can do this please?
You can use the option ObjectCreationHandling = ObjectCreationHandling.Replace.
You can do this for your entire data model using serializer settings, as is shown in Json.Net PopulateObject Appending list rather than setting value:
var serializerSettings = new JsonSerializerSettings {ObjectCreationHandling = ObjectCreationHandling.Replace};
JsonConvert.PopulateObject(json, report, serializerSettings);
Or, you can set the option on the JsonProperty attribute you are already using if you don't want to do this universally:
class Report
{
public Report()
{
this.Fields = new List<Field>();
}
[JsonProperty("fields", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public IList<Field> Fields { get; private set; }
}
I am using Json.NET to serialize a class to JSON.
I have the class like this:
class Test1
{
[JsonProperty("id")]
public string ID { get; set; }
[JsonProperty("label")]
public string Label { get; set; }
[JsonProperty("url")]
public string URL { get; set; }
[JsonProperty("item")]
public List<Test2> Test2List { get; set; }
}
I want to add a JsonIgnore() attribute to Test2List property only when Test2List is null. If it is not null then I want to include it in my json.
An alternate solution using the JsonProperty attribute:
[JsonProperty(NullValueHandling=NullValueHandling.Ignore)]
// or
[JsonProperty("property_name", NullValueHandling=NullValueHandling.Ignore)]
// or for all properties in a class
[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)]
As seen in this online doc.
As per James Newton King: If you create the serializer yourself rather than using JavaScriptConvert there is a NullValueHandling property which you can set to ignore.
Here's a sample:
JsonSerializer _jsonWriter = new JsonSerializer {
NullValueHandling = NullValueHandling.Ignore
};
Alternatively, as suggested by #amit
JsonConvert.SerializeObject(myObject,
Newtonsoft.Json.Formatting.None,
new JsonSerializerSettings {
NullValueHandling = NullValueHandling.Ignore
});
JSON.NET also respects the EmitDefaultValue property on DataMemberAttribute, in case you don't want to add Newtonsoft-specific attributes to your model:
[DataMember(Name="property_name", EmitDefaultValue=false)]
You can write: [JsonProperty("property_name",DefaultValueHandling = DefaultValueHandling.Ignore)]
It also takes care of not serializing properties with default values (not only null). It can be useful for enums for example.
You can do this to ignore all nulls in an object you're serializing, and any null properties won't then appear in the JSON
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.NullValueHandling = NullValueHandling.Ignore;
var myJson = JsonConvert.SerializeObject(myObject, settings);
In my case, using .NET 6 this was the solution:
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
More info here.
As can be seen in this link on their site (http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size.aspx) I support using [Default()] to specify default values
Taken from the link
public class Invoice
{
public string Company { get; set; }
public decimal Amount { get; set; }
// false is default value of bool
public bool Paid { get; set; }
// null is default value of nullable
public DateTime? PaidDate { get; set; }
// customize default values
[DefaultValue(30)]
public int FollowUpDays { get; set; }
[DefaultValue("")]
public string FollowUpEmailAddress { get; set; }
}
Invoice invoice = new Invoice
{
Company = "Acme Ltd.",
Amount = 50.0m,
Paid = false,
FollowUpDays = 30,
FollowUpEmailAddress = string.Empty,
PaidDate = null
};
string included = JsonConvert.SerializeObject(invoice,
Formatting.Indented,
new JsonSerializerSettings { });
// {
// "Company": "Acme Ltd.",
// "Amount": 50.0,
// "Paid": false,
// "PaidDate": null,
// "FollowUpDays": 30,
// "FollowUpEmailAddress": ""
// }
string ignored = JsonConvert.SerializeObject(invoice,
Formatting.Indented,
new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });
// {
// "Company": "Acme Ltd.",
// "Amount": 50.0
// }
In .Net Core this is much easier now. In your startup.cs just add json options and you can configure the settings there.
public void ConfigureServices(IServiceCollection services)
....
services.AddMvc().AddJsonOptions(options =>
{
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
});
With Json.NET
public class Movie
{
public string Name { get; set; }
public string Description { get; set; }
public string Classification { get; set; }
public string Studio { get; set; }
public DateTime? ReleaseDate { get; set; }
public List<string> ReleaseCountries { get; set; }
}
Movie movie = new Movie();
movie.Name = "Bad Boys III";
movie.Description = "It's no Bad Boys";
string ignored = JsonConvert.SerializeObject(movie,
Formatting.Indented,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
The result will be:
{
"Name": "Bad Boys III",
"Description": "It's no Bad Boys"
}
With System.Text.Json and .NET Core 3.0 this worked for me:
var jsonSerializerOptions = new JsonSerializerOptions()
{
IgnoreNullValues = true
};
var myJson = JsonSerializer.Serialize(myObject, jsonSerializerOptions );
An adaption to #Mrchief's / #amit's answer, but for people using VB
Dim JSONOut As String = JsonConvert.SerializeObject(
myContainerObject,
New JsonSerializerSettings With {
.NullValueHandling = NullValueHandling.Ignore
}
)
See:
"Object Initializers: Named and Anonymous Types (Visual Basic)"
https://msdn.microsoft.com/en-us/library/bb385125.aspx
Or just by setting like this.
services.AddMvc().AddJsonOptions(options =>
options.JsonSerializerOptions.IgnoreNullValues = true;
});
To expound slightly on GlennG's very helpful answer (translating the syntax from C# to VB.Net is not always "obvious") you can also decorate individual class properties to manage how null values are handled. If you do this don't use the global JsonSerializerSettings from GlennG's suggestion, otherwise it will override the individual decorations. This comes in handy if you want a null item to appear in the JSON so the consumer doesn't have to do any special handling. If, for example, the consumer needs to know an array of optional items is normally available, but is currently empty...
The decoration in the property declaration looks like this:
<JsonPropertyAttribute("MyProperty", DefaultValueHandling:=NullValueHandling.Include)> Public Property MyProperty As New List(of String)
For those properties you don't want to have appear at all in the JSON change :=NullValueHandling.Include to :=NullValueHandling.Ignore.
By the way - I've found that you can decorate a property for both XML and JSON serialization just fine (just put them right next to each other). This gives me the option to call the XML serializer in dotnet or the NewtonSoft serializer at will - both work side-by-side and my customers have the option to work with XML or JSON. This is slick as snot on a doorknob since I have customers that require both!
Here's an option that's similar, but provides another choice:
public class DefaultJsonSerializer : JsonSerializerSettings
{
public DefaultJsonSerializer()
{
NullValueHandling = NullValueHandling.Ignore;
}
}
Then, I use it like this:
JsonConvert.SerializeObject(postObj, new DefaultJsonSerializer());
The difference here is that:
Reduces repeated code by instantiating and configuring JsonSerializerSettings each place it's used.
Saves time in configuring every property of every object to be serialized.
Still gives other developers flexibility in serialization options, rather than having the property explicitly specified on a reusable object.
My use-case is that the code is a 3rd party library and I don't want to force serialization options on developers who would want to reuse my classes.
Potential drawbacks are that it's another object that other developers would need to know about, or if your application is small and this approach wouldn't matter for a single serialization.
This does not exactly answer the original question, but may prove useful depending on the use case. (And since I wound up here after my search, it may be useful for others.)
In my most recent experience, I'm working with a PATCH api. If a property is specified but with no value given (null/undefined because it's js), then the property and value are removed from the object being patched. So I was looking for a way to selectively build an object that could be serialized in such a way that this would work.
I remembered seeing the ExpandoObject, but never had a true use case for it until today. This allows you to build an object dynamically, so you won't have null properties unless you want them there.
Here is a working fiddle, with the code below.
Results:
Standard class serialization
noName: {"Name":null,"Company":"Acme"}
noCompany: {"Name":"Fred Foo","Company":null}
defaultEmpty: {"Name":null,"Company":null}
ExpandoObject serialization
noName: {"Company":"Acme"}
noCompany: {"name":"Fred Foo"}
defaultEmpty: {}
Code:
using Newtonsoft.Json;
using System;
using System.Dynamic;
public class Program
{
public static void Main()
{
SampleObject noName = new SampleObject() { Company = "Acme" };
SampleObject noCompany = new SampleObject() { Name = "Fred Foo" };
SampleObject defaultEmpty = new SampleObject();
Console.WriteLine("Standard class serialization");
Console.WriteLine($" noName: { JsonConvert.SerializeObject(noName) }");
Console.WriteLine($" noCompany: { JsonConvert.SerializeObject(noCompany) }");
Console.WriteLine($" defaultEmpty: { JsonConvert.SerializeObject(defaultEmpty) }");
Console.WriteLine("ExpandoObject serialization");
Console.WriteLine($" noName: { JsonConvert.SerializeObject(noName.CreateDynamicForPatch()) }");
Console.WriteLine($" noCompany: { JsonConvert.SerializeObject(noCompany.CreateDynamicForPatch()) }");
Console.WriteLine($" defaultEmpty: { JsonConvert.SerializeObject(defaultEmpty.CreateDynamicForPatch()) }");
}
}
public class SampleObject {
public string Name { get; set; }
public string Company { get; set; }
public object CreateDynamicForPatch()
{
dynamic x = new ExpandoObject();
if (!string.IsNullOrWhiteSpace(Name))
{
x.name = Name;
}
if (!string.IsNullOrEmpty(Company))
{
x.Company = Company;
}
return x;
}
}
.Net 6 -
Add the code in Program.cs. This will ignore the class or record property if it is null.
using System.Text.Json.Serialization;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers()
.AddJsonOptions(opts =>
{
var enumConverter = new JsonStringEnumConverter();
opts.JsonSerializerOptions.Converters.Add(enumConverter);
opts.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault | JsonIgnoreCondition.WhenWritingNull;
});
var settings = new JsonSerializerSettings();
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
settings.NullValueHandling = NullValueHandling.Ignore;
//you can add multiple settings and then use it
var bodyAsJson = JsonConvert.SerializeObject(body, Formatting.Indented, settings);