понедельник, 5 сентября 2016 г.

app.config - как в него писать и читать из него при дебагинге и релизной сборке

Давно не писал, действительно интересно получилось.
Имеет WebForms приложение (да, их до сих пор приходится писать иногда).

Как дебажим приложение в Visual Studio, то она, как известно, создает специальную сборку в каталоге Debug. Обычно там что-то вроде такого, если не подключаем дополнительные библиотеки:
.exe - название экзешника
.pdb - информация для дебагинга
.exe.config - конфигурационный файл
.vshost.exe - запущенная VS копия .exe
.vshost.exe.сonfig - конфиг от .vshost.exe
.vshost.exe.manifest - ???

Прикол в том, что при работе с файлом конфигурации через ConfigurationManager, читать-то он читает, но просто так не пишет. Плюс к этому, если вносить изменения в конфиг по имени сборки, то изменения идут в .vshost.exe.сonfig.
Такое поведение приводит к тому, что после пересборки, снова встает копия файла .exe.config и, соответсвенно, настройки не применяются.

Выход: работать только с .exe.config

private static string GetSetting(string key)
        {
            Configuration cfg = ConfigurationManager.
OpenExeConfiguration(Assembly.GetExecutingAssembly().Location);
            AppSettingsSection appSettings = 
(AppSettingsSection)cfg.GetSection("appSettings");
            return appSettings.Settings[key].Value;
        }

private static void SetSetting(string key, string value)
        {
            Configuration configuration = ConfigurationManager.
OpenExeConfiguration(Assembly.GetExecutingAssembly().Location);
            configuration.AppSettings.Settings[key].Value = value;
            configuration.Save();

            ConfigurationManager.RefreshSection("appSettings");
        }

Первый метод читает, второй пишет :)

среда, 18 мая 2011 г.

Опеределение сколько дней в месяце и получение последнего дня в месяца в T-SQL

При разработке отчёта встала задача определения сколько дней в указанном месяце в указанный год (не забываем, что есть висакосные года, когда в феврале 29 дней). Долго чесать репу не пришлось и всё-таки решение на T-SQL достаточно простое. Ниже текст скалярной функции, которая вычисляет последний день указанного месяца, точнее по указанной дате возвращает дату конечного дня... в общем как-то так :)
---------------------------------------------------------------------------
CREATE FUNCTION GET_LASTDAY_MONTH
(
@DATE DATE
)
RETURNS DATE
AS
BEGIN
DECLARE @RESULT DATE
DECLARE @DAY_OF_MONTH TINYINT
DECLARE @TEMP_RESULT DATE
SET @DAY_OF_MONTH = DAY(DATEADD(MONTH, 1, CAST(@DATE AS DATETIME)) - DAY (DATEADD(MONTH, 1, @DATE)))
SET @TEMP_RESULT = DATEADD(DAY, (@DAY_OF_MONTH - DAY(@DATE)), @DATE)
SET @RESULT = @TEMP_RESULT
RETURN @RESULT

END
------------------------------------------------------------------------------------------
В всё просто :)

понедельник, 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 - строчка с названием одного из членов перечисления;