2

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

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% 没有其他东西从字典中删除这个值。

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

4

2 回答 2

1

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

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

如果这两个页面加载实际上发生在不同的 AppDomain 中,则结果将是两个不同的 int 值。

一般来说,如果 ASP .NET 决定为您托管两个不同的 AppDomain,这符合您的最大利益……因此,如果您确实需要在页面加载时可靠地持久保存信息,您可能会考虑为您的信息使用进程外存储。

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

于 2012-04-08T04:03:14.090 回答
1

鉴于提供的代码,我没有看到错误。不过,我有个主意。

如果列表曾经返回给调用者,那么调用者可能会设置为 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;
        }
    }
}
于 2012-04-08T06:09:53.800 回答