2017-05-02 71 views
0

在.Net应用程序中使用C#时,我必须进行昂贵的调用才能获取某些数据给第三方API,并且依赖于此API有时候会更慢喜欢。通过不同的请求跟踪.net应用程序变量

事情是这样的,数据将是准确的,但我可以自己计算精度较低。所以我在考虑如何能够让我们跟踪最近5分钟内的平均请求时间,以及如果它大于我使用我自己的实现的阈值更改。

方法的草图会是这样的:

public int GetMyData() 
    { 
     return isTooSlow() ? _ownImplementation.GetData() : thirdParty.GetData(); 
    } 

即使我非常希望能够换一个接口的第三方,该矿将实现并改变它在运行时,它会很高兴有。

但主要问题是如何将这个状态保存在内存中。我只能想到使用静态类,我已经阅读了有关ApplicationState的内容,但不确定这些是否是最好的方法。

此外,不是我的小项目,但如何解决这些解决方案?如果我不得不考虑运行我的应用程序的几个实例,我认为唯一的解决方案是使用外部存储(redis或类似?)并在检查时查询它。

很抱歉,如果这个问题是太一般,但认为这是解决一个有趣的问题,不知道究竟如何最好地接近它

感谢

+1

如果你有自己的实现,那么为什么你需要打电话给第三方?或者在几小时后致电第三方并将数据存储在某处,以便更快地获得数据。 –

+0

数据在第三方“实时”更新,所以我想每次都调用它,除非它在最后几分钟内变得接近无响应。 – mitomed

回答

1

我把多个应用程序实例的问题上后面燃烧器。不是没关系,但是如果你是针对接口进行编程,那么在某些时候你可以用缓存的东西替换你的实现。

如果您希望平均请求时间超过五分钟的持续时间,那么您需要一个弹出过期条目的列表。下面是在一个刺:

internal class TimestampedEntry<T> 
{ 
    internal DateTimeOffset Timestamp { get; private set; } 
    internal T Value { get; private set; } 

    internal TimestampedEntry(T value) 
    { 
     Timestamp = DateTimeOffset.Now; 
     Value = value; 
    } 
} 

public class ExpiringList<T> 
{ 
    private readonly List<TimestampedEntry<T>> _list = new List<TimestampedEntry<T>>(); 
    private readonly TimeSpan _expiration; 

    public ExpiringList(TimeSpan expiration) 
    { 
     _expiration = expiration; 
    } 

    public void Add(T item) 
    { 
     lock (_list) 
     { 
      _list.Add(new TimestampedEntry<T>(item));    
     } 
    } 

    public IReadOnlyCollection<T> Read() 
    { 
     var cutoff = DateTimeOffset.Now - _expiration; 
     TimestampedEntry<T>[] result; 
     lock (_list) 
     { 
      result = _list.Where(item => item.Timestamp > cutoff).ToArray(); 
      _list.Clear(); 
      _list.AddRange(result); 
     } 
     return new ReadOnlyCollection<T>(result.Select(item => item.Value).ToList()); 
    } 
} 

这可确保当您从列表中读它只返回存储在指定的时间间隔内的项目,并删除其余的。您可以创建一个ExpiringList<TimeSpan>,为每个呼叫添加已用时间,然后根据需要检查平均值。

在哪里存放它?我会把它放在一个单独的实例中。这可能是单身或静态类。我更喜欢使用返回单个实例的依赖注入容器(如Windsor's singleton lifestyle)。我不喜欢创建单例。我宁愿创建一个“普通”类,然后管理它以保持单个实例。像温莎这样的DI容器可以很容易地实现。

我认为在这样的实现中一个重要的因素是保持杂乱的切换逻辑分离 - 隐藏在某种工厂中,而不是使用if/then所有逻辑来检查平均响应时间并调用任一API在一个大班上。

举例来说,如果你有代表呼吁得到的数据,像IMyDataProvider的接口,那么你可以这样定义

interface IMyDataProviderFactory 
{ 
    IMyDataProvider Create(); 
} 

你的类只取决于该工厂接口的工厂。执行IMyDataProviderFactory的类将检查您的平均响应时间,并返回调用外部API的IMyDataProvider的实现或使用您的计算的实现。

这样,该逻辑的复杂性就与依赖于API的任何类保持独立。

温莎与那些abstract factories也很好。其他DI容器也使它们变得简单,并且这种功能被内置到ASP.NET Core中。你并没有问及依赖注入,但我建议研究它。它可以更轻松地管理这种复杂性并保持可维护性。


回到多个应用程序实例和分布式缓存 - 您可以看到工厂模式实现如何更容易管理。假设今天这是一个例子,但明天你想通过分布式缓存共享这些数据。你在哪里做这个改变?大多数依赖于此API的代码根本不需要更改,因为它不会“知道”任何这些实现​​细节。您可以更改存储每个API调用时间的代码,并更改工厂的实施。