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%,没有其他任何东西可以从字典中删除此值。
我的字典如何在页面加载之间不保留值? 密钥仍保留,但价值只是消失。 我很困惑。
如果您绝对确定其他地方没有重新初始化 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;
}
}
}