Есть файл кастомных конфигураций для нескольких клиентов, которые я держу в памяти через Single Ton. Долго все работало без проблем но тут внезапно прилетела заявка от клиента, что одна из транзакций совершалась по одному клиенту, а прилитела на счет другого. Мне кажется я догадываюсь в чем дело, но очень нужен взгляд со стороны (подозреваю, что это и вовсе может быть вредительство определенных лиц имеющих доступ к конфигу, но это не точно). Код старался максимально обезличить, но по запросу предоставлю всю необходимую дополнительную информацию. Может ли сатический метод Веб-приложения вернуть данные одного клиента другому?
Заранее спасибо за помощь.
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Web.Configuration;
namespace App
{
public class Settings
{
private static GetSettings _items = null;
private static string path = "";
static Settings()
{
//подписываемся на изменение файла
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = AppDomain.CurrentDomain.BaseDirectory;
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Filter = "Имя файла настроек";
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = true;
}
protected Settings()
{
ReadSettings("Конструктор");
}
private static GetSettings.Client GetSettingsForClient(string clientId)
{
try
{
if (_items != null && _items.Clients.Any())
{
clientId = clientId.Trim();
return _items.Clients.First(x => x.ClientId.Equals(clientId));
}
else
{
//logger
return null;
}
}
catch (Exception e)
{
//logger
return null;
}
}
//метод, доступный из вне, который возвращает настройки клиента:
public static GetSettings.Client GetSettings(string clientId)
{
GetSettings.Client clientInfo = null;
try
{
for (int i = 0; i < 3; i++)
{
//SingleTon
if (_items == null || !_items.Clients.Any())
{
new Settings();
}
//думаю, что проблема вот здесь, но это не точно:
//метод статический и мы получилинастройки для одного клиента, а вернули эти настройки другому.
//Но с другой тороны - если бы это было так - то транзакции были бы перепутаны местами, а у нас ситуация когда одна транзакция просто не по тому мерчанту прошла
clientInfo = GetSettingsForClient(clientId);
if (clientInfo != null) break;
Thread.Sleep(50);
}
return clientInfo;
}
catch (Exception e)
{
//logger
return null;
}
}
private static void OnChanged(object source, FileSystemEventArgs e)
{
ReadSettings("Событие OnChanged", e);
}
private static void ReadSettings(string method, FileSystemEventArgs e = null)
{
try
{
if (method == "Событие OnChanged")
{//логеры старых и новых настроек добавлены после инцидента, так что я не знаю менялся ли файл
string oldSettings = _items != null ? Newtonsoft.Json.JsonConvert.SerializeObject(_items) : "На момент обновления файлоа конфигурации настройки не были загружены в память";
logger.SettingsLog("Выполнено изменение файла настроек. Старые настройки: \n\r" + oldSettings);
}
path = "путь к файлу";
if (File.Exists("путь к файлу"))
{
_items = ServicesMethod.DesserializeJsonFromFile(path, new GetSettings());
if (_items != null && method == "Событие OnChanged")
{
logger.SettingsLog("Новые настройки: " + Newtonsoft.Json.JsonConvert.SerializeObject(_items));
}
}
else
{
//logger
}
}
catch (ArgumentNullException ex)
{
//logger
}
catch (Exception ex)
{
//logger
}
}
}
}
Да, в вашем коде есть такая возможность, что по одному и тому же запросу приедут разные клиенты.
Я не буду писать оценки качества вашего кода (только отмечу, что вам есть куда его улучшать), я просто покажу вам самую очевидную из проблем, что бросилась в глаза.
Вы в многопоточном окружении используете статическое поле, что очень плохо
private static string path = "";
Это поле у вас используется при чтении файлов
path = "путь к файлу";
if (File.Exists("путь к файлу"))
{
_items = ServicesMethod.DesserializeJsonFromFile(path, new GetSettings());
if (_items != null && method == "Событие OnChanged")
{
.......
}
}
А теперь представьте 2 параллельных вызова к вашему методу, и в момент, когда первый вызов ещё не закончил свое выполнение, второй вызов изменил значение статического поля, которое всё ещё используется в первом вызове. То есть, по идее, после этого, оба вызова будут работать с одинаковым именем файла, не зависимо от того, с какими параметрами был сделан первый вызов.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Код который у меня, ошибка на последней строчке
подскажите, пожалуйста, как я могу получить сумму одинаковых элементов в двух списках? И добавить в конечный список уникальные элементы?
Создал в MySQL тестовую базуОдна таблица: