在Web API中缓存数据

41

我需要对一组几乎静态(可能每天更改1次)的对象进行缓存,这些对象可以在我的ASP.NET Web API OData服务中使用。这个结果集在跨多个调用之间使用(意味着不是特定于客户端调用),因此需要在应用程序级别进行缓存。

我搜索了大量关于“Web API中的缓存”的内容,但所有结果都是关于“输出缓存”的。这不是我想要的。我想缓存一个“People”集合以便在随后的调用中重新使用(可能具有滑动过期时间)。

我的问题是,既然这仍然只是ASP.NET,那么我是否应该使用传统的应用程序缓存技术来将此集合持久化到内存中,还是我需要做其他事情?这个集合并没有直接返回给用户,而是作为OData查询的源使用在API调用的幕后。每次调用时都去数据库获取完全相同的信息是没有必要的。每小时过期就足够了。

有人知道如何在这种情况下正确地缓存数据吗?

2个回答

51

我最终使用的解决方案涉及到 System.Runtime.Caching 命名空间中的 MemoryCache。以下是最终用于缓存我的集合的代码:

//If the data exists in cache, pull it from there, otherwise make a call to database to get the data
ObjectCache cache = MemoryCache.Default;

var peopleData = cache.Get("PeopleData") as List<People>;
if (peopleData != null)
   return peopleData ;

peopleData = GetAllPeople();
CacheItemPolicy policy = new CacheItemPolicy {AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(30)};
cache.Add("PeopleData", peopleData, policy);
return peopleData;

我发现使用 Lazy<T> 的另一种方式可以考虑到锁定和并发。全部功劳归于这篇文章:如何处理使用 MemoryCache 进行昂贵的构建操作?

private IEnumerable<TEntity> GetFromCache<TEntity>(string key, Func<IEnumerable<TEntity>> valueFactory) where TEntity : class 
{
    ObjectCache cache = MemoryCache.Default;
    var newValue = new Lazy<IEnumerable<TEntity>>(valueFactory);            
    CacheItemPolicy policy = new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(30) };
    //The line below returns existing item or adds the new value if it doesn't exist
    var value = cache.AddOrGetExisting(key, newValue, policy) as Lazy<IEnumerable<TEntity>>;
    return (value ?? newValue).Value; // Lazy<T> handles the locking itself
}

1
如何调用这个 GetFromCache 方法?我需要传递什么 valueFactory 参数?如果我必须存储调用存储库的 Get 方法的输出,如何使用它并在后续调用中使用它? - F11

27

2
是的,在编写这个之后,我发现System.Runtime.Caching命名空间中的MemoryCache看起来非常完美。如果AppPool重新启动,我可能会丢失数据,但这没关系,因为我只是想防止在每个API调用上重新调用DB。使用MemoryCache.Get()MemoryCache.Add()对我来说似乎很好用。AddOrGetExisting()看起来很酷,但对我的情况不起作用;它仍然需要先从DB获取数据才能调用。我设置了30分钟的AbsoluteExpiration - atconway
5
为帮助读者更好地理解,建议在 Azure 中使用的缓存技术是 Redis。如果您的 API 有多个实例,则需要使用 Redis 或其他分布式缓存。Azure 托管缓存现在非常难找,只能通过 Powershell 访问。他们仅将其保留以帮助之前使用过它的人。 - Adam
1
如果你只是缓存一些WebApi数据调用,Redis就太昂贵了。 - Larry Flewwelling

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接