2016-02-12 80 views
0

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

我们有一块软件可以通过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); 
} 

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

还是有人有完全不同的想法?

+0

所以你检查你的服务器的API版本的使用情况如何?这对我来说没有意义。此外,您所做的选择实际上并没有太大的差别,显然将功能提取到另一个功能更好。虽然我会使用某种钩子而不是在每个api调用中调用它。 – Glubus

+0

MS使用V2。您也可以尝试代码合同。这就是说,你的问题是基于意见的。 –

回答

4

UPDATE 调整为“每种方法都需要不同的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

所以我应该为每一个版本构建一个新的客户端,并在实例化时检查版本? 这对我的情况来说是很大的开销。有很多不同的版本。 – Alu

+0

此解决方案将避免使用旧客户端版本和新服务器版本的可能性。这不符合要求。 –

+0

是的,当然,但我想用户得到一个消息,他必须更新。 因此,如果他“看到”他不能使用的功能,他就会被迫更新他的服务器。 – Alu

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