diff --git a/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Extensions/TypeExtensions.cs b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Extensions/TypeExtensions.cs index cf2a7b6f..d394a69e 100644 --- a/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Extensions/TypeExtensions.cs +++ b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Extensions/TypeExtensions.cs @@ -402,19 +402,22 @@ public static string GetOpenApiReferenceId(this Type type, bool isDictionary, bo if (isDictionary) { - var name = type.Name.EndsWith("[]") ? "Dictionary_" + type.GetOpenApiSubTypeName(namingStrategy) : type.Name.Split('`').First() + "_" + type.GetOpenApiSubTypeName(namingStrategy); + var name = type.Name.EndsWith("[]") + ? "Dictionary_" + type.GetOpenApiTypeName(namingStrategy) + : type.GetOpenApiTypeName(namingStrategy); return namingStrategy.GetPropertyName(name, hasSpecifiedName: false); } if (isList) { - var name = type.Name.EndsWith("[]") ? "List_" + type.GetOpenApiSubTypeName(namingStrategy) : type.Name.Split('`').First() + "_" + type.GetOpenApiSubTypeName(namingStrategy); + var name = type.Name.EndsWith("[]") + ? "List_" + type.GetOpenApiTypeName(namingStrategy) + : type.GetOpenApiTypeName(namingStrategy); return namingStrategy.GetPropertyName(name, hasSpecifiedName: false); } if (type.IsGenericType) { - return namingStrategy.GetPropertyName(type.Name.Split('`').First(), false) + "_" + - string.Join("_", type.GenericTypeArguments.Select(a => namingStrategy.GetPropertyName(a.Name, false))); + return type.GetOpenApiTypeName(namingStrategy); } return namingStrategy.GetPropertyName(type.Name, hasSpecifiedName: false); @@ -532,8 +535,7 @@ public static string GetOpenApiTypeName(this Type type, NamingStrategy namingStr namingStrategy = new DefaultNamingStrategy(); } - var typeName = type.IsGenericType ? type.GetOpenApiGenericRootName() : type.Name; - var name = namingStrategy.GetPropertyName(typeName, hasSpecifiedName: false); + var name = string.Join("_", GetTypeNames(type, namingStrategy)); return name; } @@ -757,5 +759,32 @@ private static bool IsNullableType(this Type type, out Type underlyingType) return !underlyingType.IsNullOrDefault(); } + + private static IEnumerable GetTypeNames(Type type, NamingStrategy namingStrategy) + { + if (type.IsGenericType) + { + yield return namingStrategy.GetPropertyName(GetOpenApiGenericRootName(type), false); + + foreach (var argType in type.GetGenericArguments()) + { + foreach (var name in GetTypeNames(argType, namingStrategy)) + { + yield return namingStrategy.GetPropertyName(name, false); + } + } + } + else + { + if (type.Name.EndsWith("[]")) + { + yield return namingStrategy.GetPropertyName(type.Name.Substring(0, type.Name.Length - 2), false); + } + else + { + yield return namingStrategy.GetPropertyName(type.Name, false); + } + } + } } } diff --git a/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Visitors/BaseObjectTypeVisitor.cs b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Visitors/BaseObjectTypeVisitor.cs index e8dadd22..6eb1b42b 100644 --- a/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Visitors/BaseObjectTypeVisitor.cs +++ b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Visitors/BaseObjectTypeVisitor.cs @@ -3,6 +3,7 @@ using System.Linq; using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions; +using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Extensions; using Microsoft.OpenApi.Models; using Newtonsoft.Json.Serialization; @@ -31,11 +32,7 @@ public override bool IsVisitable(Type type) /// public override void Visit(IAcceptor acceptor, KeyValuePair type, NamingStrategy namingStrategy, params Attribute[] attributes) { - var title = type.Value.IsGenericType - ? namingStrategy.GetPropertyName(type.Value.Name.Split('`').First(), hasSpecifiedName: false) + "_" + - string.Join("_", - type.Value.GenericTypeArguments.Select(a => namingStrategy.GetPropertyName(a.Name, false))) - : namingStrategy.GetPropertyName(type.Value.Name, hasSpecifiedName: false); + var title = type.Value.GetOpenApiTypeName(namingStrategy); this.Visit(acceptor, name: type.Key, title: title, dataType: "object", dataFormat: null, attributes: attributes); } diff --git a/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Visitors/ObjectTypeVisitor.cs b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Visitors/ObjectTypeVisitor.cs index 9a1ff8a1..aabb1b79 100644 --- a/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Visitors/ObjectTypeVisitor.cs +++ b/src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Visitors/ObjectTypeVisitor.cs @@ -90,11 +90,7 @@ public override bool IsVisitable(Type type) /// public override void Visit(IAcceptor acceptor, KeyValuePair type, NamingStrategy namingStrategy, params Attribute[] attributes) { - var title = type.Value.IsGenericType - ? namingStrategy.GetPropertyName(type.Value.Name.Split('`').First(), hasSpecifiedName: false) + "_" + - string.Join("_", - type.Value.GenericTypeArguments.Select(a => namingStrategy.GetPropertyName(a.Name, false))) - : namingStrategy.GetPropertyName(type.Value.Name, hasSpecifiedName: false); + var title = type.Value.GetOpenApiTypeName(namingStrategy); var name = this.Visit(acceptor, name: type.Key, title: title, dataType: "object", dataFormat: null, attributes: attributes); if (name.IsNullOrWhiteSpace()) diff --git a/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Tests/Visitors/DictionaryObjectTypeVisitorTests.cs b/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Tests/Visitors/DictionaryObjectTypeVisitorTests.cs index 29615b4a..5bb8b5e6 100644 --- a/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Tests/Visitors/DictionaryObjectTypeVisitorTests.cs +++ b/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Tests/Visitors/DictionaryObjectTypeVisitorTests.cs @@ -91,10 +91,11 @@ public void Given_Type_When_IsPayloadVisitable_Invoked_Then_It_Should_Return_Res [DataRow(typeof(IReadOnlyDictionary), "object", null, "string", false, "string", 0)] [DataRow(typeof(KeyValuePair), "object", null, "string", false, "string", 0)] [DataRow(typeof(Dictionary), "object", null, "object", true, "fakeModel", 1)] - [DataRow(typeof(Dictionary), "object", null, "array", true, "list_string", 1)] // + [DataRow(typeof(Dictionary), "object", null, "array", true, "list_string", 1)] [DataRow(typeof(IDictionary), "object", null, "object", true, "fakeModel", 1)] [DataRow(typeof(IReadOnlyDictionary), "object", null, "object", true, "fakeModel", 1)] [DataRow(typeof(KeyValuePair), "object", null, "object", true, "fakeModel", 1)] + [DataRow(typeof(KeyValuePair>>), "object", null, "array", true, "list_fakeGenericModel_fakeModel", 1)] public void Given_Type_When_Visit_Invoked_Then_It_Should_Return_Result(Type dictionaryType, string dataType, string dataFormat, string additionalPropertyType, bool isReferential, string referenceId, int expected) { var name = "hello"; diff --git a/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Tests/Visitors/ObjectTypeVisitorTests.cs b/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Tests/Visitors/ObjectTypeVisitorTests.cs index ce0c40c2..5f035d46 100644 --- a/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Tests/Visitors/ObjectTypeVisitorTests.cs +++ b/test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Tests/Visitors/ObjectTypeVisitorTests.cs @@ -88,6 +88,7 @@ public void Given_Type_When_IsPayloadVisitable_Invoked_Then_It_Should_Return_Res [DataRow(typeof(FakeModel), "object", null, 3, 3, "fakeModel")] [DataRow(typeof(FakeRequiredModel), "object", null, 1, 0, "fakeRequiredModel")] [DataRow(typeof(FakeRecursiveModel), "object", null, 3, 2, "fakeRecursiveModel")] + [DataRow(typeof(FakeGenericModel>), "object", null, 0, 4, "fakeGenericModel_list_fakeModel")] public void Given_Type_When_Visit_Invoked_Then_It_Should_Return_Result(Type objectType, string dataType, string dataFormat, int requiredCount, int rootSchemaCount, string referenceId) { var name = "hello";