@@ -332,10 +332,9 @@ private static void AddSupportedResponseTypes(
332332 var defaultErrorType = errorMetadata ? . Type ?? typeof ( void ) ;
333333 var contentTypes = new MediaTypeCollection ( ) ;
334334
335- // If the return type is an IResult or an awaitable IResult, then we should treat it as a void return type
336- // since we can't infer anything without additional metadata.
337- if ( typeof ( IResult ) . IsAssignableFrom ( responseType ) ||
338- producesResponseMetadata . Any ( metadata => typeof ( IResult ) . IsAssignableFrom ( metadata . Type ) ) )
335+ // If the return type is an IResult or wrapped in a Task or ValueTask, then we should treat it as a void return type
336+ // since we can't infer anything without additional metadata or requiring unreferenced code.
337+ if ( IsTaskOrValueTask ( responseType ) || typeof ( IResult ) . IsAssignableFrom ( responseType ) )
339338 {
340339 responseType = typeof ( void ) ;
341340 }
@@ -427,6 +426,23 @@ static bool TypesAreCompatible(Type? apiResponseType, Type? metadataType)
427426 return apiResponseType == metadataType ||
428427 metadataType ? . IsAssignableFrom ( apiResponseType ) == true ;
429428 }
429+
430+ static bool IsTaskOrValueTask ( Type returnType )
431+ {
432+ // If this method did not need to be trim-safe, we would use CoercedAwaitableInfo.IsTypeAwaitable, but we cannot.
433+ if ( returnType . IsAssignableFrom ( typeof ( Task ) ) || returnType . IsAssignableFrom ( typeof ( ValueTask ) ) )
434+ {
435+ return true ;
436+ }
437+
438+ if ( returnType . FullName is null )
439+ {
440+ return false ;
441+ }
442+
443+ return returnType . FullName . StartsWith ( "System.Threading.Tasks.Task`1[" , StringComparison . Ordinal ) ||
444+ returnType . FullName . StartsWith ( "System.Threading.Tasks.ValueTask`1[" , StringComparison . Ordinal ) ;
445+ }
430446 }
431447
432448 private static ApiResponseType CreateDefaultApiResponseType ( Type responseType )
0 commit comments