I don't believe the JSON Schema standard supports a "rectangular array" constraint, see How to define a two-dimensional rectangular array in JSON Schema? for confirmation. The fact that Json.NET schema generates a 1d array schema for a 2d array seems like a pure bug.
As a workaround, using a custom JSchemaGenerationProvider
, you could generate an N-dimensional jagged array schema for an N-dimensional multidimensional array. Such a schema would not capture the constraint that the rows all have the same length, but it would at least capture the correct array nesting depth.
First, define the following JSchemaGenerationProvider
:
public class MultidimensionalArraySchemaProvider : JSchemaGenerationProvider
{
public override JSchema GetSchema(JSchemaTypeGenerationContext context)
{
if (CanGenerateSchema(context))
{
// Create a jagged N-d array type.
var type = context.ObjectType.GetElementType().MakeArrayType();
for (int i = context.ObjectType.GetArrayRank(); i > 1; i--)
// Disallow null array items for outer arrays
// context.Generator.DefaultRequired controls whether null is allowed for innermost array items.
type = typeof(ArrayRow<>).MakeGenericType(type);
// Return a schema for the jagged N-d array type.
return context.Generator.Generate(type);
}
else
throw new NotImplementedException();
}
public override bool CanGenerateSchema(JSchemaTypeGenerationContext context) =>
context.ObjectType.IsArray && context.ObjectType.GetArrayRank() > 1;
}
[JsonArray(AllowNullItems = false)]
class ArrayRow<T> : List<T> { }
Then, if your class looks like:
public class MyClass
{
public int[,] MyProperty { get; set; }
public string[,,,] MyProperty4D { get; set; }
}
You can do:
var generator = new JSchemaGenerator();
generator.GenerationProviders.Add(new MultidimensionalArraySchemaProvider());
var schema = generator.Generate(typeof(MyClass));
With the result:
{
"type": "object",
"properties": {
"MyProperty": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "integer"
}
}
},
"MyProperty4D": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": [
"string",
"null"
]
}
}
}
}
}
},
"required": [
"MyProperty",
"MyProperty4D"
]
}
Demo fiddle here.
Related questions: