C#并发字典不保存我的列表<;字符串>;页面加载之间的值
我已经有一段时间没有被难倒了。疯狂的是,我已经在我的代码的其他区域做过几次了,所以它几乎是完全的复制和粘贴,但除了这段代码不能正常工作之外。所以我不知何故遗漏了一些非常明显的东西C#并发字典不保存我的列表<;字符串>;页面加载之间的值,c#,concurrentdictionary,C#,Concurrentdictionary,我已经有一段时间没有被难倒了。疯狂的是,我已经在我的代码的其他区域做过几次了,所以它几乎是完全的复制和粘贴,但除了这段代码不能正常工作之外。所以我不知何故遗漏了一些非常明显的东西 public class RoomCache { private ConcurrentDictionary<string, List<string>> _dicOnlineTraders; ILoggingService _logService = new LoggingServ
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;
}
}
}
因此,在页面加载之间,我的字典没有保留在调用UpdateRoMonLineTraderList时添加到列表中的值。当我一步一步走过时,清单就在那里。下次我加载时
该页面已消失,我100%确信没有其他内容可以从字典中删除该值
我的字典如何不保留页面加载之间的值?关键点仍然保留,但值只是消失。我很困惑。如果您绝对确定没有其他代码正在初始化RoomCache或从中删除预期数据,那么我最好的猜测是您有两个AppDomain在为IIS应用程序运行……因此实际上,在一个w3wp工作进程下,您有两个静态RoomCache在两个不同的AppDomain中 您可以通过在“监视”或“即时”窗口中打印:AppDomain.CurrentDomain.Id来检查这一点 如果两个页面加载实际上发生在不同的AppDomain中,则结果将是两个不同的int值 一般来说,如果ASP.NET决定为您托管两个不同的AppDomain,这将符合您的最佳利益。。。因此,如果您确实需要跨页加载可靠的信息,您可能会考虑一个进程外存储的信息。
或者,您可以使用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;
}
}
}
公共类RoomCache
{
专用ConcurrentDictionary\u DiconlineRaders;
ILogingService_logService=新的LoggingService();
私有静态只读对象SynchronousReadLock=新对象();
//这是不好的,因为引用传递给了
//打电话的人,我们不能确定打电话的人是否会表现良好。有吗
//对该列表的修改也会改变我们的列表。
私有列表GetOnlineTradersWithSideEffects(字符串空间)
{
List=null;
_TryGetValue(sRoom,超出这些交易商);
交易者返回;
}
//将列表返回给调用者的一种无副作用的方法。
私有列表GetOnlineTraders(字符串空间)
{
List=null;
_TryGetValue(sRoom,超出这些交易商);
锁(SynchronousReadLock)
{
//创建一个新列表以返回给调用方,该列表具有
//字典中列表元素的副本。
var localCopy=新列表(theseTraders);
返回localCopy;
}
}
公共RoomCache()
{
_dicOnlineTraders=新的ConcurrentDictionary();
}
公共void UpdateTraderCurrentRoom(字符串空间、字符串空间)
{
_AddOrUpdate(sRoom,newlist(){sTrader},(x,y)=>{});
}
私有列表更新omonlinetraderlist(string sTrader,List aryTraderList)
{
尝试
{
//修改列表时,也在此处锁定,以便
//等待写入,反之亦然。
锁(SynchronousReadLock)
{
如果(!aryTraderList.Contains(sTrader))
aryTraderList.Add(斯特拉德);
返回aryTraderList;
}
}
捕获(例外情况除外)
{
_logService.LogError(ex);
返回aryTraderList;
}
}
}
您的意思是词典包含您以前添加的键,但现在该值为空?或者你的意思是字典元素(键和值)完全消失了吗?是的!这就是奇怪的部分。该键仍保留在字典中,而我的值(列表)已不存在。如果整个字典是空的,我会想,不知何故,对象(即使是静态的)正在重新初始化。但现在这不可能了,因为密钥仍然存在,并且值为空。它是可重复的、一致的还是间歇性的问题?它是100%可重复的。这本词典永远不适用。我有一些其他字典使用相同的类型执行相同类型的操作(这就是我复制代码的地方!)。我应该澄清一件事。该列表作为其键的值保留在字典中,但计数为0。我可以添加键,直到母牛回家,它们留下来,列表总是会被删除,并在每次页面加载时返回到0。谢谢杰夫。根据您的建议,在我的API上创建了多个AppDomain.CurrentDomain.Id。原因是-我的API在多个工作进程中运行。我已更改为1个工作进程,应用程序开始正常工作。
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;
}
}
}