2

最近我们了解了 IIS 的 AppDomain Recycling 以及它如何影响将静态变量设置为其主要值(null、0 等)。

我们使用一些在静态构造函数中初始化的静态变量(对于第一次初始化,配置值,如“小数位数”、“管理员电子邮件”等......从数据库中检索),然后只读取它们的值网站执行。

解决这个问题的最佳方法是什么?一些可能的想法:

  • 在每次检索时检查变量是否为 null/0(不喜欢它,因为可能会影响性能 + 将此检查添加到每个变量所花费的时间 + 添加到项目中的代码重载)

  • 以某种方式阻止 AppDomain Recycling(这种重置逻辑不会发生在具有静态变量的 Windows 表单中,它不应该像在两种环境中使用相同的语言一样工作吗?至少在标准方面作为静态变量管理)

  • 使用其他方式来保存这些变量(但我们认为,对于作为所有用户全局参考的信息的一些值,静态变量是性能/编码方面的最佳选择)

  • 订阅在这些 AppDomain Recycling 中触发的事件,以便我们可以重新初始化所有这些变量(如果无法阻止回收,这可能是最好的选择......)

想法?

4

6 回答 6

3

我会采用您不喜欢的方法。

在每次检索时检查变量是否为 null/0(不喜欢它,因为可能会影响性能 + 将此检查添加到每个变量所花费的时间 + 添加到项目中的代码重载)

  • 我认为这比从 web.config 中退出要快。
  • 你得到一个类型化的对象

它不会对性能产生影响,因为您不会在每个检索请求上都访问数据库。只有当您发现当前值设置为其默认值时,您才会转到数据库(或任何来源)。

于 2013-06-21T12:38:15.130 回答
1

检查包装到代码中的空值:

public interface IMyConfig {
  string Var1 { get; }
  string Var2 { get; }
}

public class MyConfig : IMyConfig {
  private string _Var1;
  private string _Var2;

  public string Var1 { get { return _Var1; } }
  public string Var2 { get { return _Var2; } }

  private static object s_SyncRoot = new object();
  private static IMyConfig s_Instance;

  private MyConfig() {
    // load _Var1, _Var2 variables from db here
  }

  public static IMyConfig Instance {
    get {
      if (s_Instance != null) {
        return s_Instance;
      }
      lock (s_SyncRoot) {
        s_Instance = new MyConfig();
      }
      return s_Instance;
    }
  }
}
于 2013-06-21T13:01:32.513 回答
0

有什么理由不能将这些值存储在web.config文件中并用于ConfiguationManager.AppSettings检索它们?

ConfigurationManager.AppSettings["MySetting"] ?? "defaultvalue";

鉴于您的编辑,为什么不在第一次检索所需的值时缓存它们?

var val = HttpContext.Cache["MySetting"];
if (val == null)
{
    val = // Database retrieval logic
    HttpContext.Cache["MySetting"] = val;
}
于 2013-06-21T12:29:18.143 回答
0

听起来您需要一个直写(或后写)缓存,可以使用静态变量来完成。

每当用户更改值时,将其写回数据库。然后,每当 AppPool 被回收时(这是正常现象,不应避免),静态构造函数可以从数据库中读取当前值。

您必须考虑的一件事:如果您曾经扩展到网络场,当共享变量发生更改时,您需要有某种“触发器”,以便场中的其他服务器可以知道检索新值从服务器。

对您问题的其他部分的评论:

(不喜欢 [在每次检索时检查变量是否为空/0],因为可能会影响性能 + 将此检查添加到每个变量所花费的时间 + 添加到项目中的代码重载

如果您使用直写式缓存,则不需要它,但在任何一种情况下,检查静态变量是否为 0 或 null 所花费的时间应该可以忽略不计。

[AppDomain 回收] 不会发生在具有静态变量的 Windows 窗体中,它不应该像在两种环境中使用相同的语言一样工作吗?

不,WebForms 和 WinForms 是完全不同的平台,具有不同的操作模型。网站应该能够响应许多(多达数百万)并发用户。WinForms 是为单用户访问而构建的。

于 2013-06-21T12:50:05.110 回答
0

已经解决了此类问题,遵循与此类似的模式。这使我能够处理数据可能发生变化的情况。我在引导程序中设置了我的 ISiteSettingRepository。在 1 个应用程序中,我从 XML 文件中获取配置,但在其他应用程序中,我在需要时从数据库中获取配置。

public class ApplicationSettings      
{
   public ApplicationSettings()
   {

   }
   public ApplicationSettings(ApplicationSettings settings)
   {
       ApplicationName = settings.ApplicationName;
       EncryptionAlgorithm = settings.EncryptionAlgorithm;
       EncryptionKey = settings.EncryptionKey;
       HashAlgorithm = settings.HashAlgorithm;
       HashKey = settings.HashKey;
       Duration = settings.Duration;
       BaseUrl = settings.BaseUrl;
       Id = settings.Id;

   }

 public string ApplicationName { get; set; }
 public string EncryptionAlgorithm { get; set; }
 public string EncryptionKey { get; set; }
 public string HashAlgorithm { get; set; }
 public string HashKey { get; set; }
 public int Duration { get; set; }
 public string BaseUrl { get; set; }
 public Guid Id { get; set; }

}

然后是一个“服务”接口

 public interface IApplicaitonSettingsService
{
   ApplicationSettings Get();
}

 public class ApplicationSettingsService : IApplicaitonSettingsService 
{
    private readonly ISiteSettingRepository _repository;

    public ApplicationSettingsService(ISiteSettingRepository repository)
    {
        _repository = repository;
    }

    public ApplicationSettings Get()
    {
        SiteSetting setting = _repository.GetAll();
        return setting;
    }
}
于 2013-06-21T13:00:36.957 回答
0

我会采取一种完全不同的方法,一种不涉及任何东西的方法static

首先创建一个类来强类型化您所追求的配置设置:

public class MyConfig
{
    int DecimalPlaces { get; set; }
    string AdministratorEmail { get; set; }
    //...
}

然后通过创建一些存储库来抽象出持久层:

public interface IMyConfigRepository
{
    MyConfig Load();
    void Save(MyConfig settings);
}

然后可以读取和写入这些设置的类可以静态声明它们依赖于此存储库的实现:

public class SomeClass
{
    private readonly IMyConfigRepository _repo;

    public MyClass(IMyConfigRepository repo)
    {
        _repo = repo;
    }

    public void DoSomethingThatNeedsTheConfigSettings()
    {
        var settings = _repo.Load();
        //...
    }
}

现在以您想要的方式实现存储库接口(今天您想要数据库中的设置,明天可能会序列化为 .xml 文件,明年使用云服务)和您需要的配置接口。

你已经准备好了:你现在需要的只是一种将接口绑定到它的实现的方法。这是一个 Ninject 示例(用 -NinjectModule派生类的Load方法覆盖编写):

Bind<IMyConfigRepository>().To<MyConfigSqlRepository>();

然后,您可以在/如果需要时将实现换成一个MyConfigCloudRepository或一个实现。MyConfigXmlRepository

作为一个 asp.net 应用程序,只需确保在Global.asax文件中连接这些依赖项(在应用程序启动时),然后任何具有IMyConfigRepository构造函数参数的类都将被注入 aMyConfigSqlRepository这将为MyConfigImplementation您提供可以加载的对象和请随意保存。

如果您不使用 IoC 容器,那么您只需new启动MyConfigSqlRepository应用程序,然后手动将实例注入到需要它的类型的构造函数中。

这种方法唯一的问题是,如果您还没有一个对 DependencyInjection 友好的应用程序结构,这可能意味着要进行广泛的重构——解耦对象并消除new依赖关系,使单元测试更容易专注于单一方面,并​​且更容易模拟依赖关系......以及其他优点。

于 2013-06-21T17:59:13.123 回答