Asp.net 使用IHttpControllerSelector进行属性计算-Api版本控制

Asp.net 使用IHttpControllerSelector进行属性计算-Api版本控制,asp.net,asp.net-web-api,attributerouting,api-versioning,Asp.net,Asp.net Web Api,Attributerouting,Api Versioning,我试图在asp.net webapi上使用CustomHttpControlSelector和AttributeRouting实现api版本控制 我试图做的是通过名称空间来区分控制器的版本 如果向/api/v2/foo/bar发出请求 我想让它匹配 namespace Web.Controllers.Api.v2 { [RoutePrefix("foo")] public class LongerThanFooController : ApiController {

我试图在asp.net webapi上使用CustomHttpControlSelector和AttributeRouting实现api版本控制

我试图做的是通过名称空间来区分控制器的版本

如果向/api/v2/foo/bar发出请求 我想让它匹配

namespace Web.Controllers.Api.v2
{
    [RoutePrefix("foo")]
    public class LongerThanFooController : ApiController
    {
        [HttpGet]
        [Route("bar")]
        public string BarFunction()
        {
            return "foobar";
        }
    }
}
但正如我看到的,当我在RoutePrefix(/api/v2/foo)属性上不使用完整url时,路由不会生效,当我调用

 request.GetRouteData().GetSubRoutes();
在我的CustomHttpControlSelector上。我不想在每个控制器上重复/api/v2

如果我决定删除attributeRouting并使用手动路由,如

 config.Routes.MapHttpRoute(
         name: "DefaultVersionedApi",
         routeTemplate: "api/v{version}/{controller}/{id}",
         defaults: new { id = RouteParameter.Optional }
 );

 config.Routes.MapHttpRoute(
          name: "DefaultApi",
          routeTemplate: "api/{controller}/{id}",
          defaults: new { id = RouteParameter.Optional, version = Config.LatestVersion }
  );
我失去了命名控制器和函数的所有灵活性

有没有办法摆脱这种困境


注意:对于CustomHttpControlSelector,我在

上修改了代码,现在我意识到这是一个老问题,但它可以使用软件包来回答。在最新的3.0版本中,您可以通过以下更新配置来实现场景:

var constraintResolver = new DefaultInlineConstraintResolver()
{
  ConstraintMap =
  {
    ["apiVersion"] = typeof( ApiVersionRouteConstraint )
  }
};

configuration.AddApiVersioning(
  options =>
  {
    options.Conventions.Add( new VersionByNamespaceConvention() );
    options.AssumeDefaultVersionWhenUnspecified = true;
    options.ApiVersionSelector = new CurrentImplementationApiVersionSelector( options );
  } );

configuration.MapHttpAttributeRoutes( constraintResolver );
您还应该删除基于约定的路由。如果您使用的是属性路由,则这些是不必要的

控制器的设置仅更改为:

namespace Web.Controllers.Api.v2
{
  [RoutePrefix("api")]
  public class LongerThanFooController : ApiController
  {
    [HttpGet]
    [Route("foo/bar")]
    [Route("v{version:apiVersion}/foo/bar")]
    public string BarFunction()
    {
      return "foobar";
    }
  }
}

您需要两个路由定义的原因是,在路由模板中间,<>强>不能/>强有默认值。默认值只能在末尾使用。这也意味着您需要不允许指定API版本,并指出确定应选择哪个API版本的方法是使用当前实现(例如,最新版本)。我个人不喜欢这种方法,因为我认为事情对客户来说应该是可预测的,但这会达到你想要的结果