2010-10-15 28 views
2

現在我有一個單身的問題,我只是寫在ASP.NET MVC應用 - 我的辛格爾頓看起來是這樣的:單身和ASP.NET MVC

public sealed class RequestGenerator : IRequestGenerator 
{ 
    // Singleton pattern 
    private RequestGenerator() 
    { 
     requestList = new Stack<Request>(); 
     appSettings = new WebAppSettings(); 
    } 
    private static volatile RequestGenerator instance = new RequestGenerator(); 
    private static Stack<Request> requestList = new Stack<Request>(); 
    // abstraction layer for accessing web.config 
    private static IAppSettings appSettings = new WebAppSettings(); 
    // used for "lock"-ing to prevent race conditions 
    private static object syncRoot = new object(); 
    // public accessor for singleton   
    public static IRequestGenerator Instance 
    { 
     get 
     { 
      if (instance == null) 
      { 
       lock (syncRoot) 
       { 
        if (instance == null) 
        { 
         instance = new RequestGenerator(); 
        } 
       } 
      } 
      return instance; 
     } 
    }  
    private const string REQUESTID = "RequestID"; 

    // Find functions 
    private Request FindRequest(string component, string requestId) 
    private List<Request> FindAllRequests(string component, string requestId) 

    #region Public Methods required by Interface 
    // Gets and increments last Request ID from Web.Config, creates new Request, and returns RequestID 
    public string GetID(string component, string userId) 

    // Changes state of Request to "submitted" 
    public void SetID(string component, string requestId) 

    // Changes state of Request to "success" or "failure" and records result for later output 
    public void CloseID(string component, string requestId, bool success, string result) 

    // Verifies that Component has generated a Request of this ID 
    public bool VerifyID(string component, string requestId) 

    // Verifies that Component has generated a Request of this ID and is owned by specified UserId 
    public bool VerifyID(string component, string userId, string requestId) 

    // Returns State of Request ID (Open, Submitted, etc.) 
    public Status GetState(string component, string requestId) 

    // Returns Result String of Success or Failure. 
    public string GetResult(string component, string requestId) 
    #endregion 
} 

我的控制器代碼看起來像這樣:

public ViewResult SomeAction() 
{ 
    private IRequestGenerator reqGen = RequestGenerator.Instance; 
    string requestId = reqGen.GetID(someComponentName, someUserId); 
    return View(requestId); 
} 

一切正常,我第一次打控制器。 「reqGen」被分配了單例的實例。一個新的Request實例被添加到Singleton的內部列表中。然後我們返回一個View()。下一次我點擊這個控制器的SomeAction()時,我期望Singleton用包含我剛剛添加的SomeClass實例的List來包含List,但是List是空的。

發生了什麼事?垃圾收集是否吞噬了我的物體?在ASP.NET MVC中實現Singleton模式時,是否需要考慮一些特殊的內容?

謝謝!

編輯:啊,燈泡剛剛點亮。所以每個新的頁面請求都會在一個全新的過程中進行!得到它了。 (我的背景是在桌面應用程序開發,所以這是我不同的範例...)

編輯2:當然,這裏有一些更多的澄清。我的應用程序需要一個請求號碼系統,請求的東西需要一個唯一的ID,但我沒有可用的數據庫。但是每個用戶都必須記錄每個請求的狀態。我也意識到,如果使用雙擊請求按鈕,它可以作爲調節會話的一種方法。一個單身人士似乎是要走的路,但意識到每個請求都在自己的過程中基本上消除了單身人士。我想這也消除了靜態類,對吧?

編輯3:好吧,我已經添加了我正在使用的實際代碼(減去每個方法的實現,爲了簡單起見...)我希望這更清楚。

EDIT4:我授牌的綠色對勾克里斯,因爲我開始意識到,應用程序級的單就像是有一個全球(?和全球的是邪惡,右) - 所有開玩笑除此之外,最好的選擇確實是讓DB和SQLite看起來最適合現在,儘管我將來肯定會看到自己轉向Oracle實例。不幸的是,最好的選擇是使用ORM,但這是另一種學習曲線。開溜。

編輯5:最後編輯,我發誓。 :-)

所以我嘗試使用HttpRuntime.Cache,但很驚訝地發現我的緩存經常被刷新/失效,無法弄清楚發生了什麼事情。那麼,我正在被我正在做的其他事情的副作用絆倒:寫入「Web.config」

答案 - >我不知道,當「web.config」改變了無論如何,該應用程序是重新啓動!是的,一切都被扔掉了。我的單身人士,我的緩存,一切。嘎。難怪沒有什麼是正確的。看起來像寫回到web.config通常是不好的做法,我現在要避開。

再次感謝所有幫助我解決這個問題的人。

+1

如果你正在做這個緩存重做,然後看看使用HttpContext.Current.Cache。 – 2010-10-15 21:40:18

+1

這是一個很好的問題!看着椒鹽捲餅過渡到網頁開發的過程將對許多未來的程序員有所幫助 – 2010-12-02 14:33:00

+0

@Chris,是的,我試着在我的問題和答案中詳細解釋一切,這樣每個人都可以從我的課程中學習(也是,所以當我幾個月後不可避免地忘了一些教訓,我可以快速提醒自己,我學到了什麼... ;-) – Pretzel 2010-12-02 16:46:59

回答

3

單例特定於處理實例。正在爲每個頁面請求生成新實例。頁面請求通常被認爲是無狀態的,因此來自一個頁面的數據不會只停留在另一個頁面。

爲了得到這個在應用層面的工作,實例變量將必須在那裏宣佈。有關如何創建應用程序級別變量的提示,請參閱this question。請注意,這會使所有請求都可用。這並不總是您想要的。

當然,如果你想實現某種類型的會話狀態的,那麼你可能只使用會話或使用某種類型的緩存程序。

UPDATE
根據您的編輯:靜態類不應該維護數據。它的目的是簡單地將一些常用方法組合在一起,但不應該在方法調用之間存儲數據。單例是完全不同的事情,因爲它是一個類,你只需要爲請求創建一個對象。

這些都不是你想要的。現在

,具有應用級單將可用於整個應用程序,但穿過請求,就必須進行相應的編碼。

它幾乎聽起來像你正試圖建立一個內存數據存儲。您可以沿着使用.NET Page.Cache,MemCache或Enterprise Library's Caching Application Block等各種緩存機制之一的路徑走下去。

然而,所有這些都在託管應用程序的工作進程得到回收事件得到清除的問題..這可以在最糟糕的時間內發生。而會發生基於諸如內存使用情況,一些計時器亂事過期,頁面一定數量的重新編譯等

相反,我會強烈建議使用某種類型的持久性存儲設備中。無論是隻讀取/寫入xml文件,還是將諸如SQL Lite之類的內容嵌入到應用程序中。 SQL Lite是一個非常輕量級的數據庫,不需要在服務器上安裝;你只需要組件。

+0

所以這是「靜態類」與「單一」比較中的那些實例之一,我應該實現靜態班級呢? – Pretzel 2010-10-15 21:19:06

+0

@Pretzel:不知道班級是什麼,或者你爲什麼只需要一個副本就很難說。班級做什麼?如果你真的需要它成爲一個數據容器,那麼緩存機制或會話可能會更好。雖然我不會在課堂上存儲課程。如果你提供你想要完成的事情的細節,這裏的很多人可以給你一些關於如何到達那裏的方向。 – NotMe 2010-10-15 21:25:15

+0

感謝您的更新。我已經添加了我正在使用的實際代碼,因此您可以更清楚地瞭解我正在做的事情。是的,我正在構建內存數據存儲。我沒有打算將請求存儲到數據庫或XML中(當然,還沒有)。這些請求正通過SMTP發送給用戶。我將看看SQL Lite。我應該考慮使用NHibernate還是實體框架?或者我應該直接對SQL Lite進行編碼? – Pretzel 2010-10-18 15:19:21

3

您可以使用依賴注入來控制類的生命。如果您使用的是Castle Windsor,則可以在web.config中添加此行。

<component id="MySingleton" service="IMySingleton, MyInterfaceAssembly" 
type="MySingleton, MyImplementationAssembly" lifestyle="Singleton" /> 

當然,佈線你的應用程序中使用DI超出了我回答的話題,但無論你使用它,這個答案可以幫助你,或者你可以在概念採取高峯,談戀愛用它。 :)

+0

我在幾個月前開始閱讀DI,現在已經習慣了編寫Interfaces(而不是Concrete類)的習慣,所以在我的代碼的某些地方我做了「手動注入」,但我還沒有設法採用了像溫莎城堡或Ninject這樣的DI容器。 (我還沒有完全琢磨如何使用它...)也許這將是我的項目這個週末。 – Pretzel 2010-10-16 12:34:17

+0

我試着用Ninject做DI,我能夠成功地注入單身人士,但是一旦進程死亡,單身人員就會死亡,所以這對我沒有任何作用。 – Pretzel 2010-10-18 19:28:34