diff --git a/build/04_RunTests.bat b/build/04_RunTests.bat
index 7a7369efd..c3179c101 100644
--- a/build/04_RunTests.bat
+++ b/build/04_RunTests.bat
@@ -1,3 +1,4 @@
+dotnet test "%~dp0/../src\NJsonSchema.Benchmark\NJsonSchema.Benchmark.csproj" -c Release || goto :error
dotnet test "%~dp0/../src\NJsonSchema.Tests\NJsonSchema.Tests.csproj" -c Release || goto :error
dotnet test "%~dp0/../src\NJsonSchema.CodeGeneration.Tests\NJsonSchema.CodeGeneration.Tests.csproj" -c Release || goto :error
dotnet test "%~dp0/../src\NJsonSchema.CodeGeneration.CSharp.Tests\NJsonSchema.CodeGeneration.CSharp.Tests.csproj" -c Release || goto :error
diff --git a/src/NJsonSchema.Benchmark/GeneratorPerformance.cs b/src/NJsonSchema.Benchmark/GeneratorPerformance.cs
new file mode 100644
index 000000000..35169a204
--- /dev/null
+++ b/src/NJsonSchema.Benchmark/GeneratorPerformance.cs
@@ -0,0 +1,25 @@
+using BenchmarkDotNet.Attributes;
+using NJsonSchema.Tests.Generation;
+using System.Threading.Tasks;
+using NJsonSchema.Infrastructure;
+
+using static NJsonSchema.Tests.Generation.XmlDocTests;
+
+namespace NJsonSchema.Benchmark
+{
+ public class GeneratorPerformance
+ {
+ private readonly XmlDocTests _tests;
+
+ public GeneratorPerformance()
+ {
+ _tests = new XmlDocTests();
+ }
+
+ [Benchmark]
+ public async Task XmlDocTests()
+ {
+ await typeof(ClassWithInheritdoc).GetMethod("Bar").GetXmlSummaryAsync();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NJsonSchema.Benchmark/GeneratorPerformanceTests.cs b/src/NJsonSchema.Benchmark/GeneratorPerformanceTests.cs
new file mode 100644
index 000000000..b67eab77d
--- /dev/null
+++ b/src/NJsonSchema.Benchmark/GeneratorPerformanceTests.cs
@@ -0,0 +1,65 @@
+using System.Diagnostics;
+using System.Threading.Tasks;
+using NBench;
+using NJsonSchema.Infrastructure;
+using Pro.NBench.xUnit.XunitExtensions;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace NJsonSchema.Benchmark
+{
+ public class GeneratorPerformanceTests
+ {
+ private readonly GeneratorPerformance _generatorPerformance = new GeneratorPerformance();
+ private Counter _counter;
+
+ public GeneratorPerformanceTests(ITestOutputHelper output)
+ {
+ Trace.Listeners.Clear();
+ Trace.Listeners.Add(new XunitTraceListener(output));
+ }
+
+ [PerfSetup]
+#pragma warning disable xUnit1013 // Public method should be marked as test
+ public void Setup(BenchmarkContext context)
+#pragma warning restore xUnit1013 // Public method should be marked as test
+ {
+ _counter = context.GetCounter("Iterations");
+ }
+
+ ///
+ /// Ensure that we can serialise at least 200 times per second (5ms).
+ ///
+ [NBenchFact]
+ [PerfBenchmark(
+ Description = "Xml Docs (with cache)",
+ NumberOfIterations = 3,
+ RunTimeMilliseconds = 1000,
+ RunMode = RunMode.Throughput,
+ TestMode = TestMode.Test)]
+ [CounterThroughputAssertion("Iterations", MustBe.GreaterThan, 200)]
+ public void XmlDocTestsWithCache()
+ {
+ _generatorPerformance.XmlDocTests().GetAwaiter().GetResult();
+ _counter.Increment();
+ }
+
+ ///
+ /// Ensure that we can serialise at least 200 times per second (5ms).
+ ///
+ [NBenchFact]
+ [PerfBenchmark(
+ Description = "Xml Docs (without cache)",
+ NumberOfIterations = 3,
+ RunTimeMilliseconds = 1000,
+ RunMode = RunMode.Throughput,
+ TestMode = TestMode.Test)]
+ [CounterThroughputAssertion("Iterations", MustBe.GreaterThan, 200)]
+ public void XmlDocTestsWithoutCache()
+ {
+ XmlDocumentationExtensions.ClearCacheAsync().GetAwaiter().GetResult();
+ _generatorPerformance.XmlDocTests().GetAwaiter().GetResult();
+ _counter.Increment();
+ }
+ }
+}
diff --git a/src/NJsonSchema.Benchmark/NJsonSchema.Benchmark.csproj b/src/NJsonSchema.Benchmark/NJsonSchema.Benchmark.csproj
index b594854be..e2ecd95a9 100644
--- a/src/NJsonSchema.Benchmark/NJsonSchema.Benchmark.csproj
+++ b/src/NJsonSchema.Benchmark/NJsonSchema.Benchmark.csproj
@@ -22,6 +22,7 @@
+
diff --git a/src/NJsonSchema.CodeGeneration.CSharp.Tests/GeneralGeneratorTests.cs b/src/NJsonSchema.CodeGeneration.CSharp.Tests/GeneralGeneratorTests.cs
index 44742c959..5b6fa72ec 100644
--- a/src/NJsonSchema.CodeGeneration.CSharp.Tests/GeneralGeneratorTests.cs
+++ b/src/NJsonSchema.CodeGeneration.CSharp.Tests/GeneralGeneratorTests.cs
@@ -278,7 +278,7 @@ public async Task When_class_has_description_then_csharp_has_xml_comment()
{
//// Arrange
var schema = await JsonSchema4.FromTypeAsync();
- schema.Description = "ClassDesc.";
+ schema.ActualSchema.Description = "ClassDesc.";
var generator = new CSharpGenerator(schema);
//// Act
@@ -295,7 +295,7 @@ public async Task When_property_has_description_then_csharp_has_xml_comment()
{
//// Arrange
var schema = await JsonSchema4.FromTypeAsync();
- schema.Properties["Class"].Description = "PropertyDesc.";
+ schema.ActualProperties["Class"].Description = "PropertyDesc.";
var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings { ClassStyle = CSharpClassStyle.Poco });
//// Act
diff --git a/src/NJsonSchema.CodeGeneration.CSharp/NJsonSchema.CodeGeneration.CSharp.csproj b/src/NJsonSchema.CodeGeneration.CSharp/NJsonSchema.CodeGeneration.CSharp.csproj
index 153412140..793252fb0 100644
--- a/src/NJsonSchema.CodeGeneration.CSharp/NJsonSchema.CodeGeneration.CSharp.csproj
+++ b/src/NJsonSchema.CodeGeneration.CSharp/NJsonSchema.CodeGeneration.CSharp.csproj
@@ -2,7 +2,7 @@
netstandard1.3;net451
JSON Schema reader, generator and validator for .NET
- 9.10.73
+ 9.10.74
json schema validation generator .net
Copyright © Rico Suter, 2017
https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md
diff --git a/src/NJsonSchema.CodeGeneration.TypeScript.Tests/AbstractGenerationTests.cs b/src/NJsonSchema.CodeGeneration.TypeScript.Tests/AbstractGenerationTests.cs
index bda9c81fa..74c8b5a8c 100644
--- a/src/NJsonSchema.CodeGeneration.TypeScript.Tests/AbstractGenerationTests.cs
+++ b/src/NJsonSchema.CodeGeneration.TypeScript.Tests/AbstractGenerationTests.cs
@@ -19,6 +19,7 @@ public async Task When_class_is_abstract_then_is_abstract_TypeScript_keyword_is_
{
/// Arrange
var schema = await JsonSchema4.FromTypeAsync();
+ var json = schema.ToJson();
/// Act
var generator = new TypeScriptGenerator(schema, new TypeScriptGeneratorSettings { TypeScriptVersion = 2.0m });
@@ -26,6 +27,10 @@ public async Task When_class_is_abstract_then_is_abstract_TypeScript_keyword_is_
/// Assert
Assert.Contains("export abstract class AbstractClass", code);
+
+ Assert.Contains("base: string", code);
+ Assert.Contains("super: string", code);
+ Assert.Contains("foo: string", code);
}
public class ContainerClass
@@ -53,12 +58,12 @@ public async Task When_property_is_required_and_abstract_then_it_is_not_instanti
[JsonConverter(typeof(JsonInheritanceConverter))]
public class BaseClass
{
-
+ public string Base { get; set; }
}
public class SuperClass : AbstractClass
{
-
+ public string Super { get; set; }
}
[Fact]
diff --git a/src/NJsonSchema.CodeGeneration.TypeScript.Tests/TypeScriptGeneratorTests.cs b/src/NJsonSchema.CodeGeneration.TypeScript.Tests/TypeScriptGeneratorTests.cs
index 844253b86..5ca3fddbc 100644
--- a/src/NJsonSchema.CodeGeneration.TypeScript.Tests/TypeScriptGeneratorTests.cs
+++ b/src/NJsonSchema.CodeGeneration.TypeScript.Tests/TypeScriptGeneratorTests.cs
@@ -154,7 +154,9 @@ public async Task When_property_has_description_then_csharp_has_xml_comment()
{
//// Arrange
var schema = await JsonSchema4.FromTypeAsync();
- schema.Properties["Class"].Description = "PropertyDesc.";
+ schema.ActualProperties["Class"].Description = "PropertyDesc.";
+ var json = schema.ToJson();
+
var generator = new TypeScriptGenerator(schema);
//// Act
diff --git a/src/NJsonSchema.CodeGeneration.TypeScript/NJsonSchema.CodeGeneration.TypeScript.csproj b/src/NJsonSchema.CodeGeneration.TypeScript/NJsonSchema.CodeGeneration.TypeScript.csproj
index 974bf15e4..d116b402d 100644
--- a/src/NJsonSchema.CodeGeneration.TypeScript/NJsonSchema.CodeGeneration.TypeScript.csproj
+++ b/src/NJsonSchema.CodeGeneration.TypeScript/NJsonSchema.CodeGeneration.TypeScript.csproj
@@ -2,7 +2,7 @@
netstandard1.3;net451
JSON Schema reader, generator and validator for .NET
- 9.10.73
+ 9.10.74
json schema validation generator .net
Copyright © Rico Suter, 2017
https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md
diff --git a/src/NJsonSchema.CodeGeneration/Models/ClassTemplateModelBase.cs b/src/NJsonSchema.CodeGeneration/Models/ClassTemplateModelBase.cs
index 1e3eee897..416153c96 100644
--- a/src/NJsonSchema.CodeGeneration/Models/ClassTemplateModelBase.cs
+++ b/src/NJsonSchema.CodeGeneration/Models/ClassTemplateModelBase.cs
@@ -33,7 +33,7 @@ protected ClassTemplateModelBase(TypeResolverBase resolver, JsonSchema4 schema,
public abstract string ClassName { get; }
/// Gets or sets a value indicating whether the type is abstract.
- public bool IsAbstract => _schema.IsAbstract;
+ public bool IsAbstract => _schema.ActualTypeSchema.IsAbstract;
/// Gets the property extension data.
public IDictionary ExtensionData => _schema.ExtensionData;
@@ -49,7 +49,7 @@ public class DerivedClassModel
{
internal DerivedClassModel(string typeName, JsonSchema4 schema, OpenApiDiscriminator discriminator, TypeResolverBase resolver)
{
- var mapping = discriminator.Mapping.SingleOrDefault(m => m.Value.ActualSchema == schema.ActualSchema);
+ var mapping = discriminator.Mapping.SingleOrDefault(m => m.Value.ActualTypeSchema == schema.ActualTypeSchema);
ClassName = resolver.GetOrGenerateTypeName(schema, typeName);
IsAbstract = schema.ActualTypeSchema.IsAbstract;
diff --git a/src/NJsonSchema.CodeGeneration/NJsonSchema.CodeGeneration.csproj b/src/NJsonSchema.CodeGeneration/NJsonSchema.CodeGeneration.csproj
index 7a93afb1e..61e425979 100644
--- a/src/NJsonSchema.CodeGeneration/NJsonSchema.CodeGeneration.csproj
+++ b/src/NJsonSchema.CodeGeneration/NJsonSchema.CodeGeneration.csproj
@@ -2,7 +2,7 @@
netstandard1.3;net451
JSON Schema reader, generator and validator for .NET
- 9.10.73
+ 9.10.74
json schema validation generator .net
Copyright © Rico Suter, 2017
https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md
diff --git a/src/NJsonSchema.Tests/Conversion/ArrayTypeToSchemaTests.cs b/src/NJsonSchema.Tests/Conversion/ArrayTypeToSchemaTests.cs
index 800a5570a..4b11814a0 100644
--- a/src/NJsonSchema.Tests/Conversion/ArrayTypeToSchemaTests.cs
+++ b/src/NJsonSchema.Tests/Conversion/ArrayTypeToSchemaTests.cs
@@ -32,7 +32,7 @@ public async Task When_converting_type_inheriting_from_dictionary_then_it_should
var data = schema.ToJson();
//// Assert
- Assert.Equal(JsonObjectType.Object, schema.Type);
+ Assert.Equal(JsonObjectType.Object, schema.ActualTypeSchema.Type);
Assert.DoesNotContain("Foo", json);
Assert.DoesNotContain("foo", json);
}
diff --git a/src/NJsonSchema.Tests/Generation/AttributeGenerationTests.cs b/src/NJsonSchema.Tests/Generation/AttributeGenerationTests.cs
index 9f78ef448..20ea4663f 100644
--- a/src/NJsonSchema.Tests/Generation/AttributeGenerationTests.cs
+++ b/src/NJsonSchema.Tests/Generation/AttributeGenerationTests.cs
@@ -188,5 +188,25 @@ public class AttributeTestClass
[ReadOnly(true)]
public bool ReadOnly { get; set; }
}
+
+ public class ClassWithTypedRange
+ {
+ [Range(typeof(decimal), "0", "1")]
+ public decimal Foo { get; set; }
+ }
+
+ [Fact]
+ public async Task When_range_has_type_and_strings_then_it_is_processed_correctly()
+ {
+ //// Arrange
+
+ //// Act
+ var schema = await JsonSchema4.FromTypeAsync();
+ var property = schema.Properties["Foo"];
+
+ //// Assert
+ Assert.Equal(0.0m, property.Minimum);
+ Assert.Equal(1.0m, property.Maximum);
+ }
}
}
\ No newline at end of file
diff --git a/src/NJsonSchema.Tests/Generation/ExceptionTypeTests.cs b/src/NJsonSchema.Tests/Generation/ExceptionTypeTests.cs
index c2c7d65cc..4e3afc741 100644
--- a/src/NJsonSchema.Tests/Generation/ExceptionTypeTests.cs
+++ b/src/NJsonSchema.Tests/Generation/ExceptionTypeTests.cs
@@ -24,8 +24,8 @@ public async Task When_exception_schema_is_generated_then_special_properties_are
var exceptionSchema = schema.InheritedSchema.ActualSchema;
//// Assert
- Assert.True(schema.Properties.ContainsKey("foo"));
- Assert.True(exceptionSchema.Properties.ContainsKey("InnerException"));
+ Assert.True(schema.ActualProperties.ContainsKey("foo"));
+ Assert.True(exceptionSchema.ActualProperties.ContainsKey("InnerException"));
}
}
}
diff --git a/src/NJsonSchema.Tests/Generation/InheritanceTests.cs b/src/NJsonSchema.Tests/Generation/InheritanceTests.cs
index e7eb9a9c8..9b1157e12 100644
--- a/src/NJsonSchema.Tests/Generation/InheritanceTests.cs
+++ b/src/NJsonSchema.Tests/Generation/InheritanceTests.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading.Tasks;
@@ -88,9 +89,9 @@ public async Task When_generating_type_with_inheritance_then_allOf_has_one_item(
var schema = await JsonSchema4.FromTypeAsync();
//// Assert
- Assert.NotNull(schema.Properties["Class"]);
+ Assert.NotNull(schema.ActualProperties["Class"]);
- Assert.Equal(1, schema.AllOf.Count);
+ Assert.Equal(2, schema.AllOf.Count);
Assert.Contains(schema.Definitions, d => d.Key == "Person");
Assert.NotNull(schema.AllOf.First().ActualSchema.Properties["Name"]);
}
@@ -298,10 +299,45 @@ public async Task Existing_non_string_property_cant_be_discriminant()
//// Arrange
//// Act
- Task getSchema() => JsonSchema4.FromTypeAsync();
+ Task GetSchema() => JsonSchema4.FromTypeAsync();
//// Assert
- await Assert.ThrowsAsync(getSchema);
+ await Assert.ThrowsAsync(GetSchema);
+ }
+
+ public class Foo
+ {
+ public Bar Bar { get; set; }
+ }
+
+ public class Bar : Dictionary
+ {
+ public string Baz { get; set; }
+ }
+
+ [Fact]
+ public async Task When_class_inherits_from_dictionary_then_allOf_contains_base_dictionary_schema_and_actual_schema()
+ {
+ //// Arrange
+ var settings = new JsonSchemaGeneratorSettings
+ {
+ SchemaType = SchemaType.OpenApi3
+ };
+
+ //// Act
+ var schema = await JsonSchema4.FromTypeAsync(settings);
+ var json = schema.ToJson();
+
+ //// Assert
+ var bar = schema.Definitions["Bar"];
+
+ Assert.Equal(2, bar.AllOf.Count);
+
+ Assert.Equal(bar.AllOf.Last(), bar.ActualTypeSchema);
+ Assert.Equal(bar.AllOf.First(), bar.InheritedSchema);
+
+ Assert.True(bar.AllOf.First().IsDictionary); // base class (dictionary)
+ Assert.True(bar.AllOf.Last().ActualProperties.Any()); // actual class
}
}
}
diff --git a/src/NJsonSchema.Tests/Generation/SchemaGenerationTests.cs b/src/NJsonSchema.Tests/Generation/SchemaGenerationTests.cs
index b9bebe982..dd2f07bb9 100644
--- a/src/NJsonSchema.Tests/Generation/SchemaGenerationTests.cs
+++ b/src/NJsonSchema.Tests/Generation/SchemaGenerationTests.cs
@@ -152,6 +152,25 @@ public async Task When_property_is_object_then_it_should_not_be_a_dictonary_but_
Assert.False(property.IsDictionary);
}
+ public class ClassWithStaticProperty
+ {
+ public static string Foo { get; set; }
+
+ public string Bar { get; set; }
+ }
+
+ [Fact]
+ public async Task When_property_is_static_then_it_is_ignored()
+ {
+ /// Act
+ var schema = await JsonSchema4.FromTypeAsync();
+ var json = schema.ToJson();
+
+ /// Assert
+ Assert.Equal(1, schema.ActualProperties.Count);
+ Assert.True(schema.ActualProperties.ContainsKey("Bar"));
+ }
+
// Used as demo for https://github.com/swagger-api/swagger-ui/issues/1056
//public class TestClass
diff --git a/src/NJsonSchema.Tests/Generation/XmlDocTests.cs b/src/NJsonSchema.Tests/Generation/XmlDocTests.cs
index ec10d8767..d6de7103d 100644
--- a/src/NJsonSchema.Tests/Generation/XmlDocTests.cs
+++ b/src/NJsonSchema.Tests/Generation/XmlDocTests.cs
@@ -118,7 +118,7 @@ public async Task When_xml_doc_is_missing_then_summary_is_missing()
//// Assert
Assert.Empty(summary);
}
-
+
public abstract class BaseBaseClass
{
/// Foo.
diff --git a/src/NJsonSchema.Yaml/NJsonSchema.Yaml.csproj b/src/NJsonSchema.Yaml/NJsonSchema.Yaml.csproj
index a96b7e705..d03a5670f 100644
--- a/src/NJsonSchema.Yaml/NJsonSchema.Yaml.csproj
+++ b/src/NJsonSchema.Yaml/NJsonSchema.Yaml.csproj
@@ -2,7 +2,7 @@
netstandard1.3;net45
JSON Schema reader, generator and validator for .NET
- 9.10.73
+ 9.10.74
json schema validation generator .net
Copyright © Rico Suter, 2017
https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md
diff --git a/src/NJsonSchema/Generation/JsonSchemaGenerator.cs b/src/NJsonSchema/Generation/JsonSchemaGenerator.cs
index bbb7ef276..6335cfb4d 100644
--- a/src/NJsonSchema/Generation/JsonSchemaGenerator.cs
+++ b/src/NJsonSchema/Generation/JsonSchemaGenerator.cs
@@ -146,9 +146,7 @@ public virtual async Task GenerateAsync(Type type, IEnumerableGenerates the properties for the given type and schema.
- /// The type of the schema type.
/// The types.
+ /// The type description.
/// The properties
/// The schema resolver.
/// The task.
- protected virtual async Task GenerateObjectAsync(
- Type type, TSchemaType schema, JsonSchemaResolver schemaResolver)
- where TSchemaType : JsonSchema4, new()
+ protected virtual async Task GenerateObjectAsync(Type type,
+ JsonTypeDescription typeDescription, JsonSchema4 schema, JsonSchemaResolver schemaResolver)
{
schemaResolver.AddSchema(type, false, schema);
+ var rootSchema = schema;
+
+ var hasInheritance = await GenerateInheritanceAsync(type, schema, schemaResolver).ConfigureAwait(false);
+ if (hasInheritance)
+ {
+ var actualSchema = new JsonSchema4();
+ schema.AllOf.Add(actualSchema);
+ schema = actualSchema;
+ }
+ typeDescription.ApplyType(schema);
+ schema.Description = await type.GetTypeInfo().GetDescriptionAsync(type.GetTypeInfo().GetCustomAttributes()).ConfigureAwait(false);
+ schema.AllowAdditionalProperties = false;
schema.IsAbstract = type.GetTypeInfo().IsAbstract;
- await GeneratePropertiesAndInheritanceAsync(type, schema, schemaResolver).ConfigureAwait(false);
- await ApplyAdditionalPropertiesAsync(type, schema, schemaResolver);
+ await GeneratePropertiesAsync(type, schema, schemaResolver).ConfigureAwait(false);
+ await ApplyAdditionalPropertiesAsync(type, schema, schemaResolver).ConfigureAwait(false);
+
+ GenerateInheritanceDiscriminator(type, rootSchema);
if (Settings.GenerateKnownTypes)
await GenerateKnownTypesAsync(type, schemaResolver).ConfigureAwait(false);
@@ -345,7 +356,7 @@ private async Task ApplyAdditionalPropertiesAsync(Type type, TSchem
var genericTypeArguments = extensionDataProperty.PropertyType.GetGenericTypeArguments();
var extensionDataPropertyType = genericTypeArguments.Length == 2 ? genericTypeArguments[1] : typeof(object);
- schema.AdditionalPropertiesSchema = await GenerateWithReferenceAndNullabilityAsync(extensionDataPropertyType, null, schemaResolver);
+ schema.AdditionalPropertiesSchema = await GenerateWithReferenceAndNullabilityAsync(extensionDataPropertyType, null, schemaResolver).ConfigureAwait(false);
}
else
schema.AllowAdditionalProperties = false;
@@ -510,7 +521,7 @@ private async Task GenerateDictionaryAsync(TSchemaType schema, Type
schema.AllowAdditionalProperties = true;
}
- private async Task GeneratePropertiesAndInheritanceAsync(Type type, JsonSchema4 schema, JsonSchemaResolver schemaResolver)
+ private async Task GeneratePropertiesAsync(Type type, JsonSchema4 schema, JsonSchemaResolver schemaResolver)
{
#if !LEGACY
var propertiesAndFields = type.GetTypeInfo()
@@ -603,8 +614,6 @@ private async Task GeneratePropertiesAndInheritanceAsync(Type type, JsonSchema4
await LoadPropertyOrFieldAsync(property, info, type, schema, schemaResolver).ConfigureAwait(false);
}
}
-
- await GenerateInheritanceAsync(type, schema, schemaResolver).ConfigureAwait(false);
}
/// Gets the properties of the given type or null to take all properties.
@@ -656,7 +665,7 @@ private async Task AddKnownTypeAsync(Type type, JsonSchemaResolver schemaResolve
await GenerateAsync(type, schemaResolver).ConfigureAwait(false);
}
- private async Task GenerateInheritanceAsync(Type type, JsonSchema4 schema, JsonSchemaResolver schemaResolver)
+ private async Task GenerateInheritanceAsync(Type type, JsonSchema4 schema, JsonSchemaResolver schemaResolver)
{
var baseType = type.GetTypeInfo().BaseType;
if (baseType != null && baseType != typeof(object) && baseType != typeof(ValueType))
@@ -669,7 +678,12 @@ private async Task GenerateInheritanceAsync(Type type, JsonSchema4 schema, JsonS
{
var typeDescription = Settings.ReflectionService.GetDescription(baseType, null, Settings);
if (!typeDescription.IsDictionary && !type.IsArray)
- await GeneratePropertiesAndInheritanceAsync(baseType, schema, schemaResolver).ConfigureAwait(false);
+ {
+ await GeneratePropertiesAsync(baseType, schema, schemaResolver).ConfigureAwait(false);
+ await GenerateInheritanceAsync(baseType, schema, schemaResolver).ConfigureAwait(false);
+
+ GenerateInheritanceDiscriminator(baseType, schema);
+ }
}
else
{
@@ -687,6 +701,8 @@ private async Task GenerateInheritanceAsync(Type type, JsonSchema4 schema, JsonS
}
else
schema.AllOf.Add(baseSchema);
+
+ return true;
}
}
}
@@ -700,12 +716,18 @@ private async Task GenerateInheritanceAsync(Type type, JsonSchema4 schema, JsonS
#endif
{
var typeDescription = Settings.ReflectionService.GetDescription(i, null, Settings);
- if (!typeDescription.IsDictionary && !type.IsArray && !typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(i.GetTypeInfo()))
- await GeneratePropertiesAndInheritanceAsync(i, schema, schemaResolver).ConfigureAwait(false);
+ if (!typeDescription.IsDictionary && !type.IsArray &&
+ !typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(i.GetTypeInfo()))
+ {
+ await GeneratePropertiesAsync(i, schema, schemaResolver).ConfigureAwait(false);
+ await GenerateInheritanceAsync(i, schema, schemaResolver).ConfigureAwait(false);
+
+ GenerateInheritanceDiscriminator(i, schema);
+ }
}
}
- GenerateInheritanceDiscriminator(type, schema);
+ return false;
}
private void GenerateInheritanceDiscriminator(Type type, JsonSchema4 schema)
@@ -949,14 +971,7 @@ public virtual void ApplyDataAnnotations(JsonSchema4 schema, JsonTypeDescription
if (typeDescription.Type == JsonObjectType.Number ||
typeDescription.Type == JsonObjectType.Integer)
{
- dynamic rangeAttribute = parentAttributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.RangeAttribute");
- if (rangeAttribute != null)
- {
- if (rangeAttribute.Minimum != null && rangeAttribute.Minimum > double.MinValue)
- schema.Minimum = (decimal?)(double)rangeAttribute.Minimum;
- if (rangeAttribute.Maximum != null && rangeAttribute.Maximum < double.MaxValue)
- schema.Maximum = (decimal?)(double)rangeAttribute.Maximum;
- }
+ ApplyRangeAttribute(schema, parentAttributes);
var multipleOfAttribute = parentAttributes.OfType().SingleOrDefault();
if (multipleOfAttribute != null)
@@ -1000,6 +1015,53 @@ public virtual void ApplyDataAnnotations(JsonSchema4 schema, JsonTypeDescription
}
}
+ private void ApplyRangeAttribute(JsonSchema4 schema, IEnumerable parentAttributes)
+ {
+ dynamic rangeAttribute = parentAttributes.TryGetIfAssignableTo("System.ComponentModel.DataAnnotations.RangeAttribute");
+ if (rangeAttribute != null)
+ {
+ if (rangeAttribute.Minimum != null)
+ {
+ if (rangeAttribute.OperandType == typeof(double))
+ {
+ var minimum = (double)Convert.ChangeType(rangeAttribute.Minimum, typeof(double));
+ if (minimum > double.MinValue)
+ {
+ schema.Minimum = (decimal)minimum;
+ }
+ }
+ else
+ {
+ var minimum = (decimal)Convert.ChangeType(rangeAttribute.Minimum, typeof(decimal));
+ if (minimum > decimal.MinValue)
+ {
+ schema.Minimum = minimum;
+ }
+ }
+ }
+
+ if (rangeAttribute.Maximum != null)
+ {
+ if (rangeAttribute.OperandType == typeof(double))
+ {
+ var maximum = (double)Convert.ChangeType(rangeAttribute.Maximum, typeof(double));
+ if (maximum < double.MaxValue)
+ {
+ schema.Maximum = (decimal)maximum;
+ }
+ }
+ else
+ {
+ var maximum = (decimal)Convert.ChangeType(rangeAttribute.Maximum, typeof(decimal));
+ if (maximum < decimal.MaxValue)
+ {
+ schema.Maximum = maximum;
+ }
+ }
+ }
+ }
+ }
+
private object ConvertDefaultValue(Newtonsoft.Json.Serialization.JsonProperty property)
{
if (property.DefaultValue != null && property.DefaultValue.GetType().GetTypeInfo().IsEnum)
diff --git a/src/NJsonSchema/Infrastructure/DynamicApis.cs b/src/NJsonSchema/Infrastructure/DynamicApis.cs
index 68eb7608b..8743f4a2d 100644
--- a/src/NJsonSchema/Infrastructure/DynamicApis.cs
+++ b/src/NJsonSchema/Infrastructure/DynamicApis.cs
@@ -121,7 +121,7 @@ public static async Task DirectoryExistsAsync(string filePath)
return false;
return await FromResult((bool)DirectoryType.GetRuntimeMethod("Exists",
- new[] { typeof(string) }).Invoke(null, new object[] { filePath }));
+ new[] { typeof(string) }).Invoke(null, new object[] { filePath })).ConfigureAwait(false);
}
/// Checks whether a file exists.
@@ -137,7 +137,7 @@ public static async Task FileExistsAsync(string filePath)
return false;
return await FromResult((bool)FileType.GetRuntimeMethod("Exists",
- new[] { typeof(string) }).Invoke(null, new object[] { filePath }));
+ new[] { typeof(string) }).Invoke(null, new object[] { filePath })).ConfigureAwait(false);
}
/// Reads all content of a file (UTF8).
@@ -206,13 +206,13 @@ public static object XPathEvaluate(XDocument document, string path)
}
#if LEGACY
- private static async Task FromResult(T result)
+ internal static async Task FromResult(T result)
{
return result;
}
#else
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static Task FromResult(T result)
+ internal static Task FromResult(T result)
{
return Task.FromResult(result);
}
diff --git a/src/NJsonSchema/Infrastructure/XmlDocumentationExtensions.cs b/src/NJsonSchema/Infrastructure/XmlDocumentationExtensions.cs
index d05b6f47c..d8047a017 100644
--- a/src/NJsonSchema/Infrastructure/XmlDocumentationExtensions.cs
+++ b/src/NJsonSchema/Infrastructure/XmlDocumentationExtensions.cs
@@ -23,10 +23,8 @@ namespace NJsonSchema.Infrastructure
/// This class currently works only on the desktop .NET framework.
public static class XmlDocumentationExtensions
{
- private static readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1);
-
- private static readonly Dictionary Cache =
- new Dictionary(StringComparer.OrdinalIgnoreCase);
+ private static readonly AsyncLock Lock = new AsyncLock();
+ private static readonly Dictionary Cache = new Dictionary(StringComparer.OrdinalIgnoreCase);
#if !LEGACY
@@ -82,91 +80,6 @@ public static async Task GetXmlRemarksAsync(this MemberInfo member)
return await GetXmlDocumentationTagAsync(member, "remarks").ConfigureAwait(false);
}
- /// Returns the contents of an XML documentation tag for the specified member.
- /// The reflected member.
- /// The contents of the "summary" tag for the member.
- public static Task GetXmlDocumentationAsync(this MemberInfo member)
- {
- return GetXmlDocumentationAsync(member, true);
- }
-
- /// Returns the contents of an XML documentation tag for the specified member.
- /// The reflected member.
- /// Name of the tag.
- /// The contents of the "summary" tag for the member.
- public static async Task GetXmlDocumentationTagAsync(this MemberInfo member, string tagName)
- {
- if (DynamicApis.SupportsXPathApis == false || DynamicApis.SupportsFileApis == false || DynamicApis.SupportsPathApis == false)
- return string.Empty;
-
- var assemblyName = member.Module.Assembly.GetName();
- if (await IgnoreAssemblyAsync(assemblyName, true))
- return string.Empty;
-
- var documentationPath = await GetXmlDocumentationPathAsync(member.Module.Assembly).ConfigureAwait(false);
- var element = await GetXmlDocumentationAsync(member, documentationPath).ConfigureAwait(false);
- return RemoveLineBreakWhiteSpaces(GetXmlDocumentationText(element?.Element(tagName)));
- }
-
- /// Returns the contents of the "returns" or "param" XML documentation tag for the specified parameter.
- /// The reflected parameter or return info.
- /// The contents of the "returns" or "param" tag.
- public static async Task GetXmlDocumentationAsync(this ParameterInfo parameter)
- {
- if (DynamicApis.SupportsXPathApis == false || DynamicApis.SupportsFileApis == false || DynamicApis.SupportsPathApis == false)
- return string.Empty;
-
- var assemblyName = parameter.Member.Module.Assembly.GetName();
- if (await IgnoreAssemblyAsync(assemblyName, true))
- return string.Empty;
-
- var documentationPath = await GetXmlDocumentationPathAsync(parameter.Member.Module.Assembly).ConfigureAwait(false);
- var element = await GetXmlDocumentationAsync(parameter, documentationPath).ConfigureAwait(false);
- return RemoveLineBreakWhiteSpaces(GetXmlDocumentationText(element));
- }
-
- /// Returns the contents of the "summary" XML documentation tag for the specified member.
- /// The type.
- /// The path to the XML documentation file.
- /// The contents of the "summary" tag for the member.
- public static Task GetXmlDocumentationAsync(this Type type, string pathToXmlFile)
- {
- return ((MemberInfo)type.GetTypeInfo()).GetXmlDocumentationAsync(pathToXmlFile);
- }
-
- /// Returns the contents of the "summary" XML documentation tag for the specified member.
- /// The reflected member.
- /// The path to the XML documentation file.
- /// The contents of the "summary" tag for the member.
- public static Task GetXmlDocumentationAsync(this MemberInfo member, string pathToXmlFile)
- {
- return GetXmlDocumentationAsync(member, pathToXmlFile, true);
- }
-
- /// Returns the contents of the "returns" or "param" XML documentation tag for the specified parameter.
- /// The reflected parameter or return info.
- /// The path to the XML documentation file.
- /// The contents of the "returns" or "param" tag.
- public static async Task GetXmlDocumentationAsync(this ParameterInfo parameter, string pathToXmlFile)
- {
- try
- {
- if (pathToXmlFile == null || DynamicApis.SupportsXPathApis == false || DynamicApis.SupportsFileApis == false || DynamicApis.SupportsPathApis == false)
- return null;
-
- var assemblyName = parameter.Member.Module.Assembly.GetName();
- var document = await TryGetXmlDocumentAsync(assemblyName, pathToXmlFile, true);
- if (document == null)
- return null;
-
- return await GetXmlDocumentationAsync(parameter, document);
- }
- catch
- {
- return null;
- }
- }
-
/// Gets the description of the given member (based on the DescriptionAttribute, DisplayAttribute or XML Documentation).
/// The member info
/// The attributes.
@@ -269,52 +182,84 @@ public static string GetXmlDocumentationText(this XElement element)
/// Clears the cache.
/// The task.
- public static async Task ClearCacheAsync()
+ public static Task ClearCacheAsync()
{
-#if !LEGACY
- await _lock.WaitAsync();
-#else
- _lock.Wait();
-#endif
-
- try
+ using (Lock.Lock())
{
Cache.Clear();
+ return DynamicApis.FromResult