如何在C# WebAPI控制器方法中获取已缓存的数据
如何在WebAPI控制器中获取已缓存的数据
基于你已经实现的OutputCacheFilter,要在控制器方法中获取缓存数据,核心是复用Filter中一致的缓存键生成逻辑,并直接访问缓存容器。下面是具体的实现步骤:
1. 重构缓存键生成逻辑(避免重复代码)
首先把Filter中生成缓存键的逻辑抽成公共静态方法,这样控制器和Filter可以共用,保证键的一致性。修改你的OutputCacheFilter类:
public class OutputCacheFilter : ActionFilterAttribute { // 把原来的private静态缓存改成public,或者添加公共访问方法 public static readonly ObjectCache WebApiCache = MemoryCache.Default; // 其他原有字段和构造函数... // 添加公共静态方法生成缓存键 public static string GenerateCacheKey(HttpRequestMessage request, bool dependsOnIdentity = true) { // 处理Accept头为空的情况,避免NullReferenceException var acceptHeader = request.Headers.Accept.FirstOrDefault()?.ToString() ?? string.Empty; var baseKey = string.Join(":", request.RequestUri.OriginalString, acceptHeader); // 如果启用用户身份依赖,拼接用户标识(根据你的原有逻辑补充) if (dependsOnIdentity) { // var user = new SecurityHelper().GetUser(); // 取消注释并使用你的用户获取逻辑 // return $"{user}:{baseKey}"; return baseKey; // 暂时保留,根据实际需求调整 } return baseKey; } // 其他原有方法... }
2. 在控制器中获取缓存数据
以你的MessageController为例,假设要在GetMessage方法中复用GetMessages的缓存结果,可以这样实现:
public class MessageController : ApiController { [OutputCacheFilter()] public IHttpActionResult GetMessages() { // 原有逻辑... } public IHttpActionResult GetMessage(string messageCode) { if(string.IsNullOrEmpty(messageCode)) { return BadRequest("Please pass the messageCode in order to get the message."); } // 步骤1:生成和Filter一致的缓存键 var cacheKey = OutputCacheFilter.GenerateCacheKey(Request); // 步骤2:检查缓存是否存在 if(OutputCacheFilter.WebApiCache.Contains(cacheKey)) { // 步骤3:获取缓存的内容和ContentType var cachedContent = OutputCacheFilter.WebApiCache.Get(cacheKey) as string; var contentType = OutputCacheFilter.WebApiCache.Get(cacheKey + ":response-ct") as MediaTypeHeaderValue; if(cachedContent != null) { // 步骤4:反序列化缓存的JSON字符串为DTO对象 var cachedMessages = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Message>>(cachedContent); var targetMsg = cachedMessages.FirstOrDefault(o => o.Code.Equals(messageCode, StringComparison.InvariantCultureIgnoreCase)); if(targetMsg != null) { return Ok(targetMsg); } } } // 如果缓存未命中,走原有数据库查询逻辑 MesssageManager msgManager = null; try { msgManager = new MesssageManager(); List<Message> messages = msgManager.GetMessages(); var msg = messages.FirstOrDefault(o => o.Code.Equals(messageCode, StringComparison.InvariantCultureIgnoreCase)); return Ok(msg); } catch (Exception ex) { return InternalServerError(ex); } finally { msgManager = null; } } }
关键注意事项
- 依赖用户身份的缓存:如果你的
OutputCacheFilter启用了_dependsOnIdentity,一定要在生成缓存键时拼接用户标识,否则会获取到其他用户的缓存数据。 - 反序列化处理:因为Filter中缓存的是响应的字符串内容(通常是JSON),所以需要用JSON序列化库(比如Newtonsoft.Json)反序列化为对应的DTO类型。
- 空值处理:要处理Accept头为空、缓存内容为空的情况,避免抛出空引用异常。
- 代码小修正:你的DTO类
Message最后一行publi是拼写错误,应该改为public;MesssageManager多了一个s,建议统一修正。
内容的提问来源于stack exchange,提问作者Neeraj Kumar Gupta
相关产品推荐
相关产品推荐

