【问题标题】:ASP.NET API versioningASP.NET API 版本控制
【发布时间】:2017-02-21 15:34:06
【问题描述】:

我是 ASP.NET 的新手,但我希望为即将开始的新 API 实现一些版本控制。

我什至不确定我正在寻找的东西是否可能,但我正在使用一个非常干净的版本方法,使用头变量。

理想情况下,我希望能够在代码结构中拥有一个版本文件夹,以及其中包含不同 API 版本的不同文件夹。 每个版本文件夹将包含核心 API 代码的完整副本,因此我知道永远不会有任何冲突等。我知道这会使代码膨胀,但值得保持它非常干净,并且只会超过 2-3有效的 API 版本。

我在 Internet 上找到了许多标头示例,但它们都要求类位于不同的命名空间中,如果我正在做代码的完整副本,那么每次都必须重命名所有类是不切实际的被复制了。

我正在尝试做的事情可能吗?或者在处理多个类时是否有更清洁的解决方案?

【问题讨论】:

  • 你在使用 ASP.Net Web API 2 吗?
  • 嗨,是的,我正在使用 web api 2

标签: asp.net asp.net-web-api2 versioning


【解决方案1】:

有四种基本方法可以对 RESTful 方式进行版本控制 -

  1. URI 路径 这种方法采用以下形式:

    http://api/v2/Tasks/{TaskId}

  2. URI 参数 这种方法采用以下形式:

    http://api/Tasks/{TaskId}?v=2

  3. 内容协商这是在 HTTP 标头中完成的。

    内容类型:application/vnd.taskManagerApp.v2.param.json

  4. Request Header 这也是在 HTTP 标头中完成的。

    x-taskManagerApp-version: 2

我个人喜欢第一种方法。你可以阅读Mike Wasson's ASP.NET Web API: Using Namespaces to Version Web APIs

许多人修改了 Mike Wasson 的原始来源。我喜欢ASP.NET Web API 2 book by Jamie Kurtz, Brian Wortman 中使用的那个。

由于它有太多的移动部件,我创建了a sample project at GitHub

config.Routes.MapHttpRoute(
   name: "DefaultApi",
   routeTemplate: "api/{version}/{controller}",
   defaults: new { version = "v2" }
);

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

然后,你添加ApiVersionConstraint

public class ApiVersionConstraint : IHttpRouteConstraint
{
    public ApiVersionConstraint(string allowedVersion)
    {
        AllowedVersion = allowedVersion.ToLowerInvariant();
    }

    public string AllowedVersion { get; private set; }

    public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName,
        IDictionary<string, object> values, HttpRouteDirection routeDirection)
    {
        object value;
        if (values.TryGetValue(parameterName, out value) && value != null)
        {
            return AllowedVersion.Equals(value.ToString().ToLowerInvariant());
        }
        return false;
    }
}

用法

您只需将 RoutePrefix 放在控制器上,就完成了。

[RoutePrefix("api/{apiVersion:apiVersionConstraint(v1)}/values")]
public class ValuesController : ApiController
{
    // GET api/v1/values
    [Route("")]
    public IEnumerable<string> Get()
    {
        return new string[] { "v1-value1", "v1-value2" };
    }

    // GET api/v1/values/5
    [Route("{id}")]
    public string Get(int id)
    {
        return "v1-value-" + id;
    }
}

【讨论】:

  • 我查看了您的 githum 示例,它非常适合 URL 版本控制,但我需要能够通过自定义标头传递版本。我尝试了不同的方法,可以从标头中获取版本,但是从 URL 中删除版本后,此行 [var controllerName = GetControllerName(routeData);] 会导致错误。
  • 抱歉,我没有通过 HTTP 标头进行版本控制的源代码。
  • 我认为我看错了,我不知道我想要做的事情是使用标题或 url 版本控制。将您的示例与两个 ValuesController.cs 文件一起使用,它们都有不同的命名空间和路由前缀,所以每次我创建一个新版本并复制现有的控制器 id 都必须更改所有命名空间和前缀......谢谢你的帮助 Win,我走了回到绘图板并重新开始。
【解决方案2】:

答案有点晚,但对于仍想将版本控制应用于 ASP.NET Web API 堆栈的任何人来说,ASP.NET API Versioning 已成为实现它的一种非常常见的方式。 Basic Sample 将引导您完成所有必要的步骤以开始使用。

API 版本控制支持开箱即用的查询字符串、标头、媒体类型和 URL 段。如果您支持多个方法,您可以将方法组合在一起,您甚至可以创建自己的方法来提取 API 版本。版本控制的默认方法是查询字符串。尽管它很受欢迎并且来自@Win 的建议,但我建议按 URL 段进行版本控制。它是 RESTful 最少的方法,因为它违反了 统一接口 约束,并且存在大量有问题的边缘情况。

首先添加ASP.NET Web API Versioning NuGet 包。您希望如何版本化以及如何组织代码是非常主观的,但这里是一个非常简单的设置:

namespace Example
{
   public class WebApiConfig
   {
       public static Configure(HttpConfiguration config)
       {
           // TODO: this is the minimum, but there are many options that can be configured
           config.AddApiVersioning();

           // TODO: remaining configuration
       }
   }

   // this is one of many possible ways you might organize controllers
   namespace Controllers
   {
       namespace V1
       {
           [ApiVersion("1.0")]
           [RoutePrefix("values")]
           public class ValuesController : ApiController
           {
               // GET /values?api-version=1.0
               [Route]
               public IHttpActionResult Get(ApiVersion version) =>
                   Ok(new []{$"v{version}-Value1", $"v{version}-Value2"});

               // GET /values/{id}?api-version=1.0
               [Route("{id}")]
               public IHttpActionResult Get(int id, ApiVersion version) =>
                   Ok($"v{version}-{id}")
           }
       }

       namespace V2
       {
           [ApiVersion("2.0")]
           [RoutePrefix("values")]
           public class ValuesController : ApiController
           {
               // GET /values?api-version=2.0
               [Route]
               public IHttpActionResult Get(ApiVersion version) =>
                   Ok(new []{$"v{version}-Value1", $"v{version}-Value2"});

               // GET /values/{id}?api-version=2.0
               [Route("{id}")]
               public IHttpActionResult Get(int id, ApiVersion version) =>
                   Ok($"v{version}-{id}")
           }
       }
   }
}

【讨论】:

    猜你喜欢
    • 2018-02-21
    • 1970-01-01
    • 2017-03-18
    • 1970-01-01
    • 1970-01-01
    • 2021-06-19
    • 1970-01-01
    • 2019-08-20
    • 1970-01-01
    相关资源
    最近更新 更多