понедельник, 19 апреля 2010 г.

The operation has timed out in .NET and connectionManagement

Произошла одна интересная ситуация на одной высоконагруженных систем, над которой мне как-то пришлось работать.

Ситуация следующая:
Один из компонентов системы, который разработан на .NET 2.0 и является Windows сервисом, так же он работал в большое количество потоков, вдруг начинал выдать ошибки о таймауте выполнения операции.
Начали расследование... поставили снифер, оказалось, что соединения даже не открывались. Точнее всё было ещё более интересней: соединения сначала нормально открывались по всем хостам, далее на один хост, на который шло больше всего сообщений, количество соединений доходило примерно до 20, а затем начинали сыпаться ошибки и именно только по этому хосту по остальным всё было нормально.

Долго думали и курили Гуголь, в итоге на одном из забугорных форумов была найдена заметка о том, что майкрософт ограничивает по-умолчанию количество исходящих соединений на один хост... вот такая вот интересная фича.

В общем-то вопрос решался простой вставкой вот такого текста в конфигурационный файл компонента приложения:

<connectionManagement>
<add address="*" maxconnection="5000">
</connectionManagement>

Т.е. тут происходит указание, что всего может быть не более пяти тысяч исходящих подключений. Вообще почитав доки на MSDN можно понять, что тут достаточно шаблонированное управление количеством исходящих подключений и можно конкретно указать как домен, так и поддомен целиком.

понедельник, 1 марта 2010 г.

ConfigurationManager vs WebConfigurationManager

Проблема была в следующем:
Писалась библиотека, которая должна одинаково хорошо работать как в WebApp, так и в ClientApp. Настройка библиотеки для работы, можно было бы осуществлять, как непосредственно (через установку свойств статических классов), так и через *.config приложения. Всё бы ничего, только вот незадача для получения данных из конфига в WebApp используется класс WebConfigurationManager, а для ClientApp используется ConfigurationManager. В общем-то они делают реализацию для одного и того же абстрактного класса. Начал думать, как отличить в каком контексте работает приложение. Было придумано куча вариантов, включая получение пути к конфигурационному файлу (из System.AppDomain.CurrentDomain.SetupInformation.ConfigurationFile и не париться вообще в отличении контекстов) и разбор его вручную чтобы найти свою секцию и забрать из неё данные. Но всё это как-то не прозрачно, да и запутано. А потом я вспомнил про слово-оператор as.... и получилось достаточно компактно и понятно:

DataMapConfigSectionHandler dmcsh;
dmcsh = ConfigurationManager.GetSection("ntlDataMapConfig") as DataMapConfigSectionHandler;
if (dmcsh == null)
{
dmcsh = WebConfigurationManager.GetSection("ntlDataMapConfig") as DataMapConfigSectionHandler;
}

После этого нужно dmcsh проверить на null, так как dmcsh может равняться null, если секция, которую вы указали не найдена.
Правда, такой подход всё равно накладывает определённые нехорошести: классы ConfigurationManager и WebConfigurationManager находятся в разных сборках соответственно System.Configuration.dll и System.Web.dll. CLR придётся загрузить их обе, и соответственно отъесть немного памяти, если для вас это критично, то, наверное всё-таки придётся загружать вручную конфигурационный файл и парсить его ручками, как XML документ.

четверг, 25 февраля 2010 г.

Конвертирование между типами System.String и Enum - кастомным.

В общем-то давно не писал, некогда как-то писать и тут начал возиться с системой используемой в .NET для создания собственных секций файлах .config. Всё бы ничего, только вот некоторые данные, которые должны храниться в конфиге приложения в системе имеют тип Enum.
Самое простое просто написать два хелпера: первый будет состоять из кучи if-else, где последовательно будут сравнивать строки и на выход выкинуть необходимое enum значение. Второй хелпер должен был бы конвертить Enum в строку, опять же просто switch перебирающий значения перечисления и возвращающий строку.

Почесав репу и скрепя клавиатурой сердцем решил так и сделать... но тут понял, что switch-то понятно работает в нормально сборке достаточно шустро - на хешах, а вот перебор вариантов if-else всё-таки перебор и он как известно достаточно медленная вещь.

Погуглив и попробовав несколько вариантов получилась такая вот тема:

1) Для конвертирования System.String в Enum:
(EnumType)Enum.Parse(typeof (EnumType), somethingString, true);

2) Для конвертирования Enum в System.String:
Enum.GetName(typeof(EnumType), somethingString);

Пояснения:
EnumType - это какой-то определённый нами энумератор;
somethingString - строчка с названием одного из членов перечисления;