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 を再初期化したり、そこから期待されるデータを削除したりするコードが他の場所にないことが絶対に確実な場合は、IIS アプリケーション用に 2 つの AppDomains が実行されていると推測されます...つまり、実際には 2 つの静的RoomCache は、1 つの w3wp ワーカー プロセスの下にある 2 つの異なる AppDomains にあります。

ウォッチまたはイミディエイト ウィンドウに印刷することで、これを自分で確認できます: AppDomain.CurrentDomain.Id

2 つのページの読み込みが実際に異なる AppDomains で発生している場合、結果は 2 つの異なる int 値になります。

一般に、ASP .NET が 2 つの異なる AppDomains をホストすることを決定した場合、それはあなたの最善の利益になります... したがって、ページの読み込み間で確実に永続化できる情報が本当に必要な場合は、情報のためにプロセス外ストアを検討することをお勧めします。

または、web.config を使用して、ASP .NET がアプリケーションを 1 つの 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 に答える