如何在繁忙的 ASP.NET MVC 中定义全局变量

How to define a global variable in a busy ASP.NET MVC

在我的站点中,我调用了第三方 API。为避免达到其速率限制,我需要定义一个全局变量来对请求进行排队。 (I'm using RateLimiter 还有更好的解决方案吗?)

namespace MySite.App_Start
{
    public static class Global
    {
        public static int MaxCount { get; set; } = 30;
        public static TimeSpan Interval { get; set; } = TimeSpan.FromSeconds(1);

        private static TimeLimiter rateLimiter;
        public static TimeLimiter RateLimiter
        {
            get
            {
                if (rateLimiter == null)
                    rateLimiter = TimeLimiter.GetFromMaxCountByInterval(MaxCount, Interval);

                return rateLimiter;
            }
        }
    }
}

那我就用RateLimiter属性。但是我读过很多书说拥有全局变量不是一个好主意。考虑到我的网站每秒有很多请求,我的代码可以安全使用吗?谢谢。

您的代码不是线程安全的。 试试这个:

public class Singleton
{      
  protected Singleton() { }
  private sealed class SingletonCreator
  {
    private static readonly Singleton instance = new Singleton();
    public static Singleton Instance { get { return instance; } }
  }
  public static Singleton Instance
  {
    get { return SingletonCreator.Instance; }
  }
}

或者使用您最喜欢的 IoC 容器创建 SingleInstance 对象

或许,您可以使用 lock 语句使其成为线程安全的。

public static class Global
{
    public static int MaxCount { get; set; } = 30;
    public static TimeSpan Interval { get; set; } = TimeSpan.FromSeconds(1);

    private static object _lockObject = new object();
    private static TimeLimiter rateLimiter;
    public static TimeLimiter RateLimiter
    {
        get
        {
            lock (_lockObject)
            {
                if (rateLimiter == null)
                    rateLimiter = TimeLimiter.GetFromMaxCountByInterval(MaxCount, Interval);
                return rateLimiter;
            }

        }
    }
}

您的代码不是 100% 安全的,因为它可能会在开始时创建多个 TimeLimiter 实例,并且根据周围的代码,这可能是一个问题。我猜这不会是一个大问题,但最好先正确编写代码。

这是 IoC 容器可以很好地处理的事情,但如果您不想使用它,可以使用 Lazy:

private static TimeLimiter rateLimiter = new Lazy(() =>
    TimeLimiter.GetFromMaxCountByInterval(MaxCount, Interval));
public static TimeLimiter RateLimiter => rateLimiter.Value;