diff --git a/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/AssemblyLoader/AssemblyLoader.cs b/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/AssemblyLoader/AssemblyLoader.cs index 9d69414..cc84249 100644 --- a/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/AssemblyLoader/AssemblyLoader.cs +++ b/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/AssemblyLoader/AssemblyLoader.cs @@ -146,14 +146,14 @@ internal void RegisterAssemblyPaths(IList assemblyPaths) /// The operation xelements. /// The property xelements /// The document variant element name. - /// + /// /// Serialized public string BuildInternalGenerationContext( IList contractAssembliesPaths, IList operationElements, IList propertyElements, string documentVariantElementName, - InternalSchemaGenerationSettings internalSchemaGenerationSettings) + SchemaGenerationSettings schemaGenerationSettings) { var crefSchemaMap = new Dictionary(); @@ -175,14 +175,6 @@ public string BuildInternalGenerationContext( var referenceRegistryMap = new Dictionary(); - var schemaGenerationSettings = new SchemaGenerationSettings(new DefaultPropertyNameResolver()); - - if (internalSchemaGenerationSettings.PropertyNameResolverName == - typeof(CamelCasePropertyNameResolver).FullName) - { - schemaGenerationSettings = new SchemaGenerationSettings(new CamelCasePropertyNameResolver()); - } - var internalGenerationContext = new InternalGenerationContext(); #if !NETFRAMEWORK diff --git a/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/CamelCasePropertyNameResolver.cs b/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/CamelCasePropertyNameResolver.cs index 9533569..9ad6b14 100644 --- a/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/CamelCasePropertyNameResolver.cs +++ b/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/CamelCasePropertyNameResolver.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System; using System.Reflection; using Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration.Extensions; @@ -11,6 +12,7 @@ namespace Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration /// /// Resolves property name by camel casing. /// + [Serializable] public class CamelCasePropertyNameResolver : DefaultPropertyNameResolver, IPropertyNameResolver { /// diff --git a/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/DefaultPropertyNameResolver.cs b/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/DefaultPropertyNameResolver.cs index 3a8a91d..e2f48e2 100644 --- a/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/DefaultPropertyNameResolver.cs +++ b/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/DefaultPropertyNameResolver.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ +using System; using System.Linq; using System.Reflection; using Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration.ReferenceRegistries; @@ -12,6 +13,7 @@ namespace Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration /// /// Used by to resolve property name for a given . /// + [Serializable] public class DefaultPropertyNameResolver : IPropertyNameResolver { /// diff --git a/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/DefaultSchemaIdResolver.cs b/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/DefaultSchemaIdResolver.cs new file mode 100644 index 0000000..b0ad426 --- /dev/null +++ b/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/DefaultSchemaIdResolver.cs @@ -0,0 +1,23 @@ +using System; +using Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration.Extensions; +using Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration.ReferenceRegistries; + +namespace Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration +{ + /// + /// Used by to resolve schema id name for a given . + /// + [Serializable] + public class DefaultSchemaIdResolver : ISchemaIdResolver + { + /// + public string ResolveSchemaId(Type type) + { + // Type.ToString() returns full name for non-generic types and + // returns a full name without unnecessary assembly information for generic types. + var typeName = type.ToString(); + + return typeName.SanitizeClassName(); + } + } +} diff --git a/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/IDiscriminatorResolver.cs b/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/IDiscriminatorResolver.cs new file mode 100644 index 0000000..9e9b5a5 --- /dev/null +++ b/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/IDiscriminatorResolver.cs @@ -0,0 +1,27 @@ +using System; +using System.Reflection; +using Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration.ReferenceRegistries; + +namespace Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration +{ + /// + /// Utilized by to find information about discriminator + /// + public interface IDiscriminatorResolver + { + /// + /// Resolves the discriminator property + /// + /// The parent type. + /// + PropertyInfo ResolveProperty(Type parentType); + + /// + /// Resolves the mapping key. + /// + /// The discriminator property. + /// The child type. + /// + string ResolveMappingKey(PropertyInfo discriminatorProperty, Type childType); + } +} diff --git a/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/ISchemaIdResolver.cs b/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/ISchemaIdResolver.cs new file mode 100644 index 0000000..e9df753 --- /dev/null +++ b/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/ISchemaIdResolver.cs @@ -0,0 +1,18 @@ +using System; +using Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration.ReferenceRegistries; + +namespace Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration +{ + /// + /// Used by to resolve schema id name for a given . + /// + public interface ISchemaIdResolver + { + /// + /// Resolves the schema identifier. + /// + /// The type. + /// + string ResolveSchemaId(Type type); + } +} diff --git a/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/InternalOpenApiGenerator.cs b/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/InternalOpenApiGenerator.cs index da7d3d9..1f1ca53 100644 --- a/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/InternalOpenApiGenerator.cs +++ b/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/InternalOpenApiGenerator.cs @@ -271,14 +271,8 @@ IDictionary openApiDocuments try { - var propertyNameResolverTypeName = _openApiDocumentGenerationSettings.SchemaGenerationSettings - .PropertyNameResolver.GetType().FullName; var internalGenerationContext = new InternalGenerationContext(); - var internalSchemaGenerationSettings = new InternalSchemaGenerationSettings() - { - PropertyNameResolverName = propertyNameResolverTypeName - }; generationDiagnostic = new GenerationDiagnostic(); var documentGenerationDiagnostic = new DocumentGenerationDiagnostic(); @@ -310,7 +304,7 @@ IDictionary openApiDocuments serializedOperationElements, propertyElements.Select(i => i.ToString()).ToList(), documentVariantElementNames.FirstOrDefault(), - internalSchemaGenerationSettings); + _openApiDocumentGenerationSettings.SchemaGenerationSettings); internalGenerationContext = (InternalGenerationContext)JsonConvert.DeserializeObject( @@ -325,7 +319,7 @@ IDictionary openApiDocuments serializedOperationElements, propertyElements.Select(i => i.ToString()).ToList(), documentVariantElementNames.FirstOrDefault(), - internalSchemaGenerationSettings); + _openApiDocumentGenerationSettings.SchemaGenerationSettings); internalGenerationContext = (InternalGenerationContext)JsonConvert.DeserializeObject( diff --git a/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/ReferenceRegistries/SchemaReferenceRegistry.cs b/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/ReferenceRegistries/SchemaReferenceRegistry.cs index 33ac30f..f8db48b 100644 --- a/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/ReferenceRegistries/SchemaReferenceRegistry.cs +++ b/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/ReferenceRegistries/SchemaReferenceRegistry.cs @@ -6,7 +6,10 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Reflection; using System.Xml.Linq; +using System.Xml.Serialization; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration.Exceptions; using Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration.Extensions; @@ -194,8 +197,58 @@ internal override OpenApiSchema FindOrAddReference(Type input) } var a = input.FullName; + + PropertyInfo[] propertyInfos; + if (_schemaGenerationSettings.IncludeInheritanceInformation) + { + propertyInfos = input.GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance); + + if (input.BaseType != typeof(object)) + { + var baseClassSchema = FindOrAddReference(input.BaseType); + + schema.AllOf.Add(baseClassSchema); + } - foreach (var propertyInfo in input.GetProperties()) + if (_schemaGenerationSettings.DiscriminatorResolver != null) + { + var xmlIncludeAttributes = input.GetCustomAttributes(false).ToArray(); + + if (xmlIncludeAttributes.Length > 0) + { + var discriminatorProperty = _schemaGenerationSettings.DiscriminatorResolver.ResolveProperty(input); + + if (discriminatorProperty != null) + { + var openApiDiscriminator = new OpenApiDiscriminator() + { + PropertyName = discriminatorProperty.Name, + Mapping = new Dictionary() + }; + + schema.Discriminator = openApiDiscriminator; + + foreach (var xmlIncludeAttribute in xmlIncludeAttributes) + { + var childSchema = FindOrAddReference(xmlIncludeAttribute.Type); + + schema.OneOf.Add(childSchema); + + var mappingKey = _schemaGenerationSettings.DiscriminatorResolver.ResolveMappingKey(discriminatorProperty, xmlIncludeAttribute.Type); + + openApiDiscriminator.Mapping[mappingKey] = childSchema.Reference.ReferenceV3; + } + + } + } + } + } + else + { + propertyInfos = input.GetProperties(); + } + + foreach (var propertyInfo in propertyInfos) { var ignoreProperty = false; @@ -318,11 +371,7 @@ internal override OpenApiSchema FindOrAddReference(Type input) /// internal override string GetKey(Type input) { - // Type.ToString() returns full name for non-generic types and - // returns a full name without unnecessary assembly information for generic types. - var typeName = input.ToString(); - - return typeName.SanitizeClassName(); + return _schemaGenerationSettings.SchemaIdResolver.ResolveSchemaId(input); } } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/SchemaGenerationSettings.cs b/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/SchemaGenerationSettings.cs index fa13fd4..71c29de 100644 --- a/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/SchemaGenerationSettings.cs +++ b/src/Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration/SchemaGenerationSettings.cs @@ -10,21 +10,39 @@ namespace Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration /// /// Specifies the settings for schema generation. /// + [Serializable] public class SchemaGenerationSettings { /// /// Creates an instance of class. /// /// The property name resolver. - public SchemaGenerationSettings(IPropertyNameResolver propertyNameResolver) + /// + public SchemaGenerationSettings(IPropertyNameResolver propertyNameResolver, ISchemaIdResolver schemaIdResolver = null) { PropertyNameResolver = propertyNameResolver - ?? throw new ArgumentNullException(nameof(propertyNameResolver)); + ?? throw new ArgumentNullException(nameof(propertyNameResolver)); + SchemaIdResolver = schemaIdResolver ?? new DefaultSchemaIdResolver(); } /// /// Gets the property name resolver. /// public IPropertyNameResolver PropertyNameResolver { get; } + + /// + /// Gets the schema identifier resolver. + /// + public ISchemaIdResolver SchemaIdResolver { get; } + + /// + /// Gets or sets a value indicating whether generator should support inheritance, i.e add allOf and oneOf attributes. + /// + public bool IncludeInheritanceInformation { get; set; } + + /// + /// Gets or sets the discriminator resolver. + /// + public IDiscriminatorResolver DiscriminatorResolver { get; set; } } } \ No newline at end of file