diff --git a/eng/Versions.props b/eng/Versions.props index 6bdaa4d129b0..1f5d2152f720 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -335,8 +335,8 @@ $(XunitVersion) 2.8.2 5.2.2 - 2.0.0-preview7 - 2.0.0-preview7 + 2.0.0-preview.11 + 2.0.0-preview.11 6.0.322601 1.10.93 diff --git a/src/OpenApi/src/Comparers/OpenApiTagComparer.cs b/src/OpenApi/src/Comparers/OpenApiTagComparer.cs deleted file mode 100644 index 7154553e932c..000000000000 --- a/src/OpenApi/src/Comparers/OpenApiTagComparer.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Microsoft.OpenApi.Models; - -namespace Microsoft.AspNetCore.OpenApi; - -/// -/// This comparer is used to maintain a globally unique list of tags encountered -/// in a particular OpenAPI document. -/// -internal sealed class OpenApiTagComparer : IEqualityComparer -{ - public static OpenApiTagComparer Instance { get; } = new OpenApiTagComparer(); - - public bool Equals(OpenApiTag? x, OpenApiTag? y) - { - if (x is null && y is null) - { - return true; - } - if (x is null || y is null) - { - return false; - } - if (object.ReferenceEquals(x, y)) - { - return true; - } - - // Tag comparisons are case-sensitive by default. Although the OpenAPI specification - // only outlines case sensitivity for property names, we extend this principle to - // property values for tag names as well. - // See https://spec.openapis.org/oas/v3.1.0#format. - return string.Equals(x.Name, y.Name, StringComparison.Ordinal); - } - - public int GetHashCode(OpenApiTag obj) => obj.Name.GetHashCode(); -} diff --git a/src/OpenApi/src/Services/OpenApiDocumentService.cs b/src/OpenApi/src/Services/OpenApiDocumentService.cs index c8775e6b8e24..091bb4931098 100644 --- a/src/OpenApi/src/Services/OpenApiDocumentService.cs +++ b/src/OpenApi/src/Services/OpenApiDocumentService.cs @@ -75,7 +75,6 @@ public async Task GetOpenApiDocumentAsync(IServiceProvider scop Servers = GetOpenApiServers(httpRequest) }; document.Paths = await GetOpenApiPathsAsync(document, scopedServiceProvider, operationTransformers, schemaTransformers, cancellationToken); - document.Tags = document.Tags?.Distinct(OpenApiTagComparer.Instance).ToList(); try { await ApplyTransformersAsync(document, scopedServiceProvider, cancellationToken); @@ -327,15 +326,15 @@ private async Task GetOperationAsync( => description.ActionDescriptor.AttributeRouteInfo?.Name ?? description.ActionDescriptor.EndpointMetadata.OfType().LastOrDefault()?.EndpointName; - private static List GetTags(ApiDescription description, OpenApiDocument document) + private static HashSet GetTags(ApiDescription description, OpenApiDocument document) { var actionDescriptor = description.ActionDescriptor; if (actionDescriptor.EndpointMetadata?.OfType().LastOrDefault() is { } tagsMetadata) { - List tags = []; + HashSet tags = []; foreach (var tag in tagsMetadata.Tags) { - document.Tags ??= []; + document.Tags ??= new HashSet(); document.Tags.Add(new OpenApiTag { Name = tag }); tags.Add(new OpenApiTagReference(tag, document)); @@ -345,9 +344,9 @@ private static List GetTags(ApiDescription description, Ope // If no tags are specified, use the controller name as the tag. This effectively // allows us to group endpoints by the "resource" concept (e.g. users, todos, etc.) var controllerName = description.ActionDescriptor.RouteValues["controller"]; - document.Tags ??= []; + document.Tags ??= new HashSet(); document.Tags.Add(new OpenApiTag { Name = controllerName }); - return [new OpenApiTagReference(controllerName, document)]; + return [new(controllerName, document)]; } private async Task GetResponsesAsync( diff --git a/src/OpenApi/src/Services/OpenApiGenerator.cs b/src/OpenApi/src/Services/OpenApiGenerator.cs index a96ab12c5b85..5d321bd95382 100644 --- a/src/OpenApi/src/Services/OpenApiGenerator.cs +++ b/src/OpenApi/src/Services/OpenApiGenerator.cs @@ -324,20 +324,20 @@ private static void GenerateDefaultResponses(Dictionary GetOperationTags(MethodInfo methodInfo, EndpointMetadataCollection metadata) + private HashSet GetOperationTags(MethodInfo methodInfo, EndpointMetadataCollection metadata) { var metadataList = metadata.GetOrderedMetadata(); var document = new OpenApiDocument(); if (metadataList.Count > 0) { - var tags = new List(); + var tags = new HashSet(); foreach (var metadataItem in metadataList) { foreach (var tag in metadataItem.Tags) { - document.Tags ??= []; + document.Tags ??= new HashSet(); document.Tags.Add(new OpenApiTag { Name = tag }); tags.Add(new OpenApiTagReference(tag, document)); } @@ -359,7 +359,7 @@ private List GetOperationTags(MethodInfo methodInfo, Endpoi controllerName = _environment?.ApplicationName ?? string.Empty; } - document.Tags ??= []; + document.Tags ??= new HashSet(); document.Tags.Add(new OpenApiTag { Name = controllerName }); return [new(controllerName, document)]; } diff --git a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Extensions/OpenApiEndpointRouteBuilderExtensionsTests.cs b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Extensions/OpenApiEndpointRouteBuilderExtensionsTests.cs index 9ec026f0df93..59813644f53c 100644 --- a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Extensions/OpenApiEndpointRouteBuilderExtensionsTests.cs +++ b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Extensions/OpenApiEndpointRouteBuilderExtensionsTests.cs @@ -235,8 +235,9 @@ await ValidateOpenApiDocumentAsync(responseBodyStream, document => private static async Task ValidateOpenApiDocumentAsync(MemoryStream documentStream, Action action, string format = "json") { documentStream.Position = 0; - OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader()); - var result = await OpenApiDocument.LoadAsync(documentStream, format); + var readerSettings = new OpenApiReaderSettings(); + readerSettings.AddYamlReader(); + var result = await OpenApiDocument.LoadAsync(documentStream, format, readerSettings); Assert.Empty(result.Diagnostic.Errors); action(result.Document); } diff --git a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/OpenApiDocumentIntegrationTests.cs b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/OpenApiDocumentIntegrationTests.cs index dae562746d3f..797b295c25a0 100644 --- a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/OpenApiDocumentIntegrationTests.cs +++ b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/OpenApiDocumentIntegrationTests.cs @@ -11,10 +11,6 @@ [UsesVerify] public sealed class OpenApiDocumentIntegrationTests(SampleAppFixture fixture) : IClassFixture { - private static Regex DateTimeRegex() => new( - @"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{7}[+-]\d{2}:\d{2}", - RegexOptions.Compiled); - [Theory] [InlineData("v1", OpenApiSpecVersion.OpenApi3_0)] [InlineData("v2", OpenApiSpecVersion.OpenApi3_0)] @@ -42,7 +38,6 @@ public async Task VerifyOpenApiDocument(string documentName, OpenApiSpecVersion var outputDirectory = Path.Combine(baseSnapshotsDirectory, version.ToString()); await Verifier.Verify(json) .UseDirectory(outputDirectory) - .ScrubLinesWithReplace(line => DateTimeRegex().Replace(line, "[datetime]")) .UseParameters(documentName); } } diff --git a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/snapshots/OpenApi3_0/OpenApiDocumentIntegrationTests.VerifyOpenApiDocument_documentName=xml.verified.txt b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/snapshots/OpenApi3_0/OpenApiDocumentIntegrationTests.VerifyOpenApiDocument_documentName=xml.verified.txt index 4417a72d5dfb..9eed2206b116 100644 --- a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/snapshots/OpenApi3_0/OpenApiDocumentIntegrationTests.VerifyOpenApiDocument_documentName=xml.verified.txt +++ b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/snapshots/OpenApi3_0/OpenApiDocumentIntegrationTests.VerifyOpenApiDocument_documentName=xml.verified.txt @@ -375,12 +375,12 @@ "dateTimeType": { "type": "string", "format": "date-time", - "example": "[datetime]" + "example": "2022-01-01T00:00:00Z" }, "dateOnlyType": { "type": "string", "format": "date", - "example": "[datetime]" + "example": "2022-01-01" } } } diff --git a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/snapshots/OpenApi3_1/OpenApiDocumentIntegrationTests.VerifyOpenApiDocument_documentName=xml.verified.txt b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/snapshots/OpenApi3_1/OpenApiDocumentIntegrationTests.VerifyOpenApiDocument_documentName=xml.verified.txt index d90741d5d1fd..4a8829575928 100644 --- a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/snapshots/OpenApi3_1/OpenApiDocumentIntegrationTests.VerifyOpenApiDocument_documentName=xml.verified.txt +++ b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/snapshots/OpenApi3_1/OpenApiDocumentIntegrationTests.VerifyOpenApiDocument_documentName=xml.verified.txt @@ -375,12 +375,12 @@ "dateTimeType": { "type": "string", "format": "date-time", - "example": "[datetime]" + "example": "2022-01-01T00:00:00Z" }, "dateOnlyType": { "type": "string", "format": "date", - "example": "[datetime]" + "example": "2022-01-01" } } }