在 Web API 中缓存数据
Posted
技术标签:
【中文标题】在 Web API 中缓存数据【英文标题】:Caching Data in Web API 【发布时间】:2013-05-02 20:49:22 【问题描述】:我需要缓存在我的 ASP.NET Web API OData 服务中可用的大部分是静态的对象集合(可能每天更改 1 次)。此结果集用于跨调用(意味着不是特定于客户端调用),因此需要在应用程序级别进行缓存。
我对“Web API 中的缓存”进行了大量搜索,但所有结果都与“输出缓存”有关。这不是我在这里寻找的。我想缓存一个“People”集合,以便在后续调用中重用(可能有一个滑动到期)。
我的问题是,由于这仍然只是 ASP.NET,我是否使用传统的应用程序缓存技术将这个集合保存在内存中,还是我需要做其他事情?此集合不直接返回给用户,而是用作通过 API 调用进行 OData 查询的幕后来源。我没有理由在每次通话时都访问数据库以获取每次通话的准确相同信息。每小时到期就足够了。
有谁知道在这种情况下如何正确缓存数据?
【问题讨论】:
【参考方案1】:我最终使用的解决方案涉及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>
来考虑锁定和并发性的方法。总学分归于这篇文章:How to deal with costly building operations using 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
【讨论】:
如何调用这个 GetFromCache 方法?我需要在 valueFactory 参数中设置什么?如果我必须存储调用存储库的 Get 的输出,如何使用它,然后在后续调用中使用它?跨度> 【参考方案2】:是的,输出缓存不是您想要的。您可以使用 MemoryCache 将数据缓存在内存中,例如 http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.aspx 。但是,如果应用程序池被回收,您将丢失该数据。另一种选择是使用分布式缓存,例如 AppFabric Cache 或 MemCache 等等。
【讨论】:
是的,写完这篇文章后,我发现MemoryCache
在 System.Runtime.Caching
命名空间中看起来很完美。如果 AppPool 回收,我可能会丢失数据的警告是可以的,因为我只是试图防止在 every API 调用上重新调用数据库。使用MemoryCache.Get()
和MemoryCache.Add()
似乎对我很有效。 AddOrGetExisting()
看起来很酷,但不适合我的情况;在调用之前,它仍然需要先从数据库获取数据。我将AbsoluteExpiration
设置为 30 分钟。
只是作为帮助人们一路走来的一个标记,Azure 中推荐的缓存技术现在是 Redis。如果您的 API 实例超过 1 个,则需要 Redis 或其他分布式缓存。 Azure 托管缓存现在非常隐藏,只能从 Powershell 访问。他们只是将其保留在那里以帮助以前使用它的人。
如果你所做的只是缓存一些 WebApi 数据调用,那么 Redis 太昂贵了。以上是关于在 Web API 中缓存数据的主要内容,如果未能解决你的问题,请参考以下文章