为什么我的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"];
}
除了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()
{
}
请注意,没有涉及重写!总之,应用程序实例在大多数情况下可能并不重要,我可以看到它没有可能与保持状态相关的场景,因为它的状态将由所处理的任意请求子集共享。因此,马特提到的完全正确的方式访问它可能不需要太频繁。
我记得现在,我的mvc应用程序的实现只是在get访问器中打开缓存。 doh – scottm
使用缓存通常不是适用于长寿命对象的合适存储位置。任何类上的静态字段或属性(如Application类)可能更准确。 – citykid