ASP.NET Core多项目共享缓存失效问题解决方案咨询
解决跨服务缓存同步问题的方案
方案一:使用分布式缓存(推荐Redis)
这是最直接成熟的方案,将Web API和MVC的本地内存缓存替换为共享的Redis分布式缓存,从根源解决缓存不同步问题。
- 改造步骤:
- 安装NuGet包:在Web API、MVC和DataAccess项目中安装
Microsoft.Extensions.Caching.StackExchangeRedis - 配置Redis连接:在两个项目的
appsettings.json中添加连接字符串"Redis": { "ConnectionString": "localhost:6379" } - 替换缓存服务注册:将原有的
AddMemoryCache和自定义CacheService单例注册,改为注册Redis分布式缓存;若自定义CacheService依赖IMemoryCache,则替换为依赖IDistributedCache// 在Web API和MVC的Program.cs中 builder.Services.AddStackExchangeRedisCache(options => { options.Configuration = builder.Configuration["Redis:ConnectionString"]; }); builder.Services.AddSingleton<ICacheService, CacheService>(); - 调整缓存操作逻辑:由于分布式缓存存储字节数组,需在
CacheService中添加序列化/反序列化处理(示例用System.Text.Json)public async Task SetCacheAsync<T>(string key, T value, TimeSpan expiration) { var json = JsonSerializer.Serialize(value); await _distributedCache.SetStringAsync(key, json, new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = expiration }); } public async Task<T?> GetCacheAsync<T>(string key) { var json = await _distributedCache.GetStringAsync(key); return json == null ? default : JsonSerializer.Deserialize<T>(json); } public async Task RemoveCacheAsync(string key) { await _distributedCache.RemoveAsync(key); }
- 安装NuGet包:在Web API、MVC和DataAccess项目中安装
方案二:基于HTTP通知的缓存同步
若暂时不想引入第三方缓存服务,可通过Web API主动通知MVC刷新缓存,适合小型项目场景。
- 实现思路:
- 在MVC项目中添加内部缓存失效接口,仅允许Web API访问:
[ApiController] [Route("internal/cache")] [Authorize(Policy = "AllowWebApiOnly")] // 需配置IP或密钥验证策略 public class CacheInvalidationController : ControllerBase { private readonly IMemoryCache _memoryCache; private readonly ICacheService _cacheService; public CacheInvalidationController(IMemoryCache memoryCache, ICacheService cacheService) { _memoryCache = memoryCache; _cacheService = cacheService; } [HttpPost("clear")] public IActionResult ClearCache([FromBody] string cacheKey) { _memoryCache.Remove(cacheKey); _cacheService.RemoveCache(cacheKey); return Ok(); } } - 在Web API触发缓存失效的逻辑中,调用MVC的上述接口:
private async Task NotifyMvcCacheInvalidation(string cacheKey) { using var httpClient = new HttpClient(); var mvcBaseUrl = _configuration["MvcBaseUrl"]; // 从配置读取MVC地址 await httpClient.PostAsJsonAsync($"{mvcBaseUrl}/internal/cache/clear", cacheKey); }
- 在MVC项目中添加内部缓存失效接口,仅允许Web API访问:
- 缺点:依赖服务间网络连通性,若MVC重启或网络故障会导致缓存不同步,需额外维护权限验证逻辑。
方案三:使用消息队列(如RabbitMQ)
通过消息队列广播缓存失效事件,解耦Web API和MVC的依赖,适合稍大规模项目。
- 实现步骤:
- 安装RabbitMQ客户端NuGet包
RabbitMQ.Client - Web API中发送缓存失效消息:
public void PublishCacheInvalidation(string cacheKey) { var factory = new ConnectionFactory() { HostName = "localhost" }; using var connection = factory.CreateConnection(); using var channel = connection.CreateModel(); channel.QueueDeclare(queue: "cache-invalidation", durable: false, exclusive: false, autoDelete: false, arguments: null); var body = Encoding.UTF8.GetBytes(cacheKey); channel.BasicPublish(exchange: "", routingKey: "cache-invalidation", basicProperties: null, body: body); } - MVC中添加后台服务订阅消息队列,收到消息后清理缓存:
public class CacheInvalidationService : BackgroundService { private readonly IMemoryCache _memoryCache; private readonly ICacheService _cacheService; public CacheInvalidationService(IMemoryCache memoryCache, ICacheService cacheService) { _memoryCache = memoryCache; _cacheService = cacheService; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { var factory = new ConnectionFactory() { HostName = "localhost" }; using var connection = factory.CreateConnection(); using var channel = connection.CreateModel(); channel.QueueDeclare(queue: "cache-invalidation", durable: false, exclusive: false, autoDelete: false, arguments: null); var consumer = new EventingBasicConsumer(channel); consumer.Received += (_, ea) => { var cacheKey = Encoding.UTF8.GetString(ea.Body.ToArray()); _memoryCache.Remove(cacheKey); _cacheService.RemoveCache(cacheKey); }; channel.BasicConsume(queue: "cache-invalidation", autoAck: true, consumer: consumer); await Task.Delay(Timeout.Infinite, stoppingToken); } } - 在MVC的Program.cs中注册后台服务:
builder.Services.AddHostedService<CacheInvalidationService>();
- 安装RabbitMQ客户端NuGet包
- 优点:解耦服务依赖,消息可持久化;缺点是需额外部署维护消息队列服务,复杂度高于Redis方案。
方案选择建议
- 毕业设计优先推荐Redis方案:实现简单,符合实际开发主流技术,能体现技术能力;
- 若不想引入第三方服务,可尝试HTTP通知方案,但需注意权限和可靠性;
- 消息队列方案适合规模较大的项目,毕设时间充足可尝试,但会增加部署复杂度。
内容的提问来源于stack exchange,提问作者Erik Nikoyan
相关产品推荐
相关产品推荐

