ASP.NET API 版本控制

ASP.NET API versioning

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

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

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

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

我想做的事情可行吗?或者在处理多个 类 时是否有更清晰的解决方案?

RESTful 版本有四种基本方法 -

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

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

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

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

  3. 内容协商这是在 HTTP header.

    中完成的

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

  4. 请求Header HTTP中也是这样header.

    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;
    }
}

有点迟到的答案,但对于仍想将版本控制应用于 ASP.NET Web API 堆栈的任何人,ASP.NET API Versioning has become a very common way to achieve it. The Basic Sample 将带您完成所有必要的步骤以开始.

API 版本控制支持查询字符串、header、媒体类型和 URL 段 out-of-the-box。如果支持多个方法,则可以将方法组合在一起,甚至可以创建自己的方法来提取 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}")
           }
       }
   }
}