2011-11-22 95 views
3

我有一個MVC3應用程序,我添加了一些簡單的緩存變量作爲屬性。我在Application_Start中添加我的數據,然後在控制器中稍後嘗試將HttpContext.ApplicationInstance轉換回我的類型以訪問它。但是,該屬性始終爲空。這裏有一個例子:爲什麼我的HttpApplication實例變量爲空?

編輯以工作例

public interface IMyMvcApp 
{ 
    Hashtable Cache {get;set;} 
} 


public class MvcApplication: HttpApplication, IMyMvcApp 
{ 

    public Hashtable Cache 
    { 
     get { return Context.Cache["MyStuff"] as Hashtable; } 
     set { Context.Cache["MyStuff"] = value} 
    } 

    public void Application_Start() 
    { 
     Cache = new Hashtable(); 
     Cache.Add("key", new object()); 
    } 
} 

public class AController : Controller 
{ 
    protected override void OnActionExecuting(ActionExecutingContext context) 
    { 
     var myApp = context.HttpContext.ApplicationInstance as IMyMvcApp; 

     Assert.IsNotNull(myApp.Cache); 
    } 
} 

回答

5

有由框架創建的應用程序的多個實例。爲了驗證這個,添加一個空的構造函數並在其中放置一個斷點。你會看到這個構造函數會被多次命中,而Application_Start只會被命中一次。

因此,而不是重新發明輪子,你應該使用已經內置到框架Cache對象:

protected void Application_Start() 
{ 
    ... 
    Context.Cache["key"] = new object(); 
} 

然後:

protected override void OnActionExecuting(ActionExecutingContext context) 
{ 
    var value = context.HttpContext.Cache["key"]; 
} 
+0

我記得現在,我的mvc應用程序的實現只是在get訪問器中打開緩存。 doh – scottm

+0

使用緩存通常不是適用於長壽命對象的合適存儲位置。任何類上的靜態字段或屬性(如Application類)可能更準確。 – citykid

3

除了Darin的正確答案,建議在內置緩存中,關於Asp.Net中的單身人士的說明。

MvcApplication不是單

相反,非常普遍認爲,MvcApplication不是全局單。該類被多次實例化,每個「管道」實例化一個實例,所以性能計數器「管道實例計數」告訴你當前有多少個MvcApplication實例被活躍地佔用。添加一個默認的ctor並自己證明這一點:

public MvcApplication() 
{ 
    Trace.WriteLine(this.GetHashCode()); 
} 

調試破壞行或觀察DebugViewer中的各種哈希碼。爲了強制管道實例計數增加,使用Thread.Sleep(5000)創建一個方法,一旦你並行發出另一個http請求,Asp.Net將啓動一個新的實例。

解決方案 - 如何實例在Asp.Net應用單身(MVC或Web表單)

如果您MvcApplication類然而有一個的Application_Start()方法,那麼這種方法被稱爲其實只有一次,工藝寬。這允許向MvcApplication添加靜態字段並訪問它們。

這些字段,然後通過

MvcApplication.MySingleValue 
  • 明顯訪問。

HttpApplication的怪事

的HttpApplication類的設計和它的活動是很奇怪的,這大概有它的某種鬆散的向後兼容性設計很舊的基於COM的ASP頁面的原因。那裏的應用程序對象實際上只創建一次,這肯定是與Asp.Net相關的錯誤信念的起源。一個HttpApplication奇怪的例子:

protected void Application_Start() 
{ 
} 

請注意,沒有涉及重寫!總之,應用程序實例在大多數情況下可能並不重要,我可以看到它沒有可能與保持狀態相關的場景,因爲它的狀態將由所處理的任意請求子集共享。因此,馬特提到的完全正確的方式訪問它可能不需要太頻繁。