У меня есть приложение ASP.NET с большим количеством динамического содержимого. Содержимое одинаково для всех пользователей, принадлежащих конкретному клиенту. Чтобы уменьшить количество обращений к базе данных, необходимых для каждого запроса, я решил кэшировать данные на уровне клиента. Я создал статический класс ("ClientCache") для хранения данных.
Наиболее часто используемый метод класса — это "GetClientData", который возвращает объект ClientData, содержащий все сохраненные данные для конкретного клиента. Однако ClientData загружается лениво: если запрошенные данные клиента уже кэшированы, вызывающая сторона получает кэшированные данные; в противном случае данные извлекаются, добавляются в кеш и затем возвращаются вызывающей стороне.
В конце концов я начал получать периодические сбои в методе GetClientData в строке, где объект ClientData добавляется в кеш. Вот тело метода:
public static ClientData GetClientData(Guid fk_client)
{
if (_clients == null)
_clients = new Dictionary<Guid, ClientData>();
ClientData client;
if (_clients.ContainsKey(fk_client))
{
client = _clients[fk_client];
}
else
{
client = new ClientData(fk_client);
_clients.Add(fk_client, client);
}
return client;
}
Текст исключения всегда выглядит примерно так: «Объект с таким ключом уже существует». Конечно, я пытался написать код так, чтобы просто нельзя было добавить клиента в кеш, если он уже есть.
На данный момент я подозреваю, что у меня есть состояние гонки, и метод выполняется дважды одновременно, что может объяснить, как произойдет сбой кода. Однако меня смущает то, как этот метод вообще может выполняться дважды одновременно. Насколько мне известно, любое приложение ASP.NET обрабатывает только один запрос за раз (поэтому мы можем использовать HttpContext.Current).
Итак, может ли эта ошибка быть состоянием гонки, которое потребует установки блокировок в критических разделах? Или я пропустил более очевидную ошибку?