You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 9控制器中ConcurrentDictionary在IIS环境下读写不一致问题

问题原因与解决方案

核心问题

.NET 默认将控制器注册为**瞬态(Transient)**服务,每一次HTTP请求都会创建一个全新的控制器实例。你在POST请求中更新的是当前控制器实例的myConcurrentDictionary,但GET请求会触发新的控制器实例创建,它的字典自然是空的——两个请求操作的根本不是同一个字典对象。

可行解决方案

1. 将字典声明为静态字段

直接把myConcurrentDictionary定义为控制器类的静态成员,这样所有控制器实例都会共享同一个字典实例:

public class MyController : ControllerBase
{
    // 静态字段,全局共享同一个实例
    private static readonly ConcurrentDictionary<string, object> _myConcurrentDictionary = new();

    [HttpPost]
    public IActionResult UpdateData(string key, object value)
    {
        _myConcurrentDictionary.AddOrUpdate(key, value, (k, existingVal) => value);
        return Ok();
    }

    [HttpGet]
    public IActionResult GetData(string key)
    {
        if (_myConcurrentDictionary.TryGetValue(key, out var value))
        {
            return Ok(value);
        }
        return NotFound();
    }
}

注意:静态字段的生命周期和应用程序域绑定,应用重启后数据会丢失;如果是多服务器部署,静态字段无法跨节点共享数据。

2. 用依赖注入注册单例服务(推荐)

这是更符合.NET设计规范的方案,把字典封装成单例服务,通过依赖注入注入到控制器中:

步骤1:定义数据存储服务(可选但推荐接口化)

public interface IInMemoryDataStore
{
    ConcurrentDictionary<string, object> GetDictionary();
}

public class InMemoryDataStore : IInMemoryDataStore
{
    private readonly ConcurrentDictionary<string, object> _dataDictionary = new();

    public ConcurrentDictionary<string, object> GetDictionary()
    {
        return _dataDictionary;
    }
}

步骤2:在Program.cs中注册为单例

builder.Services.AddSingleton<IInMemoryDataStore, InMemoryDataStore>();

步骤3:控制器中注入使用

public class MyController : ControllerBase
{
    private readonly ConcurrentDictionary<string, object> _myConcurrentDictionary;

    // 通过构造函数注入单例服务
    public MyController(IInMemoryDataStore dataStore)
    {
        _myConcurrentDictionary = dataStore.GetDictionary();
    }

    [HttpPost]
    public IActionResult UpdateData(string key, object value)
    {
        _myConcurrentDictionary.AddOrUpdate(key, value, (k, existingVal) => value);
        return Ok();
    }

    [HttpGet]
    public IActionResult GetData(string key)
    {
        if (_myConcurrentDictionary.TryGetValue(key, out var value))
        {
            return Ok(value);
        }
        return NotFound();
    }
}

优势:遵循依赖注入原则,后续可以轻松替换为分布式缓存(如Redis),也便于编写单元测试。

3. 分布式缓存(多实例/持久化场景)

如果你的应用是多服务器部署,或者需要数据持久化,内存级别的存储方案就不适用了。此时可以使用.NET内置的IDistributedCache,或者直接集成Redis等分布式缓存组件,替代内存中的ConcurrentDictionary。

内容的提问来源于stack exchange,提问作者D052057

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 02:52:12