Skip to content

Commit 26df7df

Browse files
authored
Add TBuilder overloads to WithTags and others (#41830)
1 parent 87d7296 commit 26df7df

File tree

4 files changed

+233
-57
lines changed

4 files changed

+233
-57
lines changed

src/Http/Routing/src/Builder/OpenApiRouteHandlerBuilderExtensions.cs

Lines changed: 70 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,23 @@ public static class OpenApiRouteHandlerBuilderExtensions
1616
{
1717
private static readonly ExcludeFromDescriptionAttribute _excludeFromDescriptionMetadataAttribute = new();
1818

19+
/// <summary>
20+
/// Adds the <see cref="IExcludeFromDescriptionMetadata"/> to <see cref="EndpointBuilder.Metadata"/> for all endpoints
21+
/// produced by <paramref name="builder"/>.
22+
/// </summary>
23+
/// <param name="builder">The <see cref="IEndpointConventionBuilder"/>.</param>
24+
/// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
25+
public static TBuilder ExcludeFromDescription<TBuilder>(this TBuilder builder) where TBuilder : IEndpointConventionBuilder
26+
=> builder.WithMetadata(_excludeFromDescriptionMetadataAttribute);
27+
1928
/// <summary>
2029
/// Adds the <see cref="IExcludeFromDescriptionMetadata"/> to <see cref="EndpointBuilder.Metadata"/> for all endpoints
2130
/// produced by <paramref name="builder"/>.
2231
/// </summary>
2332
/// <param name="builder">The <see cref="RouteHandlerBuilder"/>.</param>
2433
/// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
2534
public static RouteHandlerBuilder ExcludeFromDescription(this RouteHandlerBuilder builder)
26-
{
27-
builder.WithMetadata(_excludeFromDescriptionMetadataAttribute);
28-
29-
return builder;
30-
}
35+
=> ExcludeFromDescription<RouteHandlerBuilder>(builder);
3136

3237
/// <summary>
3338
/// Adds an <see cref="IProducesResponseTypeMetadata"/> to <see cref="EndpointBuilder.Metadata"/> for all endpoints
@@ -40,9 +45,10 @@ public static RouteHandlerBuilder ExcludeFromDescription(this RouteHandlerBuilde
4045
/// <param name="additionalContentTypes">Additional response content types the endpoint produces for the supplied status code.</param>
4146
/// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
4247
#pragma warning disable RS0026
43-
public static RouteHandlerBuilder Produces<TResponse>(this RouteHandlerBuilder builder,
48+
public static RouteHandlerBuilder Produces<TResponse>(
4449
#pragma warning restore RS0026
45-
int statusCode = StatusCodes.Status200OK,
50+
this RouteHandlerBuilder builder,
51+
int statusCode = StatusCodes.Status200OK,
4652
string? contentType = null,
4753
params string[] additionalContentTypes)
4854
{
@@ -60,9 +66,10 @@ public static RouteHandlerBuilder Produces<TResponse>(this RouteHandlerBuilder b
6066
/// <param name="additionalContentTypes">Additional response content types the endpoint produces for the supplied status code.</param>
6167
/// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
6268
#pragma warning disable RS0026
63-
public static RouteHandlerBuilder Produces(this RouteHandlerBuilder builder,
69+
public static RouteHandlerBuilder Produces(
6470
#pragma warning restore RS0026
65-
int statusCode,
71+
this RouteHandlerBuilder builder,
72+
int statusCode,
6673
Type? responseType = null,
6774
string? contentType = null,
6875
params string[] additionalContentTypes)
@@ -74,13 +81,10 @@ public static RouteHandlerBuilder Produces(this RouteHandlerBuilder builder,
7481

7582
if (contentType is null)
7683
{
77-
builder.WithMetadata(new ProducesResponseTypeMetadata(responseType ?? typeof(void), statusCode));
78-
return builder;
84+
return builder.WithMetadata(new ProducesResponseTypeMetadata(responseType ?? typeof(void), statusCode));
7985
}
8086

81-
builder.WithMetadata(new ProducesResponseTypeMetadata(responseType ?? typeof(void), statusCode, contentType, additionalContentTypes));
82-
83-
return builder;
87+
return builder.WithMetadata(new ProducesResponseTypeMetadata(responseType ?? typeof(void), statusCode, contentType, additionalContentTypes));
8488
}
8589

8690
/// <summary>
@@ -91,16 +95,14 @@ public static RouteHandlerBuilder Produces(this RouteHandlerBuilder builder,
9195
/// <param name="statusCode">The response status code.</param>
9296
/// <param name="contentType">The response content type. Defaults to "application/problem+json".</param>
9397
/// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
94-
public static RouteHandlerBuilder ProducesProblem(this RouteHandlerBuilder builder,
95-
int statusCode,
96-
string? contentType = null)
98+
public static RouteHandlerBuilder ProducesProblem(this RouteHandlerBuilder builder, int statusCode, string? contentType = null)
9799
{
98100
if (string.IsNullOrEmpty(contentType))
99101
{
100102
contentType = "application/problem+json";
101103
}
102104

103-
return Produces<ProblemDetails>(builder, statusCode, contentType);
105+
return Produces(builder, statusCode, typeof(ProblemDetails), contentType);
104106
}
105107

106108
/// <summary>
@@ -111,7 +113,8 @@ public static RouteHandlerBuilder ProducesProblem(this RouteHandlerBuilder build
111113
/// <param name="statusCode">The response status code. Defaults to <see cref="StatusCodes.Status400BadRequest"/>.</param>
112114
/// <param name="contentType">The response content type. Defaults to "application/problem+json".</param>
113115
/// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
114-
public static RouteHandlerBuilder ProducesValidationProblem(this RouteHandlerBuilder builder,
116+
public static RouteHandlerBuilder ProducesValidationProblem(
117+
this RouteHandlerBuilder builder,
115118
int statusCode = StatusCodes.Status400BadRequest,
116119
string? contentType = null)
117120
{
@@ -120,9 +123,24 @@ public static RouteHandlerBuilder ProducesValidationProblem(this RouteHandlerBui
120123
contentType = "application/problem+json";
121124
}
122125

123-
return Produces<HttpValidationProblemDetails>(builder, statusCode, contentType);
126+
return Produces(builder, statusCode, typeof(HttpValidationProblemDetails), contentType);
124127
}
125128

129+
/// <summary>
130+
/// Adds the <see cref="ITagsMetadata"/> to <see cref="EndpointBuilder.Metadata"/> for all endpoints
131+
/// produced by <paramref name="builder"/>.
132+
/// </summary>
133+
/// <remarks>
134+
/// The OpenAPI specification supports a tags classification to categorize operations
135+
/// into related groups. These tags are typically included in the generated specification
136+
/// and are typically used to group operations by tags in the UI.
137+
/// </remarks>
138+
/// <param name="builder">The <see cref="IEndpointConventionBuilder"/>.</param>
139+
/// <param name="tags">A collection of tags to be associated with the endpoint.</param>
140+
/// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
141+
public static TBuilder WithTags<TBuilder>(this TBuilder builder, params string[] tags) where TBuilder : IEndpointConventionBuilder
142+
=> builder.WithMetadata(new TagsAttribute(tags));
143+
126144
/// <summary>
127145
/// Adds the <see cref="ITagsMetadata"/> to <see cref="EndpointBuilder.Metadata"/> for all endpoints
128146
/// produced by <paramref name="builder"/>.
@@ -136,10 +154,7 @@ public static RouteHandlerBuilder ProducesValidationProblem(this RouteHandlerBui
136154
/// <param name="tags">A collection of tags to be associated with the endpoint.</param>
137155
/// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
138156
public static RouteHandlerBuilder WithTags(this RouteHandlerBuilder builder, params string[] tags)
139-
{
140-
builder.WithMetadata(new TagsAttribute(tags));
141-
return builder;
142-
}
157+
=> WithTags<RouteHandlerBuilder>(builder, tags);
143158

144159
/// <summary>
145160
/// Adds <see cref="IAcceptsMetadata"/> to <see cref="EndpointBuilder.Metadata"/> for all endpoints
@@ -150,12 +165,12 @@ public static RouteHandlerBuilder WithTags(this RouteHandlerBuilder builder, par
150165
/// <param name="contentType">The request content type that the endpoint accepts.</param>
151166
/// <param name="additionalContentTypes">The list of additional request content types that the endpoint accepts.</param>
152167
/// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
153-
public static RouteHandlerBuilder Accepts<TRequest>(this RouteHandlerBuilder builder,
154-
string contentType, params string[] additionalContentTypes) where TRequest : notnull
168+
public static RouteHandlerBuilder Accepts<TRequest>(
169+
this RouteHandlerBuilder builder,
170+
string contentType,
171+
params string[] additionalContentTypes) where TRequest : notnull
155172
{
156-
Accepts(builder, typeof(TRequest), contentType, additionalContentTypes);
157-
158-
return builder;
173+
return Accepts(builder, typeof(TRequest), contentType, additionalContentTypes);
159174
}
160175

161176
/// <summary>
@@ -168,12 +183,13 @@ public static RouteHandlerBuilder Accepts<TRequest>(this RouteHandlerBuilder bui
168183
/// <param name="contentType">The request content type that the endpoint accepts.</param>
169184
/// <param name="additionalContentTypes">The list of additional request content types that the endpoint accepts.</param>
170185
/// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
171-
public static RouteHandlerBuilder Accepts<TRequest>(this RouteHandlerBuilder builder,
172-
bool isOptional, string contentType, params string[] additionalContentTypes) where TRequest : notnull
186+
public static RouteHandlerBuilder Accepts<TRequest>(
187+
this RouteHandlerBuilder builder,
188+
bool isOptional,
189+
string contentType,
190+
params string[] additionalContentTypes) where TRequest : notnull
173191
{
174-
Accepts(builder, typeof(TRequest), isOptional, contentType, additionalContentTypes);
175-
176-
return builder;
192+
return Accepts(builder, typeof(TRequest), isOptional, contentType, additionalContentTypes);
177193
}
178194

179195
/// <summary>
@@ -185,11 +201,13 @@ public static RouteHandlerBuilder Accepts<TRequest>(this RouteHandlerBuilder bui
185201
/// <param name="contentType">The request content type that the endpoint accepts.</param>
186202
/// <param name="additionalContentTypes">The list of additional request content types that the endpoint accepts.</param>
187203
/// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
188-
public static RouteHandlerBuilder Accepts(this RouteHandlerBuilder builder,
189-
Type requestType, string contentType, params string[] additionalContentTypes)
204+
public static RouteHandlerBuilder Accepts(
205+
this RouteHandlerBuilder builder,
206+
Type requestType,
207+
string contentType,
208+
params string[] additionalContentTypes)
190209
{
191-
builder.WithMetadata(new AcceptsMetadata(requestType, false, GetAllContentTypes(contentType, additionalContentTypes)));
192-
return builder;
210+
return Accepts(builder, requestType, isOptional: false, contentType, additionalContentTypes);
193211
}
194212

195213
/// <summary>
@@ -202,38 +220,36 @@ public static RouteHandlerBuilder Accepts(this RouteHandlerBuilder builder,
202220
/// <param name="contentType">The request content type that the endpoint accepts.</param>
203221
/// <param name="additionalContentTypes">The list of additional request content types that the endpoint accepts.</param>
204222
/// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
205-
public static RouteHandlerBuilder Accepts(this RouteHandlerBuilder builder,
206-
Type requestType, bool isOptional, string contentType, params string[] additionalContentTypes)
223+
public static RouteHandlerBuilder Accepts(
224+
this RouteHandlerBuilder builder,
225+
Type requestType,
226+
bool isOptional,
227+
string contentType,
228+
params string[] additionalContentTypes)
207229
{
208-
builder.WithMetadata(new AcceptsMetadata(requestType, isOptional, GetAllContentTypes(contentType, additionalContentTypes)));
209-
return builder;
230+
var contentTypes = GetAllContentTypes(contentType, additionalContentTypes);
231+
return builder.WithMetadata(new AcceptsMetadata(requestType, isOptional, contentTypes));
210232
}
211233

212234
/// <summary>
213235
/// Adds <see cref="IEndpointDescriptionMetadata"/> to <see cref="EndpointBuilder.Metadata"/> for all endpoints
214236
/// produced by <paramref name="builder"/>.
215237
/// </summary>
216-
/// <param name="builder">The <see cref="RouteHandlerBuilder"/>.</param>
238+
/// <param name="builder">The <see cref="IEndpointConventionBuilder"/>.</param>
217239
/// <param name="description">A string representing a detailed description of the endpoint.</param>
218240
/// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
219-
public static RouteHandlerBuilder WithDescription(this RouteHandlerBuilder builder, string description)
220-
{
221-
builder.WithMetadata(new EndpointDescriptionAttribute(description));
222-
return builder;
223-
}
241+
public static TBuilder WithDescription<TBuilder>(this TBuilder builder, string description) where TBuilder : IEndpointConventionBuilder
242+
=> builder.WithMetadata(new EndpointDescriptionAttribute(description));
224243

225244
/// <summary>
226245
/// Adds <see cref="IEndpointSummaryMetadata"/> to <see cref="EndpointBuilder.Metadata"/> for all endpoints
227246
/// produced by <paramref name="builder"/>.
228247
/// </summary>
229-
/// <param name="builder">The <see cref="RouteHandlerBuilder"/>.</param>
248+
/// <param name="builder">The <see cref="IEndpointConventionBuilder"/>.</param>
230249
/// <param name="summary">A string representing a brief description of the endpoint.</param>
231250
/// <returns>A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.</returns>
232-
public static RouteHandlerBuilder WithSummary(this RouteHandlerBuilder builder, string summary)
233-
{
234-
builder.WithMetadata(new EndpointSummaryAttribute(summary));
235-
return builder;
236-
}
251+
public static TBuilder WithSummary<TBuilder>(this TBuilder builder, string summary) where TBuilder : IEndpointConventionBuilder
252+
=> builder.WithMetadata(new EndpointSummaryAttribute(summary));
237253

238254
private static string[] GetAllContentTypes(string contentType, string[] additionalContentTypes)
239255
{

src/Http/Routing/src/PublicAPI.Unshipped.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ static Microsoft.AspNetCore.Builder.EndpointRouteBuilderExtensions.MapPatch(this
1111
override Microsoft.AspNetCore.Routing.RouteValuesAddress.ToString() -> string?
1212
*REMOVED*~Microsoft.AspNetCore.Routing.DefaultInlineConstraintResolver.DefaultInlineConstraintResolver(Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.Routing.RouteOptions!>! routeOptions, System.IServiceProvider! serviceProvider) -> void
1313
Microsoft.AspNetCore.Routing.DefaultInlineConstraintResolver.DefaultInlineConstraintResolver(Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.Routing.RouteOptions!>! routeOptions, System.IServiceProvider! serviceProvider) -> void
14+
static Microsoft.AspNetCore.Http.OpenApiRouteHandlerBuilderExtensions.ExcludeFromDescription<TBuilder>(this TBuilder builder) -> TBuilder
15+
static Microsoft.AspNetCore.Http.OpenApiRouteHandlerBuilderExtensions.WithDescription<TBuilder>(this TBuilder builder, string! description) -> TBuilder
16+
static Microsoft.AspNetCore.Http.OpenApiRouteHandlerBuilderExtensions.WithSummary<TBuilder>(this TBuilder builder, string! summary) -> TBuilder
17+
static Microsoft.AspNetCore.Http.OpenApiRouteHandlerBuilderExtensions.WithTags<TBuilder>(this TBuilder builder, params string![]! tags) -> TBuilder
1418
static Microsoft.AspNetCore.Http.RouteHandlerFilterExtensions.AddFilter(this Microsoft.AspNetCore.Builder.RouteHandlerBuilder! builder, Microsoft.AspNetCore.Http.IRouteHandlerFilter! filter) -> Microsoft.AspNetCore.Builder.RouteHandlerBuilder!
1519
static Microsoft.AspNetCore.Http.RouteHandlerFilterExtensions.AddFilter(this Microsoft.AspNetCore.Builder.RouteHandlerBuilder! builder, System.Func<Microsoft.AspNetCore.Http.RouteHandlerContext!, Microsoft.AspNetCore.Http.RouteHandlerFilterDelegate!, Microsoft.AspNetCore.Http.RouteHandlerFilterDelegate!>! filterFactory) -> Microsoft.AspNetCore.Builder.RouteHandlerBuilder!
1620
static Microsoft.AspNetCore.Http.RouteHandlerFilterExtensions.AddFilter(this Microsoft.AspNetCore.Builder.RouteHandlerBuilder! builder, System.Func<Microsoft.AspNetCore.Http.RouteHandlerInvocationContext!, Microsoft.AspNetCore.Http.RouteHandlerFilterDelegate!, System.Threading.Tasks.ValueTask<object?>>! routeHandlerFilter) -> Microsoft.AspNetCore.Builder.RouteHandlerBuilder!
1721
static Microsoft.AspNetCore.Http.RouteHandlerFilterExtensions.AddFilter<TFilterType>(this Microsoft.AspNetCore.Builder.RouteHandlerBuilder! builder) -> Microsoft.AspNetCore.Builder.RouteHandlerBuilder!
18-
static Microsoft.AspNetCore.Http.OpenApiRouteHandlerBuilderExtensions.WithDescription(this Microsoft.AspNetCore.Builder.RouteHandlerBuilder! builder, string! description) -> Microsoft.AspNetCore.Builder.RouteHandlerBuilder!
19-
static Microsoft.AspNetCore.Http.OpenApiRouteHandlerBuilderExtensions.WithSummary(this Microsoft.AspNetCore.Builder.RouteHandlerBuilder! builder, string! summary) -> Microsoft.AspNetCore.Builder.RouteHandlerBuilder!
2022
static Microsoft.AspNetCore.Routing.LinkGeneratorEndpointNameAddressExtensions.GetPathByName(this Microsoft.AspNetCore.Routing.LinkGenerator! generator, Microsoft.AspNetCore.Http.HttpContext! httpContext, string! endpointName, Microsoft.AspNetCore.Routing.RouteValueDictionary? values = null, Microsoft.AspNetCore.Http.PathString? pathBase = null, Microsoft.AspNetCore.Http.FragmentString fragment = default(Microsoft.AspNetCore.Http.FragmentString), Microsoft.AspNetCore.Routing.LinkOptions? options = null) -> string?
2123
static Microsoft.AspNetCore.Routing.LinkGeneratorEndpointNameAddressExtensions.GetPathByName(this Microsoft.AspNetCore.Routing.LinkGenerator! generator, string! endpointName, Microsoft.AspNetCore.Routing.RouteValueDictionary? values = null, Microsoft.AspNetCore.Http.PathString pathBase = default(Microsoft.AspNetCore.Http.PathString), Microsoft.AspNetCore.Http.FragmentString fragment = default(Microsoft.AspNetCore.Http.FragmentString), Microsoft.AspNetCore.Routing.LinkOptions? options = null) -> string?
2224
static Microsoft.AspNetCore.Routing.LinkGeneratorEndpointNameAddressExtensions.GetUriByName(this Microsoft.AspNetCore.Routing.LinkGenerator! generator, Microsoft.AspNetCore.Http.HttpContext! httpContext, string! endpointName, Microsoft.AspNetCore.Routing.RouteValueDictionary? values = null, string? scheme = null, Microsoft.AspNetCore.Http.HostString? host = null, Microsoft.AspNetCore.Http.PathString? pathBase = null, Microsoft.AspNetCore.Http.FragmentString fragment = default(Microsoft.AspNetCore.Http.FragmentString), Microsoft.AspNetCore.Routing.LinkOptions? options = null) -> string?

0 commit comments

Comments
 (0)