Skip to content

Commit ddb99d6

Browse files
committed
Updated schema reference XML Comment handling.
Update handling of nested schemas and referenced schemas
1 parent 14dd22b commit ddb99d6

File tree

4 files changed

+106
-21
lines changed

4 files changed

+106
-21
lines changed

src/OpenApi/gen/XmlCommentGenerator.Emitter.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,14 @@ private static OpenApiParameter UnwrapOpenApiParameter(IOpenApiParameter sourceP
423423
{
424424
public Task TransformAsync(OpenApiSchema schema, OpenApiSchemaTransformerContext context, CancellationToken cancellationToken)
425425
{
426+
if (XmlCommentCache.Cache.TryGetValue(context.JsonTypeInfo.Type.CreateDocumentationId(), out var typeComment))
427+
{
428+
schema.Description = typeComment.Summary;
429+
if (typeComment.Examples?.FirstOrDefault() is { } jsonString)
430+
{
431+
schema.Example = jsonString.Parse();
432+
}
433+
}
426434
if (context.JsonPropertyInfo is { AttributeProvider: PropertyInfo propertyInfo })
427435
{
428436
if (XmlCommentCache.Cache.TryGetValue(propertyInfo.CreateDocumentationId(), out var propertyComment))
@@ -434,14 +442,6 @@ public Task TransformAsync(OpenApiSchema schema, OpenApiSchemaTransformerContext
434442
}
435443
}
436444
}
437-
if (XmlCommentCache.Cache.TryGetValue(context.JsonTypeInfo.Type.CreateDocumentationId(), out var typeComment))
438-
{
439-
schema.Description = typeComment.Summary;
440-
if (typeComment.Examples?.FirstOrDefault() is { } jsonString)
441-
{
442-
schema.Example = jsonString.Parse();
443-
}
444-
}
445445
return Task.CompletedTask;
446446
}
447447
}

src/OpenApi/src/Extensions/OpenApiDocumentExtensions.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ public static IOpenApiSchema AddOpenApiSchemaByReference(this OpenApiDocument do
2525
document.Workspace ??= new();
2626
var location = document.BaseUri + "/components/schemas/" + schemaId;
2727
document.Workspace.RegisterComponentForDocument(document, schema, location);
28-
return new OpenApiSchemaReference(schemaId, document);
28+
return new OpenApiSchemaReference(schemaId, document)
29+
{
30+
Description = schema.Description,
31+
};
2932
}
3033
}

src/OpenApi/test/Microsoft.AspNetCore.OpenApi.SourceGenerators.Tests/SchemaTests.cs

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ public async Task SupportsXmlCommentsOnSchemas()
1919
2020
var builder = WebApplication.CreateBuilder();
2121
22-
builder.Services.AddOpenApi();
22+
builder.Services.AddOpenApi(options => {
23+
var prevCreateSchemaReferenceId = options.CreateSchemaReferenceId;
24+
options.CreateSchemaReferenceId = (x) => x.Type == typeof(AddressNested) ? null : prevCreateSchemaReferenceId(x);
25+
});
2326
2427
var app = builder.Build();
2528
@@ -31,6 +34,7 @@ public async Task SupportsXmlCommentsOnSchemas()
3134
app.MapPost("/todo-with-description", (TodoWithDescription todo) => { });
3235
app.MapPost("/type-with-examples", (TypeWithExamples typeWithExamples) => { });
3336
app.MapPost("/user", (User user) => { });
37+
app.MapPost("/company", (Company company) => { });
3438
3539
app.Run();
3640
@@ -175,6 +179,60 @@ internal class User : IUser
175179
/// <inheritdoc/>
176180
public string Name { get; set; }
177181
}
182+
183+
/// <summary>
184+
/// An address.
185+
/// </summary>
186+
public class AddressWithSummary
187+
{
188+
public string Street { get; set; }
189+
}
190+
191+
public class AddressWithoutSummary
192+
{
193+
public string Street { get; set; }
194+
}
195+
196+
/// <summary>
197+
/// An address.
198+
/// </summary>
199+
public class AddressNested
200+
{
201+
public string Street { get; set; }
202+
}
203+
204+
public class Company
205+
{
206+
/// <summary>
207+
/// Billing address.
208+
/// </summary>
209+
public AddressWithSummary BillingAddressClassWithSummary { get; set; }
210+
211+
/// <summary>
212+
/// Billing address.
213+
/// </summary>
214+
public AddressWithoutSummary BillingAddressClassWithoutSummary { get; set; }
215+
216+
/// <summary>
217+
/// Billing address.
218+
/// </summary>
219+
public AddressNested BillingAddressNested { get; set; }
220+
221+
/// <summary>
222+
/// Visiting address.
223+
/// </summary>
224+
public AddressWithSummary VisitingAddressClassWithSummary { get; set; }
225+
226+
/// <summary>
227+
/// Visiting address.
228+
/// </summary>
229+
public AddressWithoutSummary VisitingAddressClassWithoutSummary { get; set; }
230+
231+
/// <summary>
232+
/// Visiting address.
233+
/// </summary>
234+
public AddressNested VisitingAddressNested { get; set; }
235+
}
178236
""";
179237
var generator = new XmlCommentGenerator();
180238
await SnapshotTestHelper.Verify(source, generator, out var compilation);
@@ -258,6 +316,21 @@ await SnapshotTestHelper.VerifyOpenApi(compilation, document =>
258316
var user = path.RequestBody.Content["application/json"].Schema;
259317
Assert.Equal("The unique identifier for the user.", user.Properties["id"].Description);
260318
Assert.Equal("The user's display name.", user.Properties["name"].Description);
319+
320+
path = document.Paths["/company"].Operations[HttpMethod.Post];
321+
var company = path.RequestBody.Content["application/json"].Schema;
322+
Assert.Equal("Billing address.", company.Properties["billingAddressClassWithSummary"].Description);
323+
Assert.Equal("Billing address.", company.Properties["billingAddressClassWithoutSummary"].Description);
324+
Assert.Equal("Billing address.", company.Properties["billingAddressNested"].Description);
325+
Assert.Equal("Visiting address.", company.Properties["visitingAddressClassWithSummary"].Description);
326+
Assert.Equal("Visiting address.", company.Properties["visitingAddressClassWithoutSummary"].Description);
327+
Assert.Equal("Visiting address.", company.Properties["visitingAddressNested"].Description);
328+
329+
var addressWithSummary = document.Components.Schemas["AddressWithSummary"];
330+
Assert.Equal("An address.", addressWithSummary.Description);
331+
332+
var addressWithoutSummary = document.Components.Schemas["AddressWithoutSummary"];
333+
Assert.Null(addressWithSummary.Description);
261334
});
262335
}
263336
}

src/OpenApi/test/Microsoft.AspNetCore.OpenApi.SourceGenerators.Tests/snapshots/SchemaTests.SupportsXmlCommentsOnSchemas#OpenApiXmlCommentSupport.generated.verified.cs

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//HintName: OpenApiXmlCommentSupport.generated.cs
1+
//HintName: OpenApiXmlCommentSupport.generated.cs
22
//------------------------------------------------------------------------------
33
// <auto-generated>
44
// This code was generated by a tool.
@@ -78,6 +78,8 @@ private static Dictionary<string, XmlComment> GenerateCacheEntries()
7878
cache.Add(@"T:ProjectBoard.ProtectedInternalElement", new XmlComment(@"Can find this XML comment.", null, null, null, null, false, null, null, null));
7979
cache.Add(@"T:ProjectRecord", new XmlComment(@"The project that contains Todo items.", null, null, null, null, false, null, [new XmlParameterComment(@"Name", @"The name of the project.", null, false), new XmlParameterComment(@"Description", @"The description of the project.", null, false)], null));
8080
cache.Add(@"T:User", new XmlComment(null, null, null, null, null, false, null, null, null));
81+
cache.Add(@"T:AddressWithSummary", new XmlComment(@"An address.", null, null, null, null, false, null, null, null));
82+
cache.Add(@"T:AddressNested", new XmlComment(@"An address.", null, null, null, null, false, null, null, null));
8183
cache.Add(@"P:ProjectBoard.ProtectedInternalElement.Name", new XmlComment(@"The unique identifier for the element.", null, null, null, null, false, null, null, null));
8284
cache.Add(@"P:ProjectRecord.Name", new XmlComment(@"The name of the project.", null, null, null, null, false, null, null, null));
8385
cache.Add(@"P:ProjectRecord.Description", new XmlComment(@"The description of the project.", null, null, null, null, false, null, null, null));
@@ -102,6 +104,12 @@ private static Dictionary<string, XmlComment> GenerateCacheEntries()
102104
cache.Add(@"P:IUser.Name", new XmlComment(@"The user's display name.", null, null, null, null, false, null, null, null));
103105
cache.Add(@"P:User.Id", new XmlComment(@"The unique identifier for the user.", null, null, null, null, false, null, null, null));
104106
cache.Add(@"P:User.Name", new XmlComment(@"The user's display name.", null, null, null, null, false, null, null, null));
107+
cache.Add(@"P:Company.BillingAddressClassWithSummary", new XmlComment(@"Billing address.", null, null, null, null, false, null, null, null));
108+
cache.Add(@"P:Company.BillingAddressClassWithoutSummary", new XmlComment(@"Billing address.", null, null, null, null, false, null, null, null));
109+
cache.Add(@"P:Company.BillingAddressNested", new XmlComment(@"Billing address.", null, null, null, null, false, null, null, null));
110+
cache.Add(@"P:Company.VisitingAddressClassWithSummary", new XmlComment(@"Visiting address.", null, null, null, null, false, null, null, null));
111+
cache.Add(@"P:Company.VisitingAddressClassWithoutSummary", new XmlComment(@"Visiting address.", null, null, null, null, false, null, null, null));
112+
cache.Add(@"P:Company.VisitingAddressNested", new XmlComment(@"Visiting address.", null, null, null, null, false, null, null, null));
105113

106114
return cache;
107115
}
@@ -435,6 +443,14 @@ private static OpenApiParameter UnwrapOpenApiParameter(IOpenApiParameter sourceP
435443
{
436444
public Task TransformAsync(OpenApiSchema schema, OpenApiSchemaTransformerContext context, CancellationToken cancellationToken)
437445
{
446+
if (XmlCommentCache.Cache.TryGetValue(context.JsonTypeInfo.Type.CreateDocumentationId(), out var typeComment))
447+
{
448+
schema.Description = typeComment.Summary;
449+
if (typeComment.Examples?.FirstOrDefault() is { } jsonString)
450+
{
451+
schema.Example = jsonString.Parse();
452+
}
453+
}
438454
if (context.JsonPropertyInfo is { AttributeProvider: PropertyInfo propertyInfo })
439455
{
440456
if (XmlCommentCache.Cache.TryGetValue(propertyInfo.CreateDocumentationId(), out var propertyComment))
@@ -446,14 +462,6 @@ public Task TransformAsync(OpenApiSchema schema, OpenApiSchemaTransformerContext
446462
}
447463
}
448464
}
449-
if (XmlCommentCache.Cache.TryGetValue(context.JsonTypeInfo.Type.CreateDocumentationId(), out var typeComment))
450-
{
451-
schema.Description = typeComment.Summary;
452-
if (typeComment.Examples?.FirstOrDefault() is { } jsonString)
453-
{
454-
schema.Example = jsonString.Parse();
455-
}
456-
}
457465
return Task.CompletedTask;
458466
}
459467
}
@@ -490,14 +498,15 @@ file static class JsonNodeExtensions
490498
file static class GeneratedServiceCollectionExtensions
491499
{
492500
[InterceptsLocation]
493-
public static IServiceCollection AddOpenApi(this IServiceCollection services)
501+
public static IServiceCollection AddOpenApi(this IServiceCollection services, Action<OpenApiOptions> configureOptions)
494502
{
495503
return services.AddOpenApi("v1", options =>
496504
{
497505
options.AddSchemaTransformer(new XmlCommentSchemaTransformer());
498506
options.AddOperationTransformer(new XmlCommentOperationTransformer());
507+
configureOptions(options);
499508
});
500509
}
501510

502511
}
503-
}
512+
}

0 commit comments

Comments
 (0)