简体   繁体   English

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

[英]Using HttpContext.Current.Application to store simple data

I want to store a small list of a simple object (containing three strings) in my ASP.NET MVC application.我想在我的 ASP.NET MVC 应用程序中存储一个简单对象(包含三个字符串)的小列表。 The list is loaded from the database and it is updated rarely by editing some values in the site's admin area.该列表是从数据库加载的,很少通过编辑站点管理区域中的某些值来更新。

I'm thinking of using HttpContext.Current.Application to store it.我正在考虑使用HttpContext.Current.Application来存储它。 This way I can load it in the Global.asax:这样我就可以在 Global.asax 中加载它:

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

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

And then can easily reference it from any controllers or views as needed.然后可以根据需要轻松地从任何控制器或视图中引用它。 Then in the event, the admin area calls the updateMyObject controller action, I can just update the DB and load it in again and replace HttpContext.Current.Application["myObject"] .然后在事件中,管理区域调用updateMyObject控制器操作,我可以更新数据库并再次加载它并替换HttpContext.Current.Application["myObject"]

Are there any cons to doing this?这样做有什么缺点吗? It seems like it will work fine for what I am trying to achieve, however does anyone know of a better way to do this, assuming there is some major disadvantage to the method I've laid out?似乎它可以很好地满足我想要实现的目标,但是有没有人知道更好的方法来做到这一点,假设我提出的方法存在一些主要缺点?

What you actually do is Caching , and it's great, since you reduce calls to an external storage (a database or a file, whatever).您实际做的是Caching ,这很棒,因为您减少了对外部存储(数据库或文件,等等)的调用。 The trade-off is memory usage, of course.当然,权衡是内存使用。 Now, almost any modern web framework, including ASP.NET, includes some kind of a caching mechanism.现在,几乎所有现代 Web 框架,包括 ASP.NET,都包含某种缓存机制。 Either you use it, or you use some kind of a global variable.要么使用它,要么使用某种全局变量。

Storing data in ASP.NET's built-in Cache object has some significant advantages, since this mechanism actually checks the memory usage and removes the cached data according to some rules.将数据存储在 ASP.NET 的内置Cache对象中具有一些显着的优势,因为这种机制实际上会检查内存使用情况并根据某些规则删除缓存的数据。

However, if the data you want to cache is intensively used across the application, and its size is not too large (say, smaller than 1 MB), you may want to store it in as a global variable.但是,如果您要缓存的数据在整个应用程序中被大量使用,并且其大小不是太大(例如,小于 1 MB),您可能希望将其存储为全局变量。

In ASP.NET, global variables are achieved by either using the Application object, like you described in your question, or by writing public static properties/fields in an internal/public class.在 ASP.NET 中,全局变量是通过使用Application对象(如您在问题中描述的)或通过在内部/公共类中编写公共静态属性/字段来实现的。

Here's my solution to static properties.这是我对静态属性的解决方案。 Note that I use a locking object, to protect the inner data from corruption.请注意,我使用锁定对象来保护内部数据免受损坏。 It looks like this:它看起来像这样:

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

The usage is very simple:用法很简单:

First time, in Application_Start:第一次,在 Application_Start 中:

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

    WhateverClass.TheData = loadDataFromSql();
}

In any controller:在任何控制器中:

var myData = WhateverClass.TheData;

This approach is better because you have type safety, since this public static property can be explicitly declared with the exact type.这种方法更好,因为您具有类型安全性,因为可以使用确切类型显式声明此公共静态属性。 In addition, this kind of storage is more testable since it doesn't depend on the web context.此外,这种存储更易于测试,因为它不依赖于网络上下文。

HTH!哼!

HttpContext.Current.Application is essentially a hangover that is needed for backwards compatibility with classic ASP. HttpContext.Current.Application本质上是与经典 ASP 向后兼容所需的宿醉。 It's essentially a static Hashtable with classic ASP locking semantics (Application.Lock / Application.UnLock).它本质上是一个静态哈希表,具有经典的 ASP 锁定语义(Application.Lock / Application.UnLock)。

As a weakly-typed Hashtable, you will need to cast objects you retrieve:作为弱类型哈希表,您需要转换您检索的对象:

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

In an ASP.NET application that is not a migration from classic ASP, I would prefer using other standard .NET stuff, such as:在不是从经典 ASP 迁移的 ASP.NET 应用程序中,我更喜欢使用其他标准的 .NET 内容,例如:

  • A static field, using .NET locking semantics if you need locking (eg the C# lock keyword, or a ReaderWriterLockSlim instance, depending on your requirements):一个静态字段,如果您需要锁定,则使用 .NET 锁定语义(例如,C# lock 关键字或 ReaderWriterLockSlim 实例,具体取决于您的要求):

    static MyObject myObject = LoadFromSql();静态 MyObject myObject = LoadFromSql();

  • The ASP.NET Cache - which has rich functionality for managing expiration, dependencies, ... ASP.NET 缓存 - 具有丰富的管理过期、依赖、...

Yes, using HttpContext.Current.Application will work fine for what you are doing.是的,使用HttpContext.Current.Application可以很好地完成您正在做的事情。 No problems.没问题。

HttpContext.Current.Application is simply a reference to the static global HttpApplicationState object in .NET for your Web Application, of which there should be one global instance per web application. HttpContext.Current.Application只是对 .NET 中 Web 应用程序的静态全局HttpApplicationState对象的引用,其中每个 Web 应用程序应该有一个全局实例。 By storing data there, you provide fast, thread-safe access to your global variables.通过在那里存储数据,您可以提供对全局变量的快速、线程安全的访问。 Be sure to lock them when updating values, as in this example:确保在更新值时锁定它们,如下例所示:

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

As others have mentioned, you can also create a series of static classes in your App_Code or other folder and there store global static values as well as your HttpContext.Current.Application values, where they can be safely checked for values or updated from the database, or update and check each other, working in tandem.正如其他人所提到的,您还可以在App_Code或其他文件夹中创建一系列静态类,并在那里存储全局静态值以及您的HttpContext.Current.Application值,在那里可以安全地检查值或从数据库更新它们,或相互更新和检查,协同工作。 I usually create a static global class to assist in the management and retrieval of the Application variables I store.我通常创建一个静态全局类来协助管理和检索我存储的应用程序变量。 In this way you have both the state dictionary of the HttpApplicationState class and the web application static objects working together to share and maintain global values.通过这种方式,您可以同时使用HttpApplicationState类的状态字典和 Web 应用程序静态对象来共享和维护全局值。 (Keep in mind each static class is assigned per worker process and there may be as many as 10 WP on average by default on many IIS web servers/web applications. So keep data in static types to a minimum.) (请记住,每个工作进程都分配了每个静态类,默认情况下,许多 IIS Web 服务器/Web 应用程序上的平均 WP 可能多达 10 个。因此,将静态类型的数据保持在最低限度。)

Keep in mind as some mentioned server farms do not share Application state.请记住,一些提到的服务器场不共享应用程序状态。 There are many ways to manage this.有很多方法可以管理这个。 I'm not a fan of cache because of the ways in which it can expire, fail, become stale, or get corrupted.我不喜欢缓存,因为它可能会过期、失败、陈旧或损坏。 A simpler solution is to simply use use the database and URL querystrings to communicate across servers and maintain state.一个更简单的解决方案是简单地使用数据库和 URL 查询字符串来跨服务器通信并维护状态。 Good luck!祝你好运!

If you're deploying to a single web server the approach would work.如果您要部署到单个 Web 服务器,则该方法可行。 Consider the Cache object for this as it provides more options for expiration if you need such functionality.为此考虑 Cache 对象,因为如果您需要此类功能,它会提供更多过期选项。 (See a comparison, albeit an aged one, here .) 在这里看一个比较,虽然是一个老的。)

If you're ever going to deploy to a web server farm or equivalent you should use memcached or another web farm friendly caching mechanism.如果您打算部署到网络服务器场或等效物,您应该使用memcached或其他网络场友好的缓存机制。 Both the Application and Cache objects only typically exist in a single server context; Application 和 Cache 对象通常只存在于单个服务器上下文中; if your user could be hitting multiple web servers during their session (and the cache needs to be identical) you'll need a shared cache that can be seen from each of the potential web servers.如果您的用户在他们的会话期间可能访问多个 Web 服务器(并且缓存需要相同),您将需要一个可以从每个潜在 Web 服务器看到的共享缓存。

Regardless of which path you take you will need to invalidate/reload your cache whenever the underlying data changes, which is custom code that varies by app.无论您采用哪条路径,只要基础数据发生变化,您都需要使缓存失效/重新加载,这是因应用程序而异的自定义代码。

This approach works well and can speed things considerably but it's a bit more work than you may realize at first glance...这种方法效果很好,可以大大加快速度,但它比您乍一看可能意识到的要多一些……

Application_Start really only gets fired on App Pool Recylce's, IIS Resets or reboots. Application_Start 实际上只会在 App Pool Recylce、IIS 重置或重新启动时触发。 If your updating these values that infrequently, why not store them in your web.config and access them that way?如果您不经常更新这些值,为什么不将它们存储在您的 web.config 中并以这种方式访问​​它们?

That being said, I don't think there is anything wrong with your approach.话虽如此,我认为您的方法没有任何问题 Though more typically I've seen people using config files for rarely changed values.虽然更常见的是我看到人们使用配置文件来获取很少更改的值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM