支持检查REST方法的最佳实践

时间:2016-02-12 12:30:08

标签: c# api rest versions

首先,我知道这个问题: Best Practices and How to support different versions of REST APIs in C# wrapper on client-side 但我认为我的问题有点不同。

我们有一个可以通过REST Api进行远程控制的软件。 用户每年将获得两次更新。 每次更新都会为他们提供一些新功能。

现在我们还有一个REST客户端,它是并行开发的,但具有不同的发布日期。除了新版本之外,客户端还必须支持旧版本。

现在的问题是,我想知道如何在我的REST客户端代码中构建版本检查。这是一个奢侈设计问题......

 public void apiStuff(Data input)
 {
     if (api.Versions < "2.5.3")
         throw new Exception("Not supported, please update")

     doApiStuffWith(input);
 }

或者我应该将检查并抛出部分放在私有方法中。

 public void apiStuff(Data input)
 {
     checkForVersionSupport("2.5.3");

     doApiStuffWith(input);
 }

我认为第一种方法作为第二种方法更具可读性,但它也是冗余代码。

或者有没有完全不同的想法?

2 个答案:

答案 0 :(得分:4)

<强>更新 调整“每种方法都需要不同的api版本”解决方案。

抽象接口的客户端逻辑:

public interface IApiClient
{
    void Foo();
    int GetCurrentVersion();
}

为方法API版本创建一个属性:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public sealed class ApiVersionRangeAttribute : Attribute
{
    public int MinVersion { get; private set; }
    public int MaxVersion { get; private set; }
    public ApiVersionRangeAttribute(int minVersion, int maxVersion)
    {
        MinVersion = minVersion;
        MaxVersion = maxVersion;
    }

    public void Validate(int version)
    {
        if (version < MinVersion || version > MaxVersion)
        {
            throw new Exception("Upgrade");
        }
    }
}

创建一个将该属性纳入帐户的工厂:

//nuget: Install-Package Castle.Core
using System;
using Castle.DynamicProxy;
public class ApiClientFactory
{
    public class ApiClient : IApiClient
    {
        [ApiVersionRange(10, 20)]
        public void Foo()
        {
            Console.Write("Foo");
        }
        public int GetCurrentVersion()
        {
            // call to the server here instead :)
            return 50;
        }
    }

    public IApiClient CreateClient()
    {
        var generator = new ProxyGenerator();
        var apiClient = generator.CreateInterfaceProxyWithTarget<IApiClient>(
          new ApiClient(), new VersionInterceptor());
        return apiClient;
    }
}

public class VersionInterceptor : StandardInterceptor
{
    protected override void PreProceed(IInvocation invocation)
    {
        var attributes = invocation.MethodInvocationTarget.GetCustomAttributes(
          typeof(ApiVersionRangeAttribute), false);
        if (attributes != null && attributes.Length == 1)
        {
            var apiRange = (ApiVersionRangeAttribute)attributes[0];
            var proxy = (IApiClient)invocation.Proxy;
            apiRange.Validate(proxy.GetCurrentVersion());
        }
        base.PreProceed(invocation);
    }
}

样本用法:

 var apiClient = new ApiClientFactory().CreateClient();
 // fail - 50 is not in range 10-20
 apiClient.Foo();

答案 1 :(得分:1)

  

恕我直言,考虑Version代替int,并使用AttributeUsage作为裁员。

     

以上答案描述了属性的用法

public void CheckVersion(Version currentVersion)
{
   //Get your version from assembly 
    Version applicationVersion = new Version(AssemblyInfo.AssemblyFileVersion);

   //
  if (currentVersion.CompareTo(applicationVersion) == 1)
      throw your Exception("Not supported");
}