2013-06-21 77 views
1

最近我們瞭解了有關IIS的AppDomain回收以及它如何影響將它們設置爲主值(空值,0等)的靜態變量。ASP.NET維護靜態變量

我們使用一些在靜態構造函數中進行初始化的靜態變量(第一次初始化,配置值如「小數位數」,「管理員電子郵件」等等)閱讀他們的網站執行價值。

解決此問題的最佳方法是什麼?一些可能的想法:

  • 檢查是否變量是在每個檢索空/ 0(不喜歡它,因爲一個可能影響性能+時間花在此檢查添加到每個變量+超載代碼添加到項目)

  • 不知怎的,防止回收的AppDomain(該復位邏輯並不在Windows窗體與靜態變量發生,應該不是同樣?至少在標準爲靜態變量管理方面的工作爲在兩個環境中使用同一種語言)

  • 使用一些其他方式持有這些v (但我們認爲,作爲所有用戶的信息用作全局參考的一些值,靜態變量是性能/編碼明智的最佳選項)

  • 訂閱在這些AppDomain中觸發的事件回收所以我們可以重新初始化所有這些變量(也許最好的選擇,如果回收不能防止...)

想法?

+1

將它們封裝爲一個非靜態類的公共只可獲得屬性,您將它作爲依賴項傳遞給需要它的任何地方?爲什麼它必須是靜態的? –

+0

「在兩種環境中都是一樣的」 - 不是真的,它們非常不同!在winforms中,每個用戶都有自己的應用程序實例和自己的一組靜態變量。這經常重新啓動(每次用戶結束應用程序時)。在webforms中有一個用於* all *請求的應用程序,因此靜態變量在所有用戶之間共享。除了回收,webapp將永遠活着。 –

回答

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; 
    } 
    } 
} 
+0

最後,我會做這樣的事情。檢查getter和null的情況下調用一個初始化函數,它將正確的值再次設置爲靜態變量......但我一直認爲這是一個設計缺陷:/ – VSP

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; 
} 
+0

是的,這些變量是由我們的CRM應用程序的用戶改變的,所以我們必須從它的數據庫中檢索它們,它們很少被改變,但是你永遠不知道它們什麼時候會這樣做...... – VSP

+0

我明白了。我已經更新了我的答案。 –

+1

@AntP Cache不會比其他靜態屬性更適用於AppPool回收。 –

3

我會用你不喜歡的方法。

檢查是否變量是在每個檢索空/ 0(不喜歡它,因爲一個可能影響性能+時間花在增加這個檢查,每一個變量+超載代碼添加到項目)

  • 我認爲這比從web.config中退出要快。
  • 你得到不是一個類型的對象

它的性能影響,因爲你不會給數據庫中每個檢索請求。只有當您發現當前值設置爲其默認值時,纔會轉到數據庫(或任何來源)。

+0

是的,您可以將所有配置值包裝到一個對象中,您將以單身形式檢索。每個應用程序池回收幾乎沒有問題。 –

0

這聽起來像你需要一個寫通過(或後寫)緩存,這可以用靜態變量來完成。

每當用戶更改該值時,將其寫回數據庫。然後,每當AppPool被回收(這是正常現象並且不應該被避免),靜態構造函數可以從數據庫中讀取當前值。你必須考慮

一兩件事:如果你向外擴展到Web場,你需要有某種形式的「觸發」時的共享變量的變化等農場的其他服務器可以知道從服務器檢索新值。

對你的問題的其他部分評論:

(不喜歡[檢查是否變量爲null/0在每個檢索]由於可能影響性能+時間花在增加這個檢查,以每變量+超載代碼添加到項目

如果使用直寫式高速緩存,你不需要這個,但在這兩種情況下所花費的時間來檢查靜態變量爲0或空的可以忽略不計。

[使用靜態變量的Windows窗體中不會發生[應用程序域回收],它應該不是在兩種環境中都是相同的語言?

不,WebForms和WinForms是使用不同操作模型的完全不同的平臺。網站應該能夠響應許多(高達數百萬)併發用戶。 WinForms是爲單用戶訪問而構建的。

+0

但是開發人員認爲變量沒有依賴於開發人員的檢查邏輯的某種事件而被重置似乎是不可靠的。甚至檢查這些變量,如果你只是給變量設置一些值,並且AppDomain在1秒之後收斂,該怎麼辦?沒有選擇就失去了價值。並且請記住,在這種情況下,值會從其他來源而不是我們的網站更改,因此我們只從數據庫中獲取值(只讀) – VSP

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; 
    } 
} 
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構造函數的參數的任何類將與MyConfigSqlRepository注入,這將給你可以隨意加載和保存的對象。

如果您沒有使用IoC容器,那麼在應用程序啓動時您只需要new上調MyConfigSqlRepository,然後手動將實例注入到需要它的類型的構造函數中。

這種方法唯一的辦法是,如果你還沒有一個DependencyInjection友好的應用程序結構,這可能意味着大量的重構 - 去耦對象並消除依賴關係,使得單元測試更容易專注於單一方面,並​​且更容易模擬依賴關係......以及其他優點。