diff --git a/eng/Versions.props b/eng/Versions.props
index e8ac2069fc78..855ecbfcf973 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -329,8 +329,8 @@
$(XunitVersion)
2.4.3
4.0.5
- 1.6.13
- 1.6.13
+ 1.6.17
+ 1.6.17
6.0.322601
1.10.93
diff --git a/eng/testing/linker/project.csproj.template b/eng/testing/linker/project.csproj.template
index 68e6ab7b07b4..ea368a6caa54 100644
--- a/eng/testing/linker/project.csproj.template
+++ b/eng/testing/linker/project.csproj.template
@@ -16,8 +16,6 @@
$(InterceptorsPreviewNamespaces);Microsoft.AspNetCore.Http.Generated
false
-
- $(NoWarn);IL2104
{AdditionalProperties}
@@ -29,19 +27,4 @@
{AdditionalProjectReferences}
-
-
-
-
-
-
-
- true
- true
-
-
-
-
diff --git a/src/OpenApi/src/Comparers/OpenApiAnyComparer.cs b/src/OpenApi/src/Comparers/OpenApiAnyComparer.cs
index d6c7d3362110..7990446ab26e 100644
--- a/src/OpenApi/src/Comparers/OpenApiAnyComparer.cs
+++ b/src/OpenApi/src/Comparers/OpenApiAnyComparer.cs
@@ -42,7 +42,6 @@ public bool Equals(IOpenApiAny? x, IOpenApiAny? y)
OpenApiByte byteX => y is OpenApiByte byteY && byteX.Value.SequenceEqual(byteY.Value),
OpenApiDate dateX => y is OpenApiDate dateY && dateX.Value == dateY.Value,
OpenApiDateTime dateTimeX => y is OpenApiDateTime dateTimeY && dateTimeX.Value == dateTimeY.Value,
- ScrubbedOpenApiAny scrubbedX => y is ScrubbedOpenApiAny scrubbedY && scrubbedX.Value == scrubbedY.Value,
_ => x.Equals(y)
});
}
@@ -74,7 +73,6 @@ public int GetHashCode(IOpenApiAny obj)
OpenApiPassword password => password.Value,
OpenApiDate date => date.Value,
OpenApiDateTime dateTime => dateTime.Value,
- ScrubbedOpenApiAny scrubbed => scrubbed.Value,
_ => null
});
diff --git a/src/OpenApi/src/Comparers/OpenApiSchemaComparer.cs b/src/OpenApi/src/Comparers/OpenApiSchemaComparer.cs
index daf42772d89c..ef446367817a 100644
--- a/src/OpenApi/src/Comparers/OpenApiSchemaComparer.cs
+++ b/src/OpenApi/src/Comparers/OpenApiSchemaComparer.cs
@@ -65,7 +65,34 @@ public bool Equals(OpenApiSchema? x, OpenApiSchema? y)
x.UniqueItems == y.UniqueItems &&
x.UnresolvedReference == y.UnresolvedReference &&
x.WriteOnly == y.WriteOnly &&
- OpenApiXmlComparer.Instance.Equals(x.Xml, y.Xml);
+ OpenApiXmlComparer.Instance.Equals(x.Xml, y.Xml) &&
+ SchemaIdEquals(x, y);
+ }
+
+ private static bool SchemaIdEquals(OpenApiSchema x, OpenApiSchema y)
+ {
+ if (x.Annotations == null && y.Annotations == null)
+ {
+ return true;
+ }
+ if (x.Annotations == null || y.Annotations == null)
+ {
+ return false;
+ }
+ if (x.Annotations.TryGetValue(OpenApiConstants.SchemaId, out var xSchemaId)
+ && y.Annotations.TryGetValue(OpenApiConstants.SchemaId, out var ySchemaId))
+ {
+ if (xSchemaId == null && ySchemaId == null)
+ {
+ return true;
+ }
+ if (xSchemaId == null || ySchemaId == null)
+ {
+ return false;
+ }
+ return xSchemaId.Equals(ySchemaId);
+ }
+ return true;
}
public int GetHashCode(OpenApiSchema obj)
diff --git a/src/OpenApi/src/Extensions/OpenApiEndpointRouteBuilderExtensions.cs b/src/OpenApi/src/Extensions/OpenApiEndpointRouteBuilderExtensions.cs
index a5b7626ef6b5..ee105edddf6b 100644
--- a/src/OpenApi/src/Extensions/OpenApiEndpointRouteBuilderExtensions.cs
+++ b/src/OpenApi/src/Extensions/OpenApiEndpointRouteBuilderExtensions.cs
@@ -9,6 +9,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Extensions;
+using Microsoft.OpenApi.Writers;
namespace Microsoft.AspNetCore.Builder;
@@ -48,7 +49,7 @@ public static IEndpointConventionBuilder MapOpenApi(this IEndpointRouteBuilder e
using var writer = Utf8BufferTextWriter.Get(output);
try
{
- document.Serialize(new ScrubbingOpenApiJsonWriter(writer), documentOptions.OpenApiVersion);
+ document.Serialize(new OpenApiJsonWriter(writer), documentOptions.OpenApiVersion);
context.Response.ContentType = "application/json;charset=utf-8";
await context.Response.BodyWriter.WriteAsync(output.ToArray(), context.RequestAborted);
await context.Response.BodyWriter.FlushAsync(context.RequestAborted);
diff --git a/src/OpenApi/src/Schemas/OpenApiJsonSchema.Helpers.cs b/src/OpenApi/src/Schemas/OpenApiJsonSchema.Helpers.cs
index bf683f5afac1..6ad6b03af319 100644
--- a/src/OpenApi/src/Schemas/OpenApiJsonSchema.Helpers.cs
+++ b/src/OpenApi/src/Schemas/OpenApiJsonSchema.Helpers.cs
@@ -304,7 +304,8 @@ public static void ReadProperty(ref Utf8JsonReader reader, string propertyName,
break;
case OpenApiConstants.SchemaId:
reader.Read();
- schema.Extensions.Add(OpenApiConstants.SchemaId, new ScrubbedOpenApiAny(reader.GetString()));
+ schema.Annotations ??= new Dictionary();
+ schema.Annotations.Add(OpenApiConstants.SchemaId, reader.GetString());
break;
// OpenAPI does not support the `const` keyword in its schema implementation, so
// we map it to its closest approximation, an enum with a single value, here.
diff --git a/src/OpenApi/src/Services/OpenApiDocumentProvider.cs b/src/OpenApi/src/Services/OpenApiDocumentProvider.cs
index dd1b53e90ea6..6c453e177ebd 100644
--- a/src/OpenApi/src/Services/OpenApiDocumentProvider.cs
+++ b/src/OpenApi/src/Services/OpenApiDocumentProvider.cs
@@ -6,6 +6,7 @@
using Microsoft.Extensions.Options;
using Microsoft.OpenApi;
using Microsoft.OpenApi.Extensions;
+using Microsoft.OpenApi.Writers;
using System.Linq;
namespace Microsoft.Extensions.ApiDescriptions;
@@ -44,7 +45,7 @@ public async Task GenerateAsync(string documentName, TextWriter writer, OpenApiS
// more info.
var targetDocumentService = serviceProvider.GetRequiredKeyedService(documentName);
var document = await targetDocumentService.GetOpenApiDocumentAsync();
- var jsonWriter = new ScrubbingOpenApiJsonWriter(writer);
+ var jsonWriter = new OpenApiJsonWriter(writer);
document.Serialize(jsonWriter, openApiSpecVersion);
}
diff --git a/src/OpenApi/src/Services/OpenApiDocumentService.cs b/src/OpenApi/src/Services/OpenApiDocumentService.cs
index fed6794bf191..a351b75af827 100644
--- a/src/OpenApi/src/Services/OpenApiDocumentService.cs
+++ b/src/OpenApi/src/Services/OpenApiDocumentService.cs
@@ -99,9 +99,9 @@ internal async Task ForEachOperationAsync(
continue;
}
- if (operation.Extensions.TryGetValue(OpenApiConstants.DescriptionId, out var descriptionIdExtension) &&
- descriptionIdExtension is ScrubbedOpenApiAny { Value: string descriptionId } &&
- TryGetCachedOperationTransformerContext(descriptionId, out var operationContext))
+ if (operation.Annotations.TryGetValue(OpenApiConstants.DescriptionId, out var descriptionId) &&
+ descriptionId is string descriptionIdString &&
+ TryGetCachedOperationTransformerContext(descriptionIdString, out var operationContext))
{
await callback(operation, operationContext, cancellationToken);
}
@@ -169,7 +169,8 @@ private async Task> GetOperationsAsy
foreach (var description in descriptions)
{
var operation = await GetOperationAsync(description, capturedTags, cancellationToken);
- operation.Extensions.Add(OpenApiConstants.DescriptionId, new ScrubbedOpenApiAny(description.ActionDescriptor.Id));
+ operation.Annotations ??= new Dictionary();
+ operation.Annotations.Add(OpenApiConstants.DescriptionId, description.ActionDescriptor.Id);
var operationContext = new OpenApiOperationTransformerContext
{
diff --git a/src/OpenApi/src/Services/Schemas/OpenApiSchemaStore.cs b/src/OpenApi/src/Services/Schemas/OpenApiSchemaStore.cs
index c206176f8194..12698a2d9e45 100644
--- a/src/OpenApi/src/Services/Schemas/OpenApiSchemaStore.cs
+++ b/src/OpenApi/src/Services/Schemas/OpenApiSchemaStore.cs
@@ -104,9 +104,7 @@ public void PopulateSchemaIntoReferenceCache(OpenApiSchema schema, bool captureS
// AnyOf schemas in a polymorphic type should contain a reference to the parent schema
// ID to support disambiguating between a derived type on its own and a derived type
// as part of a polymorphic schema.
- var baseTypeSchemaId = schema.Extensions.TryGetValue(OpenApiConstants.SchemaId, out var schemaId)
- ? ((ScrubbedOpenApiAny)schemaId).Value
- : null;
+ var baseTypeSchemaId = schema.Annotations is not null && schema.Annotations.TryGetValue(OpenApiConstants.SchemaId, out var schemaId) ? schemaId?.ToString() : null;
foreach (var anyOfSchema in schema.AnyOf)
{
AddOrUpdateSchemaByReference(anyOfSchema, baseTypeSchemaId);
@@ -176,8 +174,8 @@ private void AddOrUpdateSchemaByReference(OpenApiSchema schema, string? baseType
private static string? GetSchemaReferenceId(OpenApiSchema schema)
{
- if (schema.Extensions.TryGetValue(OpenApiConstants.SchemaId, out var referenceIdAny)
- && referenceIdAny is ScrubbedOpenApiAny { Value: string referenceId })
+ if (schema.Annotations?.TryGetValue(OpenApiConstants.SchemaId, out var referenceIdObject) == true
+ && referenceIdObject is string referenceId)
{
return referenceId;
}
diff --git a/src/OpenApi/src/Writers/ScrubbedOpenApiAny.cs b/src/OpenApi/src/Writers/ScrubbedOpenApiAny.cs
deleted file mode 100644
index 939ca06496c5..000000000000
--- a/src/OpenApi/src/Writers/ScrubbedOpenApiAny.cs
+++ /dev/null
@@ -1,30 +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;
-using Microsoft.OpenApi.Any;
-using Microsoft.OpenApi.Writers;
-
-namespace Microsoft.AspNetCore.OpenApi;
-
-///
-/// Represents an instance that does not serialize itself to
-/// the outgoing document.
-///
-/// The no-op implementation of the method
-/// prevents the value of these properties from being written to disk. When used in conjunction with
-/// the logic to exempt these properties from serialization in ,
-/// we achieve the desired result of not serializing these properties to the output document but retaining
-/// them in the in-memory document.
-///
-internal sealed class ScrubbedOpenApiAny(string? value) : IOpenApiAny
-{
- public AnyType AnyType { get; } = AnyType.Primitive;
-
- public string? Value { get; } = value;
-
- public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
- {
- return;
- }
-}
diff --git a/src/OpenApi/src/Writers/ScrubbingOpenApiJsonWriter.cs b/src/OpenApi/src/Writers/ScrubbingOpenApiJsonWriter.cs
deleted file mode 100644
index fdf9a00210d9..000000000000
--- a/src/OpenApi/src/Writers/ScrubbingOpenApiJsonWriter.cs
+++ /dev/null
@@ -1,30 +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.Writers;
-
-namespace Microsoft.AspNetCore.OpenApi;
-
-///
-/// Represents a JSON writer that scrubs certain properties from the output,
-/// specifically the schema ID and description ID that are used for schema resolution
-/// and action descriptor resolution in the in-memory OpenAPI document.
-///
-/// In conjunction with this allows us to work around
-/// the lack of an in-memory property bag on the OpenAPI object model and allows us to
-/// avoid having to scrub the properties in the OpenAPI document prior to serialization.
-///
-/// For more information, see https://github.com/microsoft/OpenAPI.NET/issues/1719.
-///
-internal sealed class ScrubbingOpenApiJsonWriter(TextWriter textWriter) : OpenApiJsonWriter(textWriter)
-{
- public override void WritePropertyName(string name)
- {
- if (name == OpenApiConstants.SchemaId || name == OpenApiConstants.DescriptionId)
- {
- return;
- }
-
- base.WritePropertyName(name);
- }
-}
diff --git a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Comparers/OpenApiAnyComparerTests.cs b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Comparers/OpenApiAnyComparerTests.cs
index 7ef5afdfe2bb..18ab3e1b27b3 100644
--- a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Comparers/OpenApiAnyComparerTests.cs
+++ b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Comparers/OpenApiAnyComparerTests.cs
@@ -40,9 +40,6 @@ public class OpenApiAnyComparerTests
[new OpenApiArray { new OpenApiString("value") }, new OpenApiArray { new OpenApiString("value2") }, false],
[new OpenApiArray { new OpenApiString("value2"), new OpenApiString("value") }, new OpenApiArray { new OpenApiString("value"), new OpenApiString("value2") }, false],
[new OpenApiArray { new OpenApiString("value"), new OpenApiString("value") }, new OpenApiArray { new OpenApiString("value"), new OpenApiString("value") }, true],
- [new ScrubbedOpenApiAny("value"), new ScrubbedOpenApiAny("value"), true],
- [new ScrubbedOpenApiAny("value"), new ScrubbedOpenApiAny("value2"), false],
- [new ScrubbedOpenApiAny(null), new ScrubbedOpenApiAny(null), true]
];
[Theory]
diff --git a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Comparers/OpenApiSchemaComparerTests.cs b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Comparers/OpenApiSchemaComparerTests.cs
index 3678c4c58734..56fb593c526b 100644
--- a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Comparers/OpenApiSchemaComparerTests.cs
+++ b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Comparers/OpenApiSchemaComparerTests.cs
@@ -144,6 +144,7 @@ public void ValidatePropertiesOnOpenApiSchema()
UnresolvedReference = true,
WriteOnly = true,
Xml = new OpenApiXml { Name = "Name" },
+ Annotations = new Dictionary { ["key"] = "value" }
};
OpenApiSchema modifiedSchema = new(originalSchema) { AdditionalProperties = new OpenApiSchema { Type = "string" } };
@@ -302,6 +303,11 @@ public void ValidatePropertiesOnOpenApiSchema()
Assert.False(OpenApiSchemaComparer.Instance.Equals(originalSchema, modifiedSchema));
Assert.True(propertyNames.Remove(nameof(OpenApiSchema.Xml)));
+ modifiedSchema = new(originalSchema);
+ modifiedSchema.Annotations["key"] = "another value";
+ Assert.False(OpenApiSchemaComparer.Instance.Equals(originalSchema, modifiedSchema));
+ Assert.True(propertyNames.Remove(nameof(OpenApiSchema.Annotations)));
+
Assert.Empty(propertyNames);
}
}
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 9655c4d09c53..def8474834f9 100644
--- a/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/OpenApiDocumentIntegrationTests.cs
+++ b/src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/OpenApiDocumentIntegrationTests.cs
@@ -32,7 +32,7 @@ await Verifier.Verify(GetOpenApiJson(document))
private static string GetOpenApiJson(OpenApiDocument document)
{
using var textWriter = new StringWriter(CultureInfo.InvariantCulture);
- var jsonWriter = new ScrubbingOpenApiJsonWriter(textWriter);
+ var jsonWriter = new OpenApiJsonWriter(textWriter);
document.SerializeAsV3(jsonWriter);
return textWriter.ToString();
}