Skip to content

Commit 95ea8bd

Browse files
committed
Fixed the issue. Will be adding the tests as a separate commit.
1 parent febd7e8 commit 95ea8bd

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

src/Mvc/Mvc.ApiExplorer/src/ApiResponseTypeProvider.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -363,9 +363,10 @@ internal static void CalculateResponseFormatForType(ApiResponseType apiResponse,
363363
}
364364

365365
// If the method is declared to return IActionResult, IResult or a derived class, that information
366-
// isn't valuable to the formatter.
367-
if (typeof(IActionResult).IsAssignableFrom(unwrappedType) ||
368-
typeof(IResult).IsAssignableFrom(unwrappedType))
366+
// isn't valuable to the formatter, unless it implements IEndpointMetadataProvider interface.
367+
bool isIResultOrIActionResult = typeof(IActionResult).IsAssignableFrom(unwrappedType) ||
368+
typeof(IResult).IsAssignableFrom(unwrappedType);
369+
if (isIResultOrIActionResult && !typeof(IEndpointMetadataProvider).IsAssignableFrom(unwrappedType))
369370
{
370371
return null;
371372
}

src/Mvc/Mvc.Core/src/ApplicationModels/DefaultApplicationModelProvider.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33

44
using System.Linq;
55
using System.Reflection;
6+
using Microsoft.AspNetCore.Builder;
67
using Microsoft.AspNetCore.Http;
8+
using Microsoft.AspNetCore.Http.Metadata;
79
using Microsoft.AspNetCore.Mvc.ActionConstraints;
810
using Microsoft.AspNetCore.Mvc.ApiExplorer;
911
using Microsoft.AspNetCore.Mvc.Filters;
@@ -19,6 +21,8 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels;
1921
internal class DefaultApplicationModelProvider : IApplicationModelProvider
2022
#pragma warning restore CA1852 // Seal internal types
2123
{
24+
private static readonly MethodInfo PopulateMetadataForEndpointMethod = typeof(EndpointMetadataPopulator).GetMethod(nameof(PopulateMetadataForEndpoint), BindingFlags.NonPublic | BindingFlags.Static)!;
25+
2226
private readonly MvcOptions _mvcOptions;
2327
private readonly IModelMetadataProvider _modelMetadataProvider;
2428
private readonly Func<ActionContext, bool> _supportsAllRequests;
@@ -349,9 +353,33 @@ internal PropertyModel CreatePropertyModel(PropertyInfo propertyInfo)
349353
applicableAttributes.AddRange(routeAttributes);
350354
AddRange(actionModel.Selectors, CreateSelectors(applicableAttributes));
351355

356+
// There may be additional metadata for the action that is associated with the return type.
357+
AddEndpointMetadata(actionModel, methodInfo);
358+
352359
return actionModel;
353360
}
354361

362+
private static void AddEndpointMetadata(ActionModel actionModel, MethodInfo methodInfo)
363+
{
364+
// Get metadata from return type
365+
var returnType = methodInfo.ReturnType;
366+
if (CoercedAwaitableInfo.IsTypeAwaitable(returnType, out var coercedAwaitableInfo))
367+
{
368+
returnType = coercedAwaitableInfo.AwaitableInfo.ResultType;
369+
}
370+
371+
if (returnType is not null && typeof(IEndpointMetadataProvider).IsAssignableFrom(returnType))
372+
{
373+
// Return type implements IEndpointMetadataProvider
374+
var builder = new InertEndpointBuilder();
375+
var invokeArgs = new object[2];
376+
invokeArgs[0] = methodInfo;
377+
invokeArgs[1] = builder;
378+
PopulateMetadataForEndpointMethod.MakeGenericMethod(returnType).Invoke(null, invokeArgs);
379+
actionModel.Properties.Add(typeof(ProducesResponseTypeAttribute), builder.Metadata.ToArray());
380+
}
381+
}
382+
355383
private string CanonicalizeActionName(string actionName)
356384
{
357385
const string Suffix = "Async";
@@ -675,4 +703,18 @@ private static void AddRange<T>(IList<T> list, IEnumerable<T> items)
675703
list.Add(item);
676704
}
677705
}
706+
707+
private static void PopulateMetadataForEndpoint<T>(MethodInfo method, EndpointBuilder builder)
708+
where T : IEndpointMetadataProvider
709+
{
710+
T.PopulateMetadata(method, builder);
711+
}
712+
713+
private sealed class InertEndpointBuilder : EndpointBuilder
714+
{
715+
public override Endpoint Build()
716+
{
717+
return new Endpoint(RequestDelegate, new EndpointMetadataCollection(Metadata), DisplayName);
718+
}
719+
}
678720
}

0 commit comments

Comments
 (0)