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

时间:2011-11-22 17:20:36

标签: c# asp.net-mvc-3 httpcontext

我有一个MVC3应用程序,我已经添加了几个简单的缓存变量作为属性。我在Application_Start中添加我的数据,然后在控制器中尝试将HttpContext.ApplicationInstance转换回我的类型以访问它。但是,该属性始终为null。这是一个例子:

编辑工作实例

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);
    }
}

2 个答案:

答案 0 :(得分: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"];
}

答案 1 :(得分:3)

除了Darin推荐内置缓存的正确答案外,还有关于Asp.Net中单身人士的说明。

MvcApplication不是单身

与非常普遍的看法相反,MvcApplication不是一个全球性的单身人士。该类被多次实例化,每个“管道”一个实例,因此性能计数器“管道实例计数”告诉您当前有多少MvcApplication实例被活化。添加一个默认的ctor并自己证明:

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

Debug会破坏该行或在DebugViewer中查看各种哈希码。要强制管道实例计数上升,请使用Thread.Sleep(5000)创建一个方法,Asp.Net将在您并行发出另一个http请求后启动一个新实例。

解决方案 - 如何在Asp.Net应用程序(MVC或WebForms)中实例化单例

但是,如果你的MvcApplication类有一个Application_Start()方法,那么这个方法实际上只在进程范围内被调用一次。这允许向MvcApplication添加静态字段并访问它们。

然后通过

访问这些字段
MvcApplication.MySingleValue
  • 明显。

HttpApplication怪异

HttpApplication类及其事件的设计非常奇怪,这可能是因为它与某些旧的基于COM的ASP页面的一些松散的向后设计兼容性。在那里,应用程序对象实际上只创建了一次,这肯定是与Asp.Net相关的错误信念的起源。 HttpApplication奇怪的一个例子:

protected void Application_Start()
{
}

请注意,没有涉及覆盖!

总之,应用程序实例在大多数情况下可能没什么兴趣,我看不出它与保持状态有关的情况,因为它的状态将由处理的任意子集共享。因此,Matt提到的完全正确的方式访问它可能不是经常需要的。