Skip to content

Commit 9345004

Browse files
authored
Allow AcceptsAttribute request type named argument (#17)
1 parent d14bffe commit 9345004

File tree

4 files changed

+18
-14
lines changed

4 files changed

+18
-14
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,12 @@ public sealed class CreateTodo
240240
}
241241
```
242242

243+
When you can't use the generic form (for example, the request type is only known at runtime), set the `RequestType` named argument instead:
244+
245+
```csharp
246+
[Accepts("application/xml", RequestType = typeof(CreateTodoRequest))]
247+
```
248+
243249
The generator translates these attributes into `.Accepts`, `.Produces`, `.ProducesProblem`, and `.ProducesValidationProblem`
244250
calls on the endpoint builder.
245251

src/GeneratedEndpoints/MinimalApiGenerator.cs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public sealed class MinimalApiGenerator : IIncrementalGenerator
5959
private const string SummaryAttributeNamedParameter = "Summary";
6060
private const string DescriptionAttributeNamedParameter = "Description";
6161
private const string ResponseTypeAttributeNamedParameter = "ResponseType";
62+
private const string RequestTypeAttributeNamedParameter = "RequestType";
6263

6364
private const string RequireAuthorizationAttributeName = "RequireAuthorizationAttribute";
6465
private const string RequireAuthorizationAttributeFullyQualifiedName = $"{AttributesNamespace}.{RequireAuthorizationAttributeName}";
@@ -281,7 +282,7 @@ internal sealed class {{AcceptsAttributeName}} : global::System.Attribute
281282
/// <summary>
282283
/// Gets the request type accepted by the endpoint.
283284
/// </summary>
284-
public global::System.Type RequestType { get; }
285+
public global::System.Type RequestType { get; init; } = default!;
285286
286287
/// <summary>
287288
/// Gets the primary content type accepted by the endpoint.
@@ -296,12 +297,10 @@ internal sealed class {{AcceptsAttributeName}} : global::System.Attribute
296297
/// <summary>
297298
/// Initializes a new instance of the <see cref="{{AcceptsAttributeName}}"/> class.
298299
/// </summary>
299-
/// <param name="requestType">The CLR type of the request body.</param>
300300
/// <param name="contentType">The primary content type accepted by the endpoint.</param>
301301
/// <param name="additionalContentTypes">Additional content types accepted by the endpoint.</param>
302-
public {{AcceptsAttributeName}}(global::System.Type requestType, string contentType = "application/json", params string[] additionalContentTypes)
302+
public {{AcceptsAttributeName}}(string contentType = "application/json", params string[] additionalContentTypes)
303303
{
304-
RequestType = requestType ?? throw new global::System.ArgumentNullException(nameof(requestType));
305304
ContentType = string.IsNullOrWhiteSpace(contentType) ? "application/json" : contentType;
306305
AdditionalContentTypes = additionalContentTypes ?? [];
307306
}
@@ -927,15 +926,14 @@ private static void TryAddAcceptsMetadata(
927926
? GetStringArrayValues(attribute.ConstructorArguments[1])
928927
: null;
929928
}
930-
else if (attribute.ConstructorArguments.Length >= 1 &&
931-
attribute.ConstructorArguments[0].Value is ITypeSymbol requestTypeSymbol)
929+
else if (GetNamedTypeSymbol(attribute, RequestTypeAttributeNamedParameter) is { } requestTypeSymbol)
932930
{
933931
requestType = requestTypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
934-
contentType = attribute.ConstructorArguments.Length > 1
935-
? NormalizeRequiredContentType(attribute.ConstructorArguments[1].Value as string, "application/json")
932+
contentType = attribute.ConstructorArguments.Length > 0
933+
? NormalizeRequiredContentType(attribute.ConstructorArguments[0].Value as string, "application/json")
936934
: "application/json";
937-
additionalContentTypes = attribute.ConstructorArguments.Length > 2
938-
? GetStringArrayValues(attribute.ConstructorArguments[2])
935+
additionalContentTypes = attribute.ConstructorArguments.Length > 1
936+
? GetStringArrayValues(attribute.ConstructorArguments[1])
939937
: null;
940938
}
941939
else

tests/GeneratedEndpoints.Tests.Lab/GetUserEndpoint.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ internal static class GetUserEndpoint
1414
{
1515
[Tags("Featured")]
1616
[AllowAnonymous]
17-
[Accepts(typeof(GetUserRequest), "application/json", "application/xml")]
17+
[Accepts("application/json", "application/xml", RequestType = typeof(GetUserRequest))]
1818
[Accepts<GetUserMetadata>("application/json", "application/xml")]
1919
[ProducesResponse( StatusCodes.Status200OK, "application/json", ResponseType = typeof(UserProfile))]
2020
[ProducesResponse<UserProfile>(StatusCodes.Status202Accepted, "application/json")]

tests/GeneratedEndpoints.Tests/GeneratedEndpointsTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public async Task MapAllAttributesAndHttpMethods(bool withNamespace)
115115
[Tags("Shared", "ClassLevel")]
116116
[RequireAuthorization("PolicyA", "PolicyB")]
117117
[DisableAntiforgery]
118-
[Accepts(typeof(ClassLevelRequest), "application/xml", "text/xml")]
118+
[Accepts("application/xml", "text/xml", RequestType = typeof(ClassLevelRequest))]
119119
[ProducesResponse(201, "application/json", "text/json", ResponseType = typeof(ClassLevelResponse))]
120120
[ProducesProblem(503, "application/problem+json")]
121121
[ProducesValidationProblem(409, "application/problem+json", "text/plain")]
@@ -138,8 +138,8 @@ public static void Configure<TBuilder>(TBuilder builder, IServiceProvider servic
138138
[AllowAnonymous]
139139
[Tags("MethodLevel")]
140140
[RequireAuthorization("MethodPolicy")]
141-
[Accepts<GetRequest>("application/custom", "text/custom")]
142-
[Microsoft.AspNetCore.Generated.Attributes.ProducesResponse<GetResponse>(200, "application/json", "text/json")]
141+
[Accepts<GetRequest>("application/custom", "text/custom")]
142+
[Microsoft.AspNetCore.Generated.Attributes.ProducesResponse<GetResponse>(200, "application/json", "text/json")]
143143
[ProducesProblem(400, "application/problem+json", "text/plain")]
144144
[ProducesValidationProblem(422, "application/problem+json", "text/plain")]
145145
[ExcludeFromDescription]

0 commit comments

Comments
 (0)