使用HttpContext.Current.Application存储简单数据

时间:2010-06-21 03:33:21

标签: c# asp.net-mvc httpcontext

我想在ASP.NET MVC应用程序中存储一个简单对象(包含三个字符串)的小列表。该列表是从数据库加载的,并且很少通过编辑站点管理区域中的某些值来更新。

我正在考虑使用HttpContext.Current.Application来存储它。这样我可以在Global.asax中加载它:

    protected void Application_Start()
    {
        RegisterRoutes(RouteTable.Routes);

        HttpContext.Current.Application["myObject"] = loadDataFromSql(); // returns my object
    }

然后可以根据需要从任何控制器或视图轻松引用它。然后,如果管理区域调用updateMyObject控制器操作,我只需更新数据库并再次加载它并替换HttpContext.Current.Application["myObject"]

这样做是否有任何缺点?看起来它会对我想要实现的目标起作用,但是有没有人知道更好的方法来做到这一点,假设我已经列出的方法有一些主要的缺点?

5 个答案:

答案 0 :(得分:30)

你实际做的是缓存,这很棒,因为你减少了对外部存储(数据库或文件,无论如何)的调用。当然,权衡是内存使用。现在,几乎任何现代Web框架(包括ASP.NET)都包含某种缓存机制。要么使用它,要么使用某种全局变量。

在ASP.NET的内置Cache对象中存储数据有一些显着的优点,因为这种机制实际上会检查内存使用情况并根据某些规则删除缓存的数据。

但是,如果要缓存的数据在应用程序中密集使用,并且其大小不是太大(例如,小于1 MB),则可能需要将其存储为全局变量。

在ASP.NET中,全局变量是通过使用Application对象实现的,就像您在问题中描述的那样,或者通过在内部/公共类中编写公共静态属性/字段来实现。

这是我对静态属性的解决方案。请注意,我使用锁定对象来保护内部数据免受损坏。它看起来像这样:

public class WhateverClass
{
  private static object theLocker = new object();
  private static YourDataType theData;
  public static YourDataType TheData
  {
    get
    {
      lock (theLocker)
      {
        return theData;
      }
    }
    set
    {
      lock (theLocker)
      {
        theData = value;
      }
    }
  }
}

用法非常简单:

第一次,在Application_Start中:

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);

    WhateverClass.TheData = loadDataFromSql();
}

在任何控制器中:

var myData = WhateverClass.TheData;

这种方法更好,因为您具有类型安全性,因为可以使用确切类型显式声明此公共静态属性。此外,这种存储更加可测试,因为它不依赖于Web环境。

HTH!

答案 1 :(得分:8)

HttpContext.Current.Application本质上是向后兼容经典ASP所需的宿醉。它本质上是一个带有经典ASP锁定语义的静态Hashtable(Application.Lock / Application.UnLock)。

作为弱类型的Hashtable,您需要转换您检索的对象:

MyObject myObject = (MyObject) HttpContext.Current.Application["myObject"];

在不是从传统ASP迁移的ASP.NET应用程序中,我更喜欢使用其他标准.NET内容,例如:

  • 静态字段,如果需要锁定,则使用.NET锁定语义(例如,C#lock关键字或ReaderWriterLockSlim实例,具体取决于您的要求):

    static MyObject myObject = LoadFromSql();

  • ASP.NET缓存 - 具有丰富的管理到期,依赖关系的功能......

答案 2 :(得分:3)

如果您要部署到单个Web服务器,则该方法可行。请考虑Cache对象,因为如果您需要此类功能,它会提供更多的到期选项。 (参见比较,虽然是老年人,here。)

如果您要部署到Web服务器场或同等身份,则应使用memcached或其他Web场友好缓存机制。 Application和Cache对象通常只存在于单个服务器上下文中;如果您的用户可能在会话期间遇到多个Web服务器(并且缓存需要相同),则您需要一个可以从每个潜在Web服务器看到的共享缓存。

无论您采用哪种路径,只要基础数据发生变化,您就需要使缓存无效/重新加载,这是自定义代码因应用而异。

这种方法运作良好,可以大大加快速度,但乍一看比你可能意识到的要多一些......

答案 3 :(得分:3)

是的,使用HttpContext.Current.Application可以正常工作。没问题。

" HttpContext.Current.Application"只是对静态全局" HttpApplicationState"的引用。 .NET中用于Web应用程序的对象,每个Web应用程序应该有一个全局实例。通过在那里存储数据,您可以快速,线程安全地访问全局变量。更新值时务必锁定它们,如下例所示:

System.Web.HttpContext.Current.Application.Lock();
System.Web.HttpContext.Current.Application["WebApplicationPath"] = MyWebApplicationPath;
System.Web.HttpContext.Current.Application.UnLock();

正如其他人所提到的,您还可以在App_Code或其他文件夹中创建一系列静态类,并存储全局静态值以及HttpContext.Current.Application值,可以安全地检查它们的值或更新从数据库,或相互更新和检查,协同工作。我通常创建一个静态全局类来帮助管理和检索我存储的Application变量。通过这种方式,您既可以使用HttpApplicationState类的状态字典,也可以使用Web应用程序静态对象来共享和维护全局值。 (请记住,每个工作进程都会分配每个静态类,并且在许多IIs Web服务器/ Web应用程序上,默认情况下平均可能有多达10个WP。因此,将静态类型的数据保持在最低限度。)

请记住,因为某些提到的服务器场不共享应用程序状态。有很多方法可以解决这个问题。我不是缓存的粉丝,因为它可能会过期,失败,变得陈旧或被破坏。一个更简单的解决方案是简单地使用数据库和url查询字符串来跨服务器进行通信并维护状态。祝你好运!

答案 4 :(得分:-1)

Application_Start实际上只会在App Pool Recylce,IIS Resets或重新启动时被触发。如果您不经常更新这些值,为什么不将它们存储在web.config中并以这种方式访问​​它们?

话虽如此,我认为你的方法没有任何错误的。虽然更常见的是我看到人们使用配置文件很少更改值。