2013-05-08 79 views
29

我需要缓存大部分为静态的对象集合(可能每天更改1次),这些对象在我的ASP.NET Web API OData服务中可用。这个结果集用于不同的调用(意味着不是客户调用特定的),所以它需要在应用程序级缓存。在Web API中缓存数据

我做了一堆关于'在Web API缓存'的搜索,但所有的结果都是关于'输出缓存'的。这不是我在这里寻找的。我想缓存一个'People'集合以便在随后的调用中重用(可能会有滑动到期)。

我的问题是,由于这仍然只是ASP.NET,我是否使用传统的应用程序缓存技术来将此集合保存在内存中,还是有其他我需要做的事情?此集合是而不是直接返回给用户,而是用作通过API调用进行OData查询的幕后源。我没有理由每次打电话到数据库,以便在每次通话时获得相同的信息。每小时过期应该足够了。

任何人都知道如何在这种情况下正确缓存数据?

回答

21

是的,输出缓存不是你要找的。您可以使用MemoryCache将数据缓存在内存中,例如http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.aspx。但是,如果应用程序池被回收,则会丢失该数据。另一种选择是使用像AppFabric Cache或MemCache这样的分布式缓存。

+0

是写这之后,我发现'MemoryCache'在'System.Runtime.Caching'命名空间看起来很完美。如果AppPool回收的话,我可以放弃数据的警告是可以的,因为我只是试图阻止在每次API调用时重新调用数据库。使用'MemoryCache.Get()'和'MemoryCache.Add()'似乎对我来说效果不错。 'AddOrGetExisting()'看起来很酷,但不适合我的情况;它在调用之前仍然需要先从数据库获取数据。我设定了30分钟的“绝对时间”。 – atconway 2013-05-08 17:35:23

+5

作为帮助人们的标记,Azure推荐的缓存技术现在是Redis。如果您的API有一个以上的实例,则需要Redis或其他分布式缓存。 Azure托管缓存现在非常隐蔽,只能从Powershell访问。他们只是在那里帮助那些以前使用过它的人。 – 2015-05-28 10:07:41

+0

如果您所做的只是缓存一些WebApi数据调用,则Redis过于昂贵。 – 2017-02-02 21:47:28

31

我最终使用的解决方案在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 
} 
+1

如何调用这个GetFromCache方法?我需要在valueFactory参数中设置什么值?如果我必须存储Get的哪些调用存储库的输出,如何使用它,然后在随后的调用中使用它? – F11 2014-10-27 03:52:37