C# ApiExplorer无法识别自定义类型的路由属性

C# ApiExplorer无法识别自定义类型的路由属性,c#,asp.net-web-api2,asp.net-web-api-helppages,C#,Asp.net Web Api2,Asp.net Web Api Helppages,我有一个项目,我想使用自定义类型的路由属性。 下面的代码将自定义类型作为查询参数,运行良好,帮助页面显示自定义类型 // GET api/values?5,6 [Route("api/values")] public string Get(IntegerListParameter ids) { return "value"; } WebApi.HelpPage提供了以下文档 如果我将代码更改为使用route属性,结果将得到一个空的帮助页面 // GET api/values/5,6

我有一个项目,我想使用自定义类型的路由属性。 下面的代码将自定义类型作为查询参数,运行良好,帮助页面显示自定义类型

// GET api/values?5,6
[Route("api/values")]
public string Get(IntegerListParameter ids)
{
    return "value";
}
WebApi.HelpPage提供了以下文档

如果我将代码更改为使用route属性,结果将得到一个空的帮助页面

// GET api/values/5,6
[Route("api/values/{ids}")]
public string Get(IntegerListParameter ids)
{
    return "value";
}
当我检查HelpController.cs中的代码时,我发现ApiExplorer.apisdescriptions返回一个空的apisdescriptions集合

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

    return View(apiDescriptions);
}
public ActionResult Index()
{
ViewBag.DocumentationProvider=配置.Services.GetDocumentationProvider();
集合apiDescriptions=Configuration.Services.GetApiExplorer().apiDescriptions;
返回视图(API描述);
}

有没有办法让ApiExplorer将我的自定义类IntegerListParameter识别为属性路由?

不确切地确定
IntegerListParameter
列表是什么数据结构,但是如果需要在查询中发送逗号分隔的整数列表(例如
~api/products?ids=1,2,3,4
),可以使用筛选器属性。可在此处找到此示例实现:

您需要:

  • 为您的
    IntegerListParameter
    类型添加HttpParameterBinding
  • 将绑定标记为
    IValueProviderParameterBinding
    并实现
    ValueProviderFactorys
  • 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);
        }
    }
    
    公共静态类WebApiConfig
    {
    公共静态无效寄存器(HttpConfiguration配置)
    {
    //...
    config.ParameterBindingRules.Insert(0,GetCustomParameterBinding);
    AddAttributes(typeof(ObjectId),新的TypeConverterAttribute(typeof(objectdConverter));
    //...
    }
    公共静态HttpParameterBinding GetCustomParameterBinding(HttpParameterDescriptor描述符)
    {
    if(descriptor.ParameterType==typeof(ObjectId))
    {
    返回新的ObjectdParameterBinding(描述符);
    }
    //任何其他类型,让默认参数绑定处理
    返回null;
    }
    }
    公共类ObjectdParameterBinding:HttpParameterBinding、IValueProviderParameterBinding
    {
    公共对象参数绑定(HttpParameterDescriptor描述)
    :基础(描述)
    {
    }
    公共覆盖任务ExecuteBindingAsync(ModelMetadataProvider metadataProvider、HttpActionContext actionContext、CancellationToken CancellationToken)
    {
    尝试
    {
    SetValue(actionContext,新ObjectId(actionContext.ControllerContext.RouteData.Values[Descriptor.ParameterName]作为字符串));
    返回Task.CompletedTask;
    }
    捕获(格式化异常)
    {
    抛出新的BadRequestException(“无效的id格式”);
    }
    }
    public IEnumerable ValueProviderFactorys{get;}=new[]{new QueryStringValueProviderFactory()};
    }
    公共类ObjectdConverter:TypeConverter
    {
    公共覆盖布尔CanConvertFrom(ITypeScriptorContext上下文,类型sourceType)
    {
    if(sourceType==typeof(string))
    返回true;
    返回base.CanConvertFrom(上下文,sourceType);
    }
    }
    
    我已经实现了逗号分隔的整数列表。作为查询参数和属性路由,它都可以很好地工作。我的问题是帮助页面没有显示列表是属性路由的操作。问题在于,当列表作为属性路由实现时,ApiExplorer.apisdescriptions无法识别该操作。这在试图找出自定义模型绑定器(逗号分隔的整数数组)为什么没有显示在Api Explorer或Swagger中时很有帮助,感谢您将其组合在一起!