We are working on a .Net core based web api application and for this we have a requirement to validate incoming request body which is JSON
format against the c# based type.
We are at this point evaluating NJsonSchema
library to see if it throws duplicate property error.
But looks like it doesnt support this validation. We also checked JSON
schema validator from NewtonSoft
but seems like it doesnt support duplicate property validations either.
Below is the minimized code using NJsonSchema
that we use -
using NewtonSoft.Json;
public class MyRequest
{
[JsonRequired]
[JsonProperty("name")]
public string Name { get; set; }
}
and when we pass a JSON object like this -
{"name":"abc","name":"xyz"}
We need our JSON validator to throw error for duplicate property
Our example test looks like this -
[Test]
public async System.Threading.Tasks.Task SchemaValidation_WithDuplicateProperty_Async()
{
var jsonString = await File.ReadAllTextAsync("Data//JsonWithDuplicateProperty.json");
var schema = JsonSchema.FromType<MyRequest>();
var errors = schema.Validate(jsonString);
Assert.That(errors.Count(), Is.EqualTo(1));
}
So my question - Has anyone done this in the past? Or are there any libraries for .net core
that provides JSON
validation for duplicate properties and/or can this be done using NJsonSchema
or NewtonSoft
.
As @zaggler notes, using Newtonsoft, you can use the DuplicatePropertyNameHandling
enum. Unfortunately, you can't use it directly in a a call to DeserializeObject
(in the JsonSerializerSettings
); it has to be used in a JToken Reader. See this discussion thread for more details:
https://github.com/JamesNK/Newtonsoft.Json/issues/931
Here is a method that wraps the action up in a DeserializeObject
-esque way:
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.IO;
public class Program
{
public static void Main()
{
var json = @"{""name"":""abc"",""name"":""xyz""}";
var objA = DeserializeObject<MyRequest>(json, new JsonSerializerSettings(), DuplicatePropertyNameHandling.Ignore);
Console.WriteLine(".Ignore: " + objA.Name);
var objB = DeserializeObject<MyRequest>(json, new JsonSerializerSettings(), DuplicatePropertyNameHandling.Replace);
Console.WriteLine(".Replace: " + objB.Name);
var objC = DeserializeObject<MyRequest>(json, new JsonSerializerSettings(), DuplicatePropertyNameHandling.Error);
Console.WriteLine(".Error: " + objC.Name); // throws error before getting here
}
public static T DeserializeObject<T>(string json, JsonSerializerSettings settings, DuplicatePropertyNameHandling duplicateHandling)
{
JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
using (var stringReader = new StringReader(json))
using (var jsonTextReader = new JsonTextReader(stringReader))
{
jsonTextReader.DateParseHandling = DateParseHandling.None;
JsonLoadSettings loadSettings = new JsonLoadSettings {
DuplicatePropertyNameHandling = duplicateHandling
};
var jtoken = JToken.ReadFrom(jsonTextReader, loadSettings);
return jtoken.ToObject<T>(jsonSerializer);
}
}
}
public class MyRequest
{
[JsonRequired]
[JsonProperty("name")]
public string Name { get; set; }
}
Output:
.Ignore: abc
.Replace: xyz
Run-time exception (line 31): Property with the name 'name' already exists in the current JSON object. Path 'name', line 1, position 21.
See: