首先,MemoryCache 是System.Runtime.Caching 命名空间的一部分。它可以被MVC应用程序使用,但不限于MVC应用程序。
注意:还有一个 System.Web.Caching 命名空间(旧得多)只能与 ASP.NET 框架(包括 MVC)一起使用。
应该/可以用来加载静态信息以节省重复调用吗?
是的。
应该/可以用它来跨多个操作方法在视图上持久化数据吗?
是的。如果您的视图使用相同的数据,它可以。或者,如果您的 _Layout.cshtml 页面上有需要缓存的数据,可以在 global filter 中完成。
如果我在同一页面上有多个用户使用相同的 MemoryCache,会发生什么情况?
默认情况下,缓存在所有用户之间共享。它专门用于将数据保存在内存中,因此不必在每次请求时都从数据库中获取数据(例如,结帐页面上的状态名称列表,用于填充所有用户的下拉列表)。
最好将频繁更改的数据缓存一两秒钟,以防止大量并发请求成为对数据库的拒绝服务攻击。
缓存依赖于唯一键。通过将用户名或 ID 作为键的一部分,可以将单个用户信息存储在缓存中。
var key = "MyFavoriteItems-" + this.User.Identity.Name;
警告:此方法仅适用于您只有一个网络服务器的情况。它不会扩展到多个 Web 服务器。 Session state(用于个人用户内存存储)是一种更具可扩展性的方法。然而,会话状态并不总是值得tradeoffs。
典型的缓存模式
请注意,尽管MemoryCache 是线程安全的,但将它与数据库调用结合使用可以使操作跨线程。如果不加锁,您可能会收到多个对数据库的查询,以便在缓存过期时重新加载缓存。
因此,您应该使用double-checked locking 模式来确保只有一个线程能够通过以从数据库重新加载缓存。
假设您有一个列表,因为每个用户在到达特定页面时都需要该列表,因此对于每个请求来说都是浪费的。
public IEnumerable<StateOrProvinceDto> GetStateOrProvinceList(string country)
{
// Query the database to get the data...
}
要缓存此查询的结果,您可以添加另一个具有双重检查锁定模式的方法,并使用它来调用您的原始方法。
注意:一种常见的方法是使用decorator pattern 使缓存与您的 API 无缝。
private ObjectCache _cache = MemoryCache.Default;
private object _lock = new object();
// NOTE: The country parameter would typically be a database key type,
// (normally int or Guid) but you could still use it to build a unique key using `.ToString()`.
public IEnumerable<StateOrProvinceDto> GetCachedStateOrProvinceList(string country)
{
// Key can be any string, but it must be both
// unique across the cache and deterministic
// for this function.
var key = "GetCachedStateList" + country;
// Try to get the object from the cache
var stateOrProvinceList = _cache[key] as IEnumerable<StateOrProvinceDto>;
// Check whether the value exists
if (stateOrProvinceList == null)
{
lock (_lock)
{
// Try to get the object from the cache again
stateOrProvinceList = _cache[key] as IEnumerable<StateOrProvinceDto>;
// Double-check that another thread did
// not call the DB already and load the cache
if (stateOrProvinceList == null)
{
// Get the list from the DB
stateOrProvinceList = GetStateOrProvinceList()
// Add the list to the cache
_cache.Set(key, stateOrProvinceList, DateTimeOffset.Now.AddMinutes(5));
}
}
}
// Return the cached list
return stateOrProvinceList;
}
所以,您调用GetCachedStateOrProvinceList,它会自动从缓存中获取列表,如果没有缓存,则会自动将列表从数据库加载到缓存中。仅允许 1 个线程调用数据库,其余线程将等待直到缓存被填充,然后在可用时从缓存中返回列表。
另请注意,每个国家/地区的州或省列表将单独缓存。