为什么我的HttpApplication实例变量为空?

为什么我的HttpApplication实例变量为空?

问题描述:

我有一个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); 
    } 
} 

有由框架创建的应用程序的多个实例。为了验证这个,添加一个空的构造函数并在其中放置一个断点。你会看到这个构造函数会被多次命中,而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

除了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() 
{ 
} 

请注意,没有涉及重写!总之,应用程序实例在大多数情况下可能并不重要,我可以看到它没有可能与保持状态相关的场景,因为它的状态将由所处理的任意请求子集共享。因此,马特提到的完全正确的方式访问它可能不需要太频繁。