Your Note class needs a parameterless constructor
class Note
{
public DateTime currentDate { get; set; }
public string summary { get; set; }
// add this
public Note()
{
}
public Note(DateTime _date, string _sum)
{
currentDate = _date;
summary = _sum;
}
}
It might be worth thinking if you need your original two parameter constructor. If you removed it, then you could instantiate a new Note like this
var completeNote = new Note
{
currentdate = date,
summary = givenNote
};
Answer from Kevin Brydon on Stack OverflowSystem.Text.Json failure to deserialize strongly typed models from string
System.Text.Json fails to deserialize into a model with an ImmutableList property.
c# - System.Text.Json.deserialize Json String - Stack Overflow
Check if json string can be deserialized into specific class
Videos
Don't know why you want to use the JsonNode.Parse().
If you just want to modify the location's value, maybe you can use the JsonSerializer with BookStore and Book class to help you.
The Book class is a IEnumerable property of BookStore.
an example by .NET6 Console App
BookClass is a 2-level nested class
// See https://aka.ms/new-console-template for more information
using System.Text.Json;
// Initialize json string
string jsonStr = "{\"id\": 1, \"ShopName\" :\"Paint Shop\", \"Books\" : [\r\n {\r\n \"bookId\":1,\r\n \"bookName\":\"Peter Pan\",\r\n \"location\":\"A01\"\r\n },\r\n {\r\n \"bookId\":2,\r\n \"bookName\":\"Cooking Book\",\r\n \"location\":\"A02\"\r\n }\r\n ]\r\n }";
// Deserilize to object
Bookstore bookstore = JsonSerializer.Deserialize<Bookstore>(jsonStr);
// Write the location's value
Console.WriteLine(bookstore.Books.ToArray()[1].location);
// Modified the location's value
bookstore.Books.ToArray()[1].location += "_Modified";
// Write the modified location's value
Console.WriteLine(bookstore.Books.ToArray()[1].location);
// See result output
Console.ReadLine();
public class Bookstore
{
public int id { get; set; }
public string ShopName { get; set; }
public IEnumerable<Book> Books { get; set; }
}
public class Book
{
public int bookId { get; set; }
public string bookName { get; set; }
public string location { get; set; }
}
Result output image

If you persist to use JsonNode.Parse(), then need more steps. like this.
// See https://aka.ms/new-console-template for more information
using System.Text.Json;
using System.Text.Json.Nodes;
// Initialize json string
string jsonStr = "{\"id\": 1, \"ShopName\" :\"Paint Shop\", \"Books\" : [\r\n {\r\n \"bookId\":1,\r\n \"bookName\":\"Peter Pan\",\r\n \"location\":\"A01\"\r\n },\r\n {\r\n \"bookId\":2,\r\n \"bookName\":\"Cooking Book\",\r\n \"location\":\"A02\"\r\n }\r\n ]\r\n }";
// Parse to jsonNode
JsonNode jsonNode = JsonNode.Parse(jsonStr);
// Convert to JsonObject
JsonObject jsonObject = jsonNode.AsObject();
// Convert Books to Json Array
JsonArray jsonArray = jsonObject["Books"].AsArray();
// Convert index 1 in array to Json object
JsonObject book1Object = jsonArray[1].AsObject();
// Write the location value
Console.WriteLine(book1Object["location"]);
// Modify location value
book1Object["location"] += "_modified";
// Write the modified location value
Console.WriteLine(book1Object["location"]);
// See output
Console.ReadLine();
public class Bookstore
{
public int id { get; set; }
public string ShopName { get; set; }
public IEnumerable<Book> Books { get; set; }
}
public class Book
{
public int bookId { get; set; }
public string bookName { get; set; }
public string location { get; set; }
}
Other suggestion
Use Newtonsoft.Json is better. Because when convert a json to a C# object, will need to convert many properties with different value type.
The Newtonsoft.Json had already handle these situation, at the mean time the System.Text.Json does not.
You can use JObject to modify json directly
var jObject = JObject.Parse(json);
jObject["Books"][1]["location"] = "new value";
Result:

Note:
You should add Newtonsoft.Json package.
So I have a json string like:
"{\"thisisnorthecorrectname\":\"Value1\"}"Now I want to use System.Text.Json to check if this string can be deserialized into this class:
internal class Test {
public string Name { get; set; }
}I have tried with a method like this:
static bool CanDeserialize<T>(string jsonString, out T deserializedObject) {
deserializedObject = default;
try {
deserializedObject = JsonSerializer.Deserialize<T>(jsonString);
return true;
}
catch (JsonException) {
return false;
}
}But this does not throw an Exception. Instead it gives me a class object where the property name is NULL.
How can I check if the json string can be deserialized properly into a class?
@Victor LG's answer using Newtonsoft is close, but it doesn't technically avoid the a catch as the original poster requested. It just moves it elsewhere. Also, though it creates a settings instance to enable catching missing members, those settings aren't passed to the DeserializeObject call so they are actually ignored.
Here's a "catch free" version of his extension method that also includes the missing members flag. The key to avoiding the catch is setting the Error property of the settings object to a lambda which then sets a flag to indicate failure and clears the error so it doesn't cause an exception.
public static bool TryParseJson<T>(this string @this, out T result)
{
bool success = true;
var settings = new JsonSerializerSettings
{
Error = (sender, args) => { success = false; args.ErrorContext.Handled = true; },
MissingMemberHandling = MissingMemberHandling.Error
};
result = JsonConvert.DeserializeObject<T>(@this, settings);
return success;
}
Here's an example to use it:
if(value.TryParseJson(out MyType result))
{
// Do something with result…
}
With Json.NET you can validate your json against a schema:
string schemaJson = @"{
'status': {'type': 'string'},
'error': {'type': 'string'},
'code': {'type': 'string'}
}";
JsonSchema schema = JsonSchema.Parse(schemaJson);
JObject jobj = JObject.Parse(yourJsonHere);
if (jobj.IsValid(schema))
{
// Do stuff
}
And then use that inside a TryParse method.
public static T TryParseJson<T>(this string json, string schema) where T : new()
{
JsonSchema parsedSchema = JsonSchema.Parse(schema);
JObject jObject = JObject.Parse(json);
return jObject.IsValid(parsedSchema) ?
JsonConvert.DeserializeObject<T>(json) : default(T);
}
Then do:
var myType = myJsonString.TryParseJson<AwsomeType>(schema);
Update:
Please note that schema validation is no longer part of the main Newtonsoft.Json package, you'll need to add the Newtonsoft.Json.Schema package.
Update 2:
As noted in the comments, "JSONSchema" have a pricing model, meaning it isn't free. You can find all the information here
I've had a look at your fiddle and spotted a couple of problems. Working fiddle here
System.Text.Jsonis case-sensitive by default (except for web apps). You can resolve this by using eitherPropertyNamingPolicy = JsonNamingPolicy.CamelCaseorPropertyNameCaseInsensitive = truein the serializer options.The second issue is outlined in Enums as strings
By default, enums are serialized as numbers. To serialize enum names as strings, use the JsonStringEnumConverter.
You should add
JsonSerializerOptionsto resolve (1) and (2):var options = new JsonSerializerOptions { Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) }, PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; var items = JsonSerializer.Deserialize<List<MenuItem>>(json, options);The third issue appears to be with the binding in the constructor for the list of
Permissions. In the constructor you define aList<Permission>for the permissions parameter. I receive the error in your question unless the constructor argument type matches the model property type exactly. So, I updated the constructor to take aIReadOnlyList<Permission>and it deserializes successfully:[JsonConstructor] public MenuItem ( string name, string url, IReadOnlyList<Permission> permissions ) { this.Name = name; this.Url = url; this.Permissions = permissions ?? new List<Permission>().AsReadOnly(); }Alternatively, you could change the
Permissionsproperty toList<Permission>.
This answer to a question with a similar problem explains that this is actually a limitation of System.Text.Json and there is currently an open github issue.
A working fork of your fiddle is demoed here.
I had the same issue. The solution is to use
JsonSerializable
attribute of
System.Text.Json.Serialization
It looks like:
[JsonSerializable(typeof(YourClassName))]
public class YourClassName
{
public byte YourPropertyName { get; set; }
}
Always class and always public and always properties and always use the attribute on the class.
The new
System.Text.Jsonapi exposes aJsonConverterapi which allows us to convert the type as we like.For example, we can create a generic
numbertostringconverter:public class AutoNumberToStringConverter : JsonConverter<object> { public override bool CanConvert(Type typeToConvert) { return typeof(string) == typeToConvert; } public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if(reader.TokenType == JsonTokenType.Number) { return reader.TryGetInt64(out long l) ? l.ToString(): reader.GetDouble().ToString(); } if(reader.TokenType == JsonTokenType.String) { return reader.GetString(); } using(JsonDocument document = JsonDocument.ParseValue(ref reader)){ return document.RootElement.Clone().ToString(); } } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) { writer.WriteStringValue( value.ToString()); } }When working with MVC/Razor Page, we can register this converter in startup:
services.AddControllersWithViews().AddJsonOptions(opts => { opts.JsonSerializerOptions.PropertyNameCaseInsensitive= true; opts.JsonSerializerOptions.Converters.Insert(0, new AutoNumberToStringConverter()); });and then the MVC/Razor will handle the type conversion automatically.
Or if you like to control the serialization/deserialization manually:
var opts = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, }; opts.Converters.Add(new AutoNumberToStringConverter()); var o = JsonSerializer.Deserialize<Product>(json,opts) ;In a similar way you can enable string to number type conversion as below :
public class AutoStringToNumberConverter : JsonConverter<object> { public override bool CanConvert(Type typeToConvert) { // see https://stackoverflow.com/questions/1749966/c-sharp-how-to-determine-whether-a-type-is-a-number switch (Type.GetTypeCode(typeToConvert)) { case TypeCode.Byte: case TypeCode.SByte: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.Decimal: case TypeCode.Double: case TypeCode.Single: return true; default: return false; } } public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if(reader.TokenType == JsonTokenType.String) { var s = reader.GetString() ; return int.TryParse(s,out var i) ? i : (double.TryParse(s, out var d) ? d : throw new Exception($"unable to parse {s} to number") ); } if(reader.TokenType == JsonTokenType.Number) { return reader.TryGetInt64(out long l) ? l: reader.GetDouble(); } using(JsonDocument document = JsonDocument.ParseValue(ref reader)){ throw new Exception($"unable to parse {document.RootElement.ToString()} to number"); } } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) { var str = value.ToString(); // I don't want to write int/decimal/double/... for each case, so I just convert it to string . You might want to replace it with strong type version. if(int.TryParse(str, out var i)){ writer.WriteNumberValue(i); } else if(double.TryParse(str, out var d)){ writer.WriteNumberValue(d); } else{ throw new Exception($"unable to parse {str} to number"); } } }
If you only want to deserialize strings as numbers, you could simply set the NumberHandling property to AllowReadingFromString in the options:
var o = JsonSerializer.Deserialize<Product>(json, new JsonSerializerOptions
{
// [...]
NumberHandling = JsonNumberHandling.AllowReadingFromString
});
Note: This will automatically deserialize strings as numbers, but not numbers as string. If you need more advanced logic, you will need a custom converter (see other answers).