如何在ASP.NET Web API中使用缓存?

65

我正在使用带有WEB API的ASP.NET MVC 4

我有以下操作,在下面显示的操作中,我的服务方法调用DoMagic()方法进行数据库调用并返回整数值,然后我在每个页面上使用该操作,该操作使用ajax调用。

下面是我的WEB API操作:

[OutputCache(Duration = 86400, VaryByParam = "none")]
[ActionName("GetMyMagicNumber")]
public int GetMyMagicNumber()
{
    if (WebSecurity.IsAuthenticated)
    {
        var revenue = _magicService.DoMagic();
        return revenue;
    }
    return 0;
}

我的问题是:我尝试使用[OutputCache(Duration = 86400, VaryByParam = "none")],我期望只有第一次调用数据库时才会发生,随后对该操作的请求将返回缓存的值,但事实并非如此。

每次仍然会再次调用数据库,而且这需要时间。我该如何解决这个问题?


请参见https://dev59.com/5Ggu5IYBdhLWcg3wJDyb#11547814#11547814。 - phil soady
3
这是ASP.net Web Api,而不是MVC Web Api。它们是两种不同的技术。 - Alex
我假设你特别想要服务器端缓存? - Zapnologica
4个回答

61

链接已损坏,请更新答案并提供必要的信息。 - Pranesh Janarthanan
@pranesh-janarthanan,哪个链接失效了?两个链接对我来说都可以使用。也许你在公司防火墙后面? - OakNinja
1
今天早上我尝试打开第一个链接Strathweb时,它出现了错误。在回答问题时最好附带代码而不仅仅是指定参考链接。 - Pranesh Janarthanan
1
@PraneshJanarthanan 我同意,但是在开源的 Github 项目里通过发布数千行代码的方式来回答并不是一个好的做法。 - OakNinja
@OakNinja这不是很有建设性的评论。通常情况下,用链接回答是一个不好的做法,就像Pranesh提到的原因一样。请提供代码片段,演示如何使用此工具来解决OP的问题,并避免在未来只提供链接的答案。 - BLAZORLOVER
1
如果 GitHub 存储库被删除并且从 Visual Studio Marketplace 中移除了库,代码片段就没有任何作用了。由于这个问题是普遍性的,因此代码片段很快就会过时,因为它不会随着官方文档的更新而自动更改。尽管我通常同意这个观点,但这是典型的情况,其中代码片段根本没有任何价值。 - OakNinja

40
在您的项目中添加对 System.Runtime.Caching 的引用。 添加一个辅助类:
using System;
using System.Runtime.Caching;


public static class MemoryCacher
{
    public static object GetValue(string key)
    {
        MemoryCache memoryCache = MemoryCache.Default;
        return memoryCache.Get(key);
    }

    public static bool Add(string key, object value, DateTimeOffset absExpiration)
    {
        MemoryCache memoryCache = MemoryCache.Default;
        return memoryCache.Add(key, value, absExpiration);
    }

    public static  void Delete(string key)
    {
        MemoryCache memoryCache = MemoryCache.Default;
        if (memoryCache.Contains(key))
        {
            memoryCache.Remove(key);
        }
    }
}

然后从您的代码中获取或设置缓存中的对象:

list = (List <ChapterEx>)MemoryCacher.GetValue("CacheItem1");

并且

MemoryCacher.Add("CacheItem1", list, DateTimeOffset.UtcNow.AddYears(1));

7
Web API 是服务器端的,因此需要使用服务器端缓存解决方案。 - Sagi
1
点赞,因为我不熟悉“内存缓存”这个术语 ;) - Adil Ansari
2
发现这是目前Web API 2.2的最佳解决方案,因为一旦请求进来,就像Sagi所提到的那样,它基本上是在服务器端处理的。 - Trevor
2
请注意,您需要设置一些HTTP头。当然,需要设置Cache-Control和MaxAge,但最重要的是NoStore头。如果您不需要它,则可以不设置,但在复杂的REST API中,响应内容基于当前用户进行过滤和处理,而不是任何查询字符串参数时,确保不向用户提供无效数据非常重要。假设您使用一个用户登录,请求资源并获取数据,然后使用另一个用户登录,您将从第一个用户的缓存内容中获取内容,这将是灾难性的失败。请测试您的缓存条目 :) - Nexus
2
@Sangeeta 没有什么。直接使用 MemoryCache 即可。 - Matti Virkkunen
显示剩余6条评论

18

正如OakNinja所提到的,ASP.NET Web API目前不支持通过[OutputCache]属性进行输出缓存。

然而,有几个开源实现来填补这个空白:

Strathweb.CacheOutput

一个小型库将类似于MVC的“OutputCacheAttribute”的缓存选项带到Web API操作中。

Github:https://github.com/filipw/Strathweb.CacheOutput
许可:Apache v2

CacheCow

用于客户端和服务器端的ASP.NET Web API HTTP缓存实现。

Github:https://github.com/aliostad/CacheCow
许可:MIT

Scott Hanselmann撰写了一篇很好的博客文章,介绍了两个功能集。


能否在HTTP请求中添加特定的头信息,告知客户端如果需要的话可以缓存此请求? - Zapnologica
@Zapnologica:这个问题和答案都集中在服务器端缓存上。而你提到的是客户端缓存。为了获得最佳体验,你应该同时使用这两种技术。 - CodeZombie
有关服务器端缓存,没有具体提及?就我所知,OP使用的属性在MVC中同时执行两个功能。不过我注意到了。 - Zapnologica
1
看起来CacheCow现在支持属性路由。https://github.com/aliostad/CacheCow/commit/73b4417ce906da3ad6742130458ead808f8077d4 - antmeehan
提醒一下,如果有人想在 aspnet 框架的 Web API 项目中使用 CacheCow,请注意:具有相关示例的存储库的最后提交是 9635b94。文档非常有限(只能通过手动克隆 wiki 存储库 才能找到一些内容)。 - somethingRandom

8

[ResponseCache]现在在ASP.NET Core中得到支持。

特性看起来与[OutputCache]相似,但是[ResponseCache]仅用于客户端。

响应缓存会向响应中添加缓存相关的头信息。这些头信息指定了您希望客户端、代理和中间件缓存响应的方式。

https://learn.microsoft.com/en-us/aspnet/core/performance/caching/response

[ResponseCache(Duration = 3600)]
[HttpGet]
public IEnumerable<Product> Get()
{
  return _service.GetAll();
}

8
[ResponseCache]并非等同于[OutputCache],它仅通过在响应中添加缓存相关的头来在客户端缓存东西。这将减少客户端或代理向Web服务器发出请求的次数。[ResponseCaching]不会在Web服务器上缓存响应。 - Vasan
2
我还要补充一点,这是针对 .Net Core 的。 - TombMedia

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