Search code examples
c#jsonserializationjson.netjsonschema

Generated JSON invalid according to its own schema


I'm generating a schema for my class like this.

JSchemaGenerator generator = new() 
  { ContractResolver = new CamelCasePropertyNamesContractResolver() };
JSchema dtoSchema = generator.Generate(typeof(SomeDto));
File.WriteAllText("dto.schema.json", dtoSchema.ToString());

The classes in the DTO are as follows.

class SomeDto
{
  public Guid Id { get; set; }
  public DateTime Occasion { get; set; }
  public Dictionary<Key, SubDto> Data { get; set; } = default!;
}

enum Key { Donkey, Monkey, Honky }

class SubDto
{
  public string Name { get; set; } = default!;
  public double Value { get; set; }
}

I'm using those to create a serialization on of that structure to the drive.

JsonSerializerOptions options = new()
{
  TypeInfoResolver = new DefaultJsonTypeInfoResolver
  { Modifiers = { JsonPropertyInfoExtensions.AddTypedConverters } },
  PropertyNameCaseInsensitive = true,
  PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
  WriteIndented = true
};
string output = JsonSerializer.Serialize(dto, options);
File.WriteAllText("dto.example.json", output);

Then, elsewhere, at a location where said schema file resides next to the actual JSON file created based on the exactly same DTO, I validate the contents like this.

string data = File.ReadAllText("dto.example.json");
string schema = File.ReadAllText("dto.schema.json");
JObject jsonData = JObject.Parse(data);
JSchema jsonSchema = JSchema.Parse(schema);
bool valid = jsonData.IsValid(jsonSchema, out IList<string> issues);

It tells me it's invalid. The issues mentioned are due to the key type inconsistency. While the announced type in the schema of the key (being an enum) is number, the actual content of the JSON is a string.

Invalid type. Expected Number but got String. Path 'data.Donkey.value', line 7...
Invalid type. Expected Number but got String. Path 'data.Monkey.value', line 11...

As the actual requirement of the consumer goes, I need to have the readable name, not the numeric value. At the moment, I could probably make that change manually altering the schema but that's... baaad. In so many ways...

Is there a way to produce schema knowing that the keys corresponding to the keys will be strings and not numbers?


Solution

  • Not a fan of answering my own questions, I still prefer that over just leaving it as-is.

    The suggestion made in comments pointed out a way to investigate the exact reason(s) of the validation failure. Once found out where it breaks, it was straightforward (if not easy) to resolve the issue.

    Extensions.IsValid(JToken, JsonSchema, out IList<String>)
    

    The last argument, out IList<string> errorMessages will contain error messages explaining where the violations were encountered. (Credit goes to @dbc.)