【问题标题】:ApiExplorer does not recognize route attributes with custom typeApiExplorer 无法识别自定义类型的路由属性
【发布时间】:2017-05-01 22:38:02
【问题描述】:

我有一个项目,我想在其中使用自定义类型的路由属性。 我将自定义类型作为查询参数的以下代码工作正常,帮助页面显示自定义类型。

// GET api/values?5,6
[Route("api/values")]
public string Get(IntegerListParameter ids)
{
    return "value";
}

WebApi.HelpPage 提供以下文档 Help:Page

如果我更改代码以使用路由属性,结果是我得到一个空的帮助页面。

// GET api/values/5,6
[Route("api/values/{ids}")]
public string Get(IntegerListParameter ids)
{
    return "value";
}

当我检查在 HelpController.cs 中观察到的代码时,ApiExplorer.ApiDescriptions 返回一个空的 ApiDescriptions 集合

public ActionResult Index()
{
    ViewBag.DocumentationProvider = Configuration.Services.GetDocumentationProvider();
    Collection<ApiDescription> apiDescriptions = Configuration.Services.GetApiExplorer().ApiDescriptions;

    return View(apiDescriptions);
}

有什么方法可以让 ApiExplorer 将我的自定义类 IntegerListParameter 识别为属性路由?

【问题讨论】:

    标签: c# asp.net-web-api2 asp.net-web-api-helppages


    【解决方案1】:

    你需要:

    1. 为您的 IntegerListParameter 类型添加 HttpParameterBinding
    2. 将绑定标记为IValueProviderParameterBinding并实现ValueProviderFactories
    3. IntegerListParameter 添加一个转换器并为typeof(string) 参数覆盖CanConvertFrom 方法

    在这些操作之后,必须在 ApiExplorer 中识别具有自定义类型 IntegerListParameter 的路由。

    请参阅我的示例以了解类型ObjectId

    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            //...
            config.ParameterBindingRules.Insert(0, GetCustomParameterBinding);
            TypeDescriptor.AddAttributes(typeof(ObjectId), new TypeConverterAttribute(typeof(ObjectIdConverter)));
            //...
        }
    
        public static HttpParameterBinding GetCustomParameterBinding(HttpParameterDescriptor descriptor)
        {
            if (descriptor.ParameterType == typeof(ObjectId))
            {
                return new ObjectIdParameterBinding(descriptor);
            }
            // any other types, let the default parameter binding handle
            return null;
        }
    }
    
    public class ObjectIdParameterBinding : HttpParameterBinding, IValueProviderParameterBinding
    {
        public ObjectIdParameterBinding(HttpParameterDescriptor desc)
            : base(desc)
        {
        }
    
        public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
        {
            try
            {
                SetValue(actionContext, new ObjectId(actionContext.ControllerContext.RouteData.Values[Descriptor.ParameterName] as string));
                return Task.CompletedTask;
            }
            catch (FormatException)
            {
                throw new BadRequestException("Invalid id format");
            }
        }
    
        public IEnumerable<ValueProviderFactory> ValueProviderFactories { get; } = new[] { new QueryStringValueProviderFactory() };
    }
    
    public class ObjectIdConverter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType == typeof(string))
                return true;
            return base.CanConvertFrom(context, sourceType);
        }
    }
    

    【讨论】:

    • 这在尝试找出自定义模型绑定器(以逗号分隔的整数数组)未显示在 Api Explorer 或 Swagger 中的原因时很有帮助,感谢您将这些放在一起!
    • 我正在努力了解如何在原始问题的上下文中实现此答案。我的情况与@crabCRUSHERclamCOLLECTOR 类似,我有一个逗号分隔的整数数组要绑定。我有一个可用的 ModelBinder,但 Swagger 无法识别它。这与 ModelBinder 有什么关系?
    【解决方案2】:

    不完全确定 IntegerListParameter 列表是什么数据结构,但如果您需要在查询中发送以逗号分隔的整数列表(例如 ~api/products?ids=1,2,3,4),您可以使用过滤器属性。可以在这里找到一个示例实现:Convert custom action filter for Web API use?

    【讨论】:

    • 我已经实现了逗号分隔的整数列表。它既可以用作查询参数,也可以用作属性路由。
    • 我的问题是帮助页面没有显示列表是属性路由的操作。问题是当列表作为属性路由实现时,ApiExplorer.ApiDescriptions 无法识别操作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-27
    • 2019-05-20
    • 1970-01-01
    • 1970-01-01
    • 2020-11-11
    • 2019-07-10
    • 2016-09-04
    相关资源
    最近更新 更多