【问题标题】:Web Api 2 API not recognizing Multiple Attributes for Routing (Versioning)Web Api 2 API 无法识别多个路由属性(版本控制)
【发布时间】:2014-12-06 02:40:52
【问题描述】:

我正在尝试从RoutingConstaints Sample 实现Attribute RoutingVersionedRoute,但是当我在控制器上同时使用它们时,版本化属性不再起作用。

我需要对属性进行哪些修改才能使其与属性路由搭配得很好?

对于代码示例,请下载示例项目(或仅查看上面链接中的几个文件),然后按如下方式修改路由:

// When I use the RoutePrefix, VersionedRoute no longer works (Sending "Api-Version" through http header doesn't route correctly
// If I remove the RoutePrefix I can use VersionedRoute again
// What do I need to change in its code to be able to use both?

[VersionedRoute("api/Customers", 1)] // This route would be used as http://url/api/customers with a header of "api-version: 1"
[RoutePrefix("api/v1/Customers")] // This route would be used purely through url versioning of http://url/api/v1/Customers
public class CustomersV1Controller : ApiController {

    /* Other stuff removed */

    [VersionedRoute("api/Customer", 1)] // I'd rather not have to use this here at all and just use a single one on the class, but having both nor just one on either works right now.
    [Route("")]
    public IHttpActionResult Get()
    {
        return Json(_customers);
    }
}

VersionedRoute Code

VersionConstraint Code

编辑:如果您需要更多信息或发布想法或尝试的东西,请告诉我:)

Edit2:这是我在 Troy Hunt 的博客中尝试做的一个示例:http://www.troyhunt.com/2014/02/your-api-versioning-is-wrong-which-is.html

Edit3:这是我希望编码尽可能接近的内容,因为它会减少很多开销和魔术字符串。

[VersionedRoute("api/Customers", 1)] // This route would be used as http://url/api/customers with a header of "api-version: 1"
[RoutePrefix("api/v1/Customers")] // This route would be used purely through url versioning of http://url/api/v1/Customers
public class CustomersV1Controller : ApiController {

    /* Other stuff removed */
    [Route("")]
    public IHttpActionResult Get()
    {
        // Removed
        return Ok(customers);
    }


    [Route("{id:int}")]
    public IHttpActionResult GetById(int id)
    {
        // Removed
        return Ok(customer);
    }
}

[VersionedRoute("api/Customers", 2)] // This route would be used as http://url/api/customers with a header of "api-version: 2"
[RoutePrefix("api/v2/Customers")] // This route would be used purely through url versioning of http://url/api/v2/Customers
public class CustomersV2Controller : ApiController {

    /* Other stuff removed */
    [Route("")]
    public IHttpActionResult Get()
    {
        // Removed
        return Ok(customersThatAreDifferentThanV1);
    }


    [Route("{id:int}")]
    public IHttpActionResult GetById(int id)
    {
        // Removed
        return Ok(customerThatIsDifferent);
    }
}

编辑:最后一次碰撞,试图只在控制器属性级别而不是每个操作上为每个路由写入一次路由版本信息。

【问题讨论】:

  • 你到底想做什么?
  • @DavidG 我正在尝试同时使用VersionedRoute("Customer", 1),这将允许我使用http 标头来提供版本#,以及使用RoutePrefix("v1/Customer/") 通过url 进行版本控制。基本上我想同时支持标头和 url 版本控制。但是,当我应用 RoutePrefix 时,VersionedRoute 属性停止工作。
  • 设置项目时您的配置是什么样的?
  • @entropic 完整项目链接在 OP 中:aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/…
  • @John 这篇文章提到了Route,但没有提到RoutePrefix,但是在 cmets 中有人提出了一个潜在的解决方案。

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


【解决方案1】:

RouteVersionedRoute 属性可以很好地协同工作,但您的 RoutePrefix 属性也适用于您的 VersionedRoute(尝试访问 /api/v1/Customers/api/Customer - 您将获得设置 api-version 标头时的响应)

以下代码将针对您的示例中的两个 URL 产生所需的行为,返回正确的响应,但显然这并不能解决您想要一个 VersionedRoute 和一个 RoutePrefix 在类顶部的问题.为此将需要另一种方法。但是,您可以为不同的 api 版本设置单独的控制器。

[RoutePrefix("api")]
public class CustomersV1Controller : ApiController
{
    /* Other stuff removed */

    [VersionedRoute("Customers", 1)]
    [Route("v1/Customers")]
    public IHttpActionResult Get()
    {
        return Json(_customers);
    }
}

一个改进是创建您自己的属性而不是Route,这样您就不需要每次都为版本添加前缀:

public class CustomVersionedRoute : Attribute, IHttpRouteInfoProvider
{
    private readonly string _template;

    public CustomVersionedRoute(string route, int version)
    {
        _template = string.Format("v{0}/{1}", version, route);
    }

    public string Name { get { return _template; } }
    public string Template { get { return _template ; } }
    public int Order { get; set; }
}

[RoutePrefix("api")]
public class CustomersV2Controller : ApiController
{
    /* Other stuff removed */

    [VersionedRoute("Customers", 2)]
    [CustomVersionedRoute("Customers", 2)]
    public IHttpActionResult Get()
    {
        return Json(_customers);
    }
}

【讨论】:

  • 正确,这会导致大量重复代码 :(。我宁愿只在类的顶部设置一个 VersionedRoute 和一个 RoutePrefix,然后不必担心下面的其余路由。我有一个解决方法,使用常量来保存路由前缀的东西,但你可以想象它并不像它应该(可能)那样干净。
  • 我的问题是如何获得一个VersionedRoute 和一个RoutePrefix,这样我就不必担心将版本信息放在每个方法之上。我知道我可以在每个上面手动指定它,但我想保持它的清洁和干燥。
  • 我不确定。如果有帮助,一个改进是通过制作自己的属性来整理Route 属性(请参阅编辑),您可以将常量和版本传递给该属性,但每个方法仍然需要两个属性,每条路线一个。
  • 是的,我也尝试过自定义属性,我希望我可以有多个基类,这样我就可以从 versionedroute 和常规属性路由继承并将两个版本都传递到模板中。当我尝试时,我最终从RouteFactoryAttribute 继承,但它又是魔术字符串的两倍 :(。感谢您尝试帮助我解决这个问题,如果您有更多想法,请告诉我 :)
  • 您可以通过使用它们的接口来拥有这些“多个基类”,但我不确定这会对您有所帮助。我也有这个想法,并创建了一个具有两个接口的属性 - CustomVersionedRouteAttribute : Attribute, IDirectRouteFactory, IHttpRouteInfoProvider。我遇到的问题是 MVC 框架似乎只识别每个属性一个路由。在不更改属性内的任何代码的情况下,如果我注释掉任何一个接口,它在另一种情况下都可以正常工作,但是当两个接口都在那里时,它只支持一个路由。如果有帮助,我可以发布我尝试过的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-11
  • 2013-12-12
  • 2015-07-19
  • 1970-01-01
  • 2017-03-24
  • 2020-10-03
  • 1970-01-01
相关资源
最近更新 更多