C# 并发字典在页面加载之间未保存我的列表<字符串>值

本文关键字:列表 我的 保存 字符串 之间 字典 并发 加载 | 更新日期: 2023-09-27 18:30:18

我已经有一段时间没有被难倒了。 疯狂的是,我已经在代码的其他区域做了几次,所以它几乎是完全复制和粘贴,但除了这段代码无法正常工作。 所以我不知何故错过了一些非常明显的东西。

public class RoomCache
{
    private ConcurrentDictionary<string, List<string>> _dicOnlineTraders;
    ILoggingService _logService = new LoggingService();
    public RoomCache()
    {
        _dicOnlineTraders = new ConcurrentDictionary<string, List<string>>();
    }
    public void UpdateTraderCurrentRoom(string sRoom, string sTrader)
    {
        _dicOnlineTraders.AddOrUpdate(sRoom, new List<string>() { sTrader }, (x, y) => UpdateRoomOnlineTraderList(sTrader, y));
    }
    private List<string> UpdateRoomOnlineTraderList(string sTrader, List<string> aryTraderList)
    {
        try
        {
            if (!aryTraderList.Contains(sTrader))
            aryTraderList.Add(sTrader);
            return aryTraderList;
        }
        catch (Exception ex)
        {
            _logService.LogError(ex);
            return aryTraderList;
        }
    }
}

上面的类在 Application_Start() global.asax 中实例化.cs如下所示:

public static RoomCache RoomCache;
RoomCache = new RoomCache();

所以现在在页面加载之间,我的字典没有保留我在调用UpdateRoomOnlineTraderList时添加到列表中的值。 当我走过时,列表就在那里。 下次我加载时页面它消失了,我是 100%,没有其他任何东西可以从字典中删除此值。

我的字典如何在页面加载之间不保留值? 密钥仍保留,但价值只是消失。 我很困惑。

C# 并发字典在页面加载之间未保存我的列表<字符串>值

如果您绝对确定其他地方没有重新初始化 RoomCache 或从中删除预期数据的代码,我最好的猜测是您有两个应用程序域为您的 IIS 应用程序运行......因此,在一个w3wp工作进程下,您实际上在两个不同的应用程序域中有两个静态RoomCache。

您可以通过在手表或即时窗口中打印来自行检查:AppDomain.CurrentDomain.Id

如果两个页面加载实际上发生在不同的应用程序域中,则结果将是两个不同的 int 值。

通常,如果 ASP .NET 决定为您托管两个不同的应用程序域,则符合您的最佳利益...因此,如果您确实需要跨页面加载可靠地持久化的信息,则可以考虑使用进程外存储来存储您的信息。

或者,您可以使用 web.config 坚持要求 ASP .NET 将应用程序限制为仅一个 AppDomain。如果 ASP .NET 决定在页面加载之间回收您的 AppDomain(可能一直发生),这仍然不会保护您。

鉴于提供的代码,我没有看到错误。但是,我有一个想法。

如果将列表返回给调用方,则调用方可能会设置为 null...然后,这会将集合中的列表也设置为 null(因为它们当然是同一个列表)。

如果GetOnlineTradersWithSideEffects存在,这将导致该问题。

public class RoomCache
{
    private ConcurrentDictionary<string, List<string>> _dicOnlineTraders;
    ILoggingService _logService = new LoggingService();
    private static readonly object SynchronousReadLock = new object();
    // This is bad because the reference is passed out to the
    // caller and we can't be sure that callers will behave. Any
    // modifications to that list will change our list too.
    private List<string> GetOnlineTradersWithSideEffects(string sRoom)
    {
        List<string> theseTraders = null;
        _dicOnlineTraders.TryGetValue(sRoom, out theseTraders);
        return theseTraders; 
    }
    // A side-effect-free method of returning the list to a caller.
    private List<string> GetOnlineTraders(string sRoom)
    {
        List<string> theseTraders = null;
        _dicOnlineTraders.TryGetValue(sRoom, out theseTraders);
        lock (SynchronousReadLock)
        {
            // Create a new list to return to a caller, that has 
            // copies of the elements of the list in the dictionary.
            var localCopy = new List<string>(theseTraders);
            return localCopy;
        }
    }
    public RoomCache()
    {
        _dicOnlineTraders = new ConcurrentDictionary<string, List<string>>();
    }
    public void UpdateTraderCurrentRoom(string sRoom, string sTrader)
    {
        _dicOnlineTraders.AddOrUpdate(sRoom, new List<string>() { sTrader }, (x, y) => {});
    }
    private List<string> UpdateRoomOnlineTraderList(string sTrader, List<string> aryTraderList)
    {
        try
        {
            // Lock here too, when modifying the list so that our reads 
            // wait for writes and vice-versa.
            lock (SynchronousReadLock)
            {
                if (!aryTraderList.Contains(sTrader))
                    aryTraderList.Add(sTrader);
                return aryTraderList;
            }
        }
        catch (Exception ex)
        {
            _logService.LogError(ex);
            return aryTraderList;
        }
    }
}