@@ -60,6 +60,7 @@ public sealed class MinimalApiGenerator : IIncrementalGenerator
6060 private const string DescriptionAttributeNamedParameter = "Description" ;
6161 private const string ResponseTypeAttributeNamedParameter = "ResponseType" ;
6262 private const string RequestTypeAttributeNamedParameter = "RequestType" ;
63+ private const string IsOptionalAttributeNamedParameter = "IsOptional" ;
6364
6465 private const string RequireAuthorizationAttributeName = "RequireAuthorizationAttribute" ;
6566 private const string RequireAuthorizationAttributeFullyQualifiedName = $ "{ AttributesNamespace } .{ RequireAuthorizationAttributeName } ";
@@ -284,6 +285,11 @@ internal sealed class {{AcceptsAttributeName}} : global::System.Attribute
284285 /// </summary>
285286 public global::System.Type RequestType { get; init; } = default!;
286287
288+ /// <summary>
289+ /// Gets a value indicating whether the request body is optional.
290+ /// </summary>
291+ public bool IsOptional { get; init; }
292+
287293 /// <summary>
288294 /// Gets the primary content type accepted by the endpoint.
289295 /// </summary>
@@ -318,6 +324,11 @@ internal sealed class {{AcceptsAttributeName}}<TRequest> : global::System.Attrib
318324 /// </summary>
319325 public global::System.Type RequestType => typeof(TRequest);
320326
327+ /// <summary>
328+ /// Gets a value indicating whether the request body is optional.
329+ /// </summary>
330+ public bool IsOptional { get; init; }
331+
321332 /// <summary>
322333 /// Gets the primary content type accepted by the endpoint.
323334 /// </summary>
@@ -915,6 +926,7 @@ private static void TryAddAcceptsMetadata(
915926 string ? requestType = null ;
916927 string contentType ;
917928 EquatableImmutableArray < string > ? additionalContentTypes ;
929+ var isOptional = GetNamedBoolValue ( attribute , IsOptionalAttributeNamedParameter ) ;
918930
919931 if ( attributeClass . IsGenericType && attributeClass . TypeArguments . Length == 1 )
920932 {
@@ -942,7 +954,7 @@ private static void TryAddAcceptsMetadata(
942954 }
943955
944956 var acceptsList = accepts ??= new List < AcceptsMetadata > ( ) ;
945- acceptsList . Add ( new AcceptsMetadata ( requestType , contentType , additionalContentTypes ) ) ;
957+ acceptsList . Add ( new AcceptsMetadata ( requestType , contentType , additionalContentTypes , isOptional ) ) ;
946958 }
947959
948960 private static void TryAddProducesMetadata (
@@ -1001,6 +1013,17 @@ private static void TryAddProducesMetadata(
10011013 return null ;
10021014 }
10031015
1016+ private static bool GetNamedBoolValue ( AttributeData attribute , string namedParameter , bool defaultValue = false )
1017+ {
1018+ foreach ( var namedArg in attribute . NamedArguments )
1019+ {
1020+ if ( namedArg . Key == namedParameter && namedArg . Value . Value is bool boolValue )
1021+ return boolValue ;
1022+ }
1023+
1024+ return defaultValue ;
1025+ }
1026+
10041027 private static EquatableImmutableArray < string > MergeUnion ( EquatableImmutableArray < string > ? existing , IEnumerable < string > values )
10051028 {
10061029 var list = new List < string > ( ) ;
@@ -1510,6 +1533,10 @@ private static void GenerateMapRequestHandler(StringBuilder source, RequestHandl
15101533 source . Append ( accepts . RequestType ) ;
15111534 source . Append ( '>' ) ;
15121535 source . Append ( '(' ) ;
1536+ if ( accepts . IsOptional )
1537+ {
1538+ source . Append ( "isOptional: true, " ) ;
1539+ }
15131540 source . Append ( StringLiteral ( accepts . ContentType ) ) ;
15141541 AppendAdditionalContentTypes ( source , accepts . AdditionalContentTypes ) ;
15151542 source . Append ( ')' ) ;
@@ -1660,7 +1687,8 @@ private static StringBuilder GetUseEndpointHandlersStringBuilder(ImmutableArray<
16601687 var additionalCost = accepts . AdditionalContentTypes is { Count : > 0 }
16611688 ? accepts . AdditionalContentTypes . Value . Sum ( ct => 6 + ct . Length )
16621689 : 0 ;
1663- cost += 32 + accepts . RequestType . Length + accepts . ContentType . Length + additionalCost ;
1690+ var optionalCost = accepts . IsOptional ? 20 : 0 ;
1691+ cost += 32 + optionalCost + accepts . RequestType . Length + accepts . ContentType . Length + additionalCost ;
16641692 }
16651693 }
16661694
@@ -1902,7 +1930,11 @@ private readonly record struct RequestHandlerMetadata(
19021930 bool ExcludeFromDescription
19031931 ) ;
19041932
1905- private readonly record struct AcceptsMetadata ( string RequestType , string ContentType , EquatableImmutableArray < string > ? AdditionalContentTypes ) ;
1933+ private readonly record struct AcceptsMetadata (
1934+ string RequestType ,
1935+ string ContentType ,
1936+ EquatableImmutableArray < string > ? AdditionalContentTypes ,
1937+ bool IsOptional ) ;
19061938
19071939 private readonly record struct ProducesMetadata (
19081940 string ResponseType ,
0 commit comments