Skip to content
代码片段 群组 项目
未验证 提交 69f1ace4 编辑于 作者: Safia Abdalla's avatar Safia Abdalla 提交者: GitHub
浏览文件

Expose ParameterInfo for Minimal Actions API Explorer (#36439) (#36547)


* Expose ParameterInfo for Minimal Actions API Explorer

Populate the ParameterDescriptor for Minimal Actions parameters with
a type that implements IParameterInfoParameterDescriptor so that any
custom attributes on the parameter can be inspected.
Relates to #36438.

* Remove file-scoped namespace

Addresses review feedback.

Co-authored-by: default avatarMartin Costello <martin@martincostello.com>
上级 5cc47862
No related branches found
No related tags found
无相关合并请求
// Licensed to the .NET Foundation under one or more agreements. // Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Security.Claims; using System.Security.Claims;
using System.Threading;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Http.Metadata;
using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Abstractions;
...@@ -162,6 +160,7 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer ...@@ -162,6 +160,7 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
var nullabilityContext = new NullabilityInfoContext(); var nullabilityContext = new NullabilityInfoContext();
var nullability = nullabilityContext.Create(parameter); var nullability = nullabilityContext.Create(parameter);
var isOptional = parameter.HasDefaultValue || nullability.ReadState != NullabilityState.NotNull || allowEmpty; var isOptional = parameter.HasDefaultValue || nullability.ReadState != NullabilityState.NotNull || allowEmpty;
var parameterDescriptor = CreateParameterDescriptor(parameter);
return new ApiParameterDescription return new ApiParameterDescription
{ {
...@@ -170,10 +169,19 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer ...@@ -170,10 +169,19 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
Source = source, Source = source,
DefaultValue = parameter.DefaultValue, DefaultValue = parameter.DefaultValue,
Type = parameter.ParameterType, Type = parameter.ParameterType,
IsRequired = !isOptional IsRequired = !isOptional,
ParameterDescriptor = parameterDescriptor
}; };
} }
private static ParameterDescriptor CreateParameterDescriptor(ParameterInfo parameter)
=> new EndpointParameterDescriptor
{
Name = parameter.Name ?? string.Empty,
ParameterInfo = parameter,
ParameterType = parameter.ParameterType,
};
// TODO: Share more of this logic with RequestDelegateFactory.CreateArgument(...) using RequestDelegateFactoryUtilities // TODO: Share more of this logic with RequestDelegateFactory.CreateArgument(...) using RequestDelegateFactoryUtilities
// which is shared source. // which is shared source.
private (BindingSource, string, bool) GetBindingSourceAndName(ParameterInfo parameter, RoutePattern pattern) private (BindingSource, string, bool) GetBindingSourceAndName(ParameterInfo parameter, RoutePattern pattern)
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Reflection;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure;
namespace Microsoft.AspNetCore.Mvc.ApiExplorer
{
internal sealed class EndpointParameterDescriptor : ParameterDescriptor, IParameterInfoParameterDescriptor
{
public ParameterInfo ParameterInfo { get; set; } = default!;
}
}
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.ComponentModel;
using System.Reflection; using System.Reflection;
using System.Security.Claims; using System.Security.Claims;
using System.Threading; using System.Threading;
...@@ -11,6 +12,7 @@ using System.Threading.Tasks; ...@@ -11,6 +12,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.Patterns; using Microsoft.AspNetCore.Routing.Patterns;
...@@ -268,6 +270,20 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer ...@@ -268,6 +270,20 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
AssertPathParameter(GetApiDescription(([FromRoute] int foo) => { })); AssertPathParameter(GetApiDescription(([FromRoute] int foo) => { }));
} }
[Fact]
public void AddsFromRouteParameterAsPathWithCustomType()
{
static void AssertPathParameter(ApiDescription apiDescription)
{
var param = Assert.Single(apiDescription.ParameterDescriptions);
Assert.Equal(typeof(TryParseStringRecord), param.Type);
Assert.Equal(typeof(TryParseStringRecord), param.ModelMetadata.ModelType);
Assert.Equal(BindingSource.Path, param.Source);
}
AssertPathParameter(GetApiDescription((TryParseStringRecord foo) => { }, "/{foo}"));
}
[Fact] [Fact]
public void AddsFromQueryParameterAsQuery() public void AddsFromQueryParameterAsQuery()
{ {
...@@ -410,6 +426,32 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer ...@@ -410,6 +426,32 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
Assert.True(barParam.IsRequired); Assert.True(barParam.IsRequired);
} }
[Fact]
public void TestParameterAttributesCanBeInspected()
{
var apiDescription = GetApiDescription(([Description("The name.")] string name) => { });
Assert.Equal(1, apiDescription.ParameterDescriptions.Count);
var nameParam = apiDescription.ParameterDescriptions[0];
Assert.Equal(typeof(string), nameParam.Type);
Assert.Equal(typeof(string), nameParam.ModelMetadata.ModelType);
Assert.Equal(BindingSource.Query, nameParam.Source);
Assert.False(nameParam.IsRequired);
Assert.NotNull(nameParam.ParameterDescriptor);
Assert.Equal("name", nameParam.ParameterDescriptor.Name);
Assert.Equal(typeof(string), nameParam.ParameterDescriptor.ParameterType);
var descriptor = Assert.IsAssignableFrom<IParameterInfoParameterDescriptor>(nameParam.ParameterDescriptor);
Assert.NotNull(descriptor.ParameterInfo);
var description = Assert.Single(descriptor.ParameterInfo.GetCustomAttributes<DescriptionAttribute>());
Assert.NotNull(description);
Assert.Equal("The name.", description.Description);
}
[Fact] [Fact]
public void RespectsProducesProblemExtensionMethod() public void RespectsProducesProblemExtensionMethod()
{ {
......
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册