通过不同的请求跟踪 .net 应用程序变量
Keep track of a .net application variable through different requests
在 .Net 应用程序中,当使用 C# 时,我必须进行一次昂贵的调用才能将一些数据发送给第三方 API,并且取决于这个,有时它比我希望的要慢。
事实是,该数据将是准确的,但我可以自己计算出不太精确的数据。所以我在想我如何能够让我们说在过去 5 分钟内跟踪平均请求时间,如果它大于我的阈值更改使用我自己的实现。
该方法的草图如下所示:
public int GetMyData()
{
return isTooSlow() ? _ownImplementation.GetData() : thirdParty.GetData();
}
即使在理想情况下我希望能够将第三方包装在一个接口中,我将实现该接口并在运行时更改它,这将是一个很好的选择。
但主要问题是如何在内存中保留该状态。我只能考虑使用静态 class 并且我已经阅读了有关 ApplicationState 的内容,但不确定其中任何一种是否是最佳方法。
此外,不是针对我的小项目,而是这些解决方案如何扩展?如果我不得不考虑我的应用程序的多个实例 运行 我认为唯一的解决方案是使用外部存储(redis 或类似的?)并在进行检查时查询它。
抱歉,如果问题太笼统,但认为这是一个有趣的问题,但不知道如何最好地解决它
谢谢
我会把多个应用程序实例的问题放在次要位置。并不是说这无关紧要,但是如果您针对接口进行编程,那么在某些时候您可以用缓存的东西替换您的实现。
如果您想要平均请求时间超过五分钟,那么您将需要一个可以弹出过期条目的列表。这是一个刺:
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());
}
}
这可确保当您从列表中读取时,它只会 returns 存储在指定时间间隔内的项目,并且还会删除其余项目。您可以创建一个 ExpiringList<TimeSpan>
,为每个调用添加经过的时间,然后根据需要检查平均值。
存放在哪里?我会把它放在一个 class 中,只有一个实例。这可能是单例或静态 class。我更喜欢使用 returns 单个实例的依赖项注入容器(如 Windsor's singleton lifestyle。)我不喜欢创建单例。我宁愿创建一个 "normal" class 然后管理它以保留单个实例。像 Windsor 这样的 DI 容器让这一切变得简单。
我认为在这样的实现中的一个重要因素是将混乱的切换逻辑分开 - 隐藏在某种工厂中,而不是让 if/then
包含检查平均响应时间的所有逻辑并在一个大的 class.
中调用 API
例如,如果您有一个表示获取数据的调用的接口,例如 IMyDataProvider
,那么您可以定义一个工厂,例如
interface IMyDataProviderFactory
{
IMyDataProvider Create();
}
您的 classes 仅依赖于该工厂接口。实现 IMyDataProviderFactory
的 class 检查您的平均响应时间,并且 returns 调用外部 API 的 IMyDataProvider
的实现或使用您的计算的实现。
这样,该逻辑的复杂性就与 class 依赖于 API 的任何内容分开。
温莎也很适合 abstract factories。其他 DI 容器也使它们变得简单,并且这种功能内置于 ASP.NET 核心中。您不是在询问依赖注入,但我建议您对其进行调查。它使管理这种复杂性并使其易于维护变得更加容易。
回到多个应用程序实例和分布式缓存 - 您可以看到工厂模式实现如何使其更易于管理。假设今天这是一个实例,但明天您想通过分布式缓存共享此数据。您在哪里进行更改?大多数依赖于此 API 的代码根本不需要更改,因为它 "know" 不涉及任何这些实现细节。您将更改存储每个 API 调用时间的代码并更改工厂的实现。
在 .Net 应用程序中,当使用 C# 时,我必须进行一次昂贵的调用才能将一些数据发送给第三方 API,并且取决于这个,有时它比我希望的要慢。
事实是,该数据将是准确的,但我可以自己计算出不太精确的数据。所以我在想我如何能够让我们说在过去 5 分钟内跟踪平均请求时间,如果它大于我的阈值更改使用我自己的实现。
该方法的草图如下所示:
public int GetMyData()
{
return isTooSlow() ? _ownImplementation.GetData() : thirdParty.GetData();
}
即使在理想情况下我希望能够将第三方包装在一个接口中,我将实现该接口并在运行时更改它,这将是一个很好的选择。
但主要问题是如何在内存中保留该状态。我只能考虑使用静态 class 并且我已经阅读了有关 ApplicationState 的内容,但不确定其中任何一种是否是最佳方法。
此外,不是针对我的小项目,而是这些解决方案如何扩展?如果我不得不考虑我的应用程序的多个实例 运行 我认为唯一的解决方案是使用外部存储(redis 或类似的?)并在进行检查时查询它。
抱歉,如果问题太笼统,但认为这是一个有趣的问题,但不知道如何最好地解决它
谢谢
我会把多个应用程序实例的问题放在次要位置。并不是说这无关紧要,但是如果您针对接口进行编程,那么在某些时候您可以用缓存的东西替换您的实现。
如果您想要平均请求时间超过五分钟,那么您将需要一个可以弹出过期条目的列表。这是一个刺:
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());
}
}
这可确保当您从列表中读取时,它只会 returns 存储在指定时间间隔内的项目,并且还会删除其余项目。您可以创建一个 ExpiringList<TimeSpan>
,为每个调用添加经过的时间,然后根据需要检查平均值。
存放在哪里?我会把它放在一个 class 中,只有一个实例。这可能是单例或静态 class。我更喜欢使用 returns 单个实例的依赖项注入容器(如 Windsor's singleton lifestyle。)我不喜欢创建单例。我宁愿创建一个 "normal" class 然后管理它以保留单个实例。像 Windsor 这样的 DI 容器让这一切变得简单。
我认为在这样的实现中的一个重要因素是将混乱的切换逻辑分开 - 隐藏在某种工厂中,而不是让 if/then
包含检查平均响应时间的所有逻辑并在一个大的 class.
例如,如果您有一个表示获取数据的调用的接口,例如 IMyDataProvider
,那么您可以定义一个工厂,例如
interface IMyDataProviderFactory
{
IMyDataProvider Create();
}
您的 classes 仅依赖于该工厂接口。实现 IMyDataProviderFactory
的 class 检查您的平均响应时间,并且 returns 调用外部 API 的 IMyDataProvider
的实现或使用您的计算的实现。
这样,该逻辑的复杂性就与 class 依赖于 API 的任何内容分开。
温莎也很适合 abstract factories。其他 DI 容器也使它们变得简单,并且这种功能内置于 ASP.NET 核心中。您不是在询问依赖注入,但我建议您对其进行调查。它使管理这种复杂性并使其易于维护变得更加容易。
回到多个应用程序实例和分布式缓存 - 您可以看到工厂模式实现如何使其更易于管理。假设今天这是一个实例,但明天您想通过分布式缓存共享此数据。您在哪里进行更改?大多数依赖于此 API 的代码根本不需要更改,因为它 "know" 不涉及任何这些实现细节。您将更改存储每个 API 调用时间的代码并更改工厂的实现。