Архив за месяц: Апрель 2016

Импорт конфигурационных настроек сервисами и клиентами WCF

В некоторых случаях службы и клиенты удобно реализовывать в виде отдельных DLL, которые затем могут быть использованы различными приложениями. Например: MyService.dll и MyClient.dll. Предполагается, что они будут находиться в подкаталогах ./Extensions/MyExtensionName/ хостовых приложений, дабы при необходимости оный контент всегда можно было бы просто удалить даже вручную, не зацепив при этом случайно ресурсы основного приложения.

Однако, будучи подгруженными в хостовое приложение они, как и любые другие DLL, по умолчанию будут искать свои настройки в составе конфигурационного файла этого приложения. Всё же мне бы не хотелось в чужой config-файл вносить правки, необходимые для работы моих сервисов или клиентов, ну или хотелось бы, по крайней мере, минимизировать объём таких корректировок настолько, насколько это возможно... На мой взгляд, предпочтительным способом была бы возможность сохранения нужных мне настроек в отдельных конфигурационных файлах, находящихся рядом с соответствующей DLL моего сервиса или клиента, т.е. в файлах MyService.dll.config и MyClient.dll.config.

Экспорт конфигурационных настроек на стороне сервиса
Начиная с .NET 4.5 в классе реализации сервиса можно определить метод Configure со следующей сигнатурой:

public static void Configure(ServiceConfiguration config)

Этот метод будет вызван WCF перед началом использования нашей службы. В нём можно выполнить загрузку конфигурационных настроек из внешнего файла, например так:

public static void Configure(ServiceConfiguration config) {
    ExeConfigurationFileMap configMap = new ExeConfigurationFileMap();
    configMap.ExeConfigFilename = typeof(MyService).Assembly.Location + ".config";
    Configuration dll_config = ConfigurationManager.OpenMappedExeConfiguration(configMap,
        ConfigurationUserLevel.None);
    config.LoadFromConfiguration(dll_config);
}

Однако в бочке мёда имеется и ложка дёгтя: в процессе импорта настроек WCF будет игнорировать все базовые адреса, обозначенные в импортируемом файле. Соответственно, либо эти базовые адреса нужно будет предварительно указать в конфигурационном файле самого хостового приложения (чего делать не очень хотелось бы, хотя это и не смертельно), либо в составе импортируемого файла настроек для конечных точек подключения и для метаданных использовать только полные адреса. Какой из вариантов выбрать - это уже нужно будет смотреть по ситуации.

Например, если расширение хранится в каталоге %AppData%/CompanyName/ApplicationName/Extensions/MyExtensionName/ с тем, чтобы предоставлять пользователю возможность править конфигурационные настройки или вовсе удалять расширение, то нужным вариантом будет второй.

А если пользователь не имеет административных прав и расширение хранится в каталоге %ProgramFiles%/CompanyName/ApplicationName/Extensions/MyExtensionName/, то в данном случае вариант использования - это дело вкуса администратора.

Экспорт конфигурационных настроек на стороне клиента
На стороне клиента использовать метод Configure в коде наших прокси не получится, но начиная с WCF 4.0 нам в помощь появился класс ConfigurationChannelFactory. Его можно создать в конструкторе создаваемого нами прокси  и использовать в процессе работы например так:

[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class Drawing : IDisposable, IDrawing {

    IDrawing Channel;
    ConfigurationChannelFactory<IDrawing> channelFactory;

    public void Open() {
        if (channelFactory.State != CommunicationState.Opened &&
            channelFactory.State != CommunicationState.Opening)
            channelFactory.Open();
    }

    public void Close() {
        if (channelFactory.State == CommunicationState.Opened)
            channelFactory.Close();
    }

    public CommunicationState State
    {
        get { return channelFactory.State; }
    }

    public Drawing(string endpointName) {
        ExeConfigurationFileMap configMap = new ExeConfigurationFileMap();
        configMap.ExeConfigFilename = typeof(Drawing).Assembly.Location + ".config";
        Configuration dll_config = ConfigurationManager.OpenMappedExeConfiguration(configMap,
            ConfigurationUserLevel.None);
        channelFactory =
            new ConfigurationChannelFactory<IDrawing>(endpointName, dll_config, null);
        Channel = channelFactory.CreateChannel();
    }

    public void Dispose() {
        if (channelFactory != null&& channelFactory.State == CommunicationState.Opened)
            channelFactory.Close();
    }

    // here is other members...   
}
Обратите внимание на то, что в процессе реализации нужного нам прокси мы обошлись без наследования от класса ClientBase.

Ссылки:

Импорт конфигурационных настроек сервисами и клиентами WCF

В некоторых случаях службы и клиенты удобно реализовывать в виде отдельных DLL, которые затем могут быть использованы различными приложениями. Например: MyService.dll и MyClient.dll. Предполагается, что они будут находиться в подкаталогах ./Extensions/MyExtensionName/ хостовых приложений, дабы при необходимости оный контент всегда можно было бы просто удалить даже вручную, не зацепив при этом случайно ресурсы основного приложения.

Однако, будучи подгруженными в хостовое приложение они, как и любые другие DLL, по умолчанию будут искать свои настройки в составе конфигурационного файла этого приложения. Всё же мне бы не хотелось в чужой config-файл вносить правки, необходимые для работы моих сервисов или клиентов, ну или хотелось бы, по крайней мере, минимизировать объём таких корректировок настолько, насколько это возможно... На мой взгляд, предпочтительным способом была бы возможность сохранения нужных мне настроек в отдельных конфигурационных файлах, находящихся рядом с соответствующей DLL моего сервиса или клиента, т.е. в файлах MyService.dll.config и MyClient.dll.config.

Экспорт конфигурационных настроек на стороне сервиса
Начиная с .NET 4.5 в классе реализации сервиса можно определить метод Configure со следующей сигнатурой:

public static void Configure(ServiceConfiguration config)

Этот метод будет вызван WCF перед началом использования нашей службы. В нём можно выполнить загрузку конфигурационных настроек из внешнего файла, например так:

public static void Configure(ServiceConfiguration config) {
    ExeConfigurationFileMap configMap = new ExeConfigurationFileMap();
    configMap.ExeConfigFilename = typeof(MyService).Assembly.Location + ".config";
    Configuration dll_config = ConfigurationManager.OpenMappedExeConfiguration(configMap,
        ConfigurationUserLevel.None);
    config.LoadFromConfiguration(dll_config);
}

Однако в бочке мёда имеется и ложка дёгтя: в процессе импорта настроек WCF будет игнорировать все базовые адреса, обозначенные в импортируемом файле. Соответственно, либо эти базовые адреса нужно будет предварительно указать в конфигурационном файле самого хостового приложения (чего делать не очень хотелось бы, хотя это и не смертельно), либо в составе импортируемого файла настроек для конечных точек подключения и для метаданных использовать только полные адреса. Какой из вариантов выбрать - это уже нужно будет смотреть по ситуации.

Например, если расширение хранится в каталоге %AppData%/CompanyName/ApplicationName/Extensions/MyExtensionName/ с тем, чтобы предоставлять пользователю возможность править конфигурационные настройки или вовсе удалять расширение, то нужным вариантом будет второй.

А если пользователь не имеет административных прав и расширение хранится в каталоге %ProgramFiles%/CompanyName/ApplicationName/Extensions/MyExtensionName/, то в данном случае вариант использования - это дело вкуса администратора.

Экспорт конфигурационных настроек на стороне клиента
На стороне клиента использовать метод Configure в коде наших прокси не получится, но начиная с WCF 4.0 нам в помощь появился класс ConfigurationChannelFactory. Его можно создать в конструкторе создаваемого нами прокси  и использовать в процессе работы например так:

[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class Drawing : IDisposable, IDrawing {

    IDrawing Channel;
    ConfigurationChannelFactory<IDrawing> channelFactory;

    public void Open() {
        if (channelFactory.State != CommunicationState.Opened &&
            channelFactory.State != CommunicationState.Opening)
            channelFactory.Open();
    }

    public void Close() {
        if (channelFactory.State == CommunicationState.Opened)
            channelFactory.Close();
    }

    public CommunicationState State
    {
        get { return channelFactory.State; }
    }

    public Drawing(string endpointName) {
        ExeConfigurationFileMap configMap = new ExeConfigurationFileMap();
        configMap.ExeConfigFilename = typeof(Drawing).Assembly.Location + ".config";
        Configuration dll_config = ConfigurationManager.OpenMappedExeConfiguration(configMap,
            ConfigurationUserLevel.None);
        channelFactory =
            new ConfigurationChannelFactory<IDrawing>(endpointName, dll_config, null);
        Channel = channelFactory.CreateChannel();
    }

    public void Dispose() {
        if (channelFactory != null&& channelFactory.State == CommunicationState.Opened)
            channelFactory.Close();
    }

    // here is other members...   
}
Обратите внимание на то, что в процессе реализации нужного нам прокси мы обошлись без наследования от класса ClientBase.

Ссылки:

Об использовании событий pre-build и post-build в Visual Studio

В некоторых проектах, создаваемых при помощи Visual Studo, возникает необходимость выполнения различного рода дополнительных операций в pre-build [и | или] post-build.

Если исходный код проекта находится в сети, а не на локальном диске, то открывать его следует в Visual Studio через предварительно подключенный сетевой диск. Т.е. например, если исходный код проекта находится в каталоге "\\hyprostr\dfs\groups\developers\src\DwgSaveAs\", то следует предварительно создать сетевой диск при помощи команды NET ADD:

net add Y: "\\hyprostr\dfs\groups\developers"

После этого, открывать в IDE проект, находящийся в сети, всегда следует путём указания каталога "Y:\src\DwgSaveAs\", вместо его сетевого имени "\\hyprostr\dfs\groups\developers\src\DwgSaveAs". В этом случае значения переменных ProjectDir, TargetDir и т.п. будут так же содержать значения, начинающиеся с "Y:\", а не с "\\hyprostr\". Это позволит в pre-build и post-build использовать команды такие как COPY, т.е. такие, которые обычно не могут работать с UNC-путями.

Предположим, что в событии post-build нашего проекта размещена такая команда:

COPY /Y "$(ProjectDir)teigha_vc11_amd64dll\*" "$(TargetDir)*"

Если проект будет открыт в IDE с использованием сетевого пути ("\\hyprostr\..."), а не сетевого диска "Y:\...", то попытка выполнить операцию, обозначенную в post-build будет неудачной. Если же проект будет открыть с использованием сетевого диска, то обозначенная в команде операция будет выполнена успешно.

Циклы в pre-build и post-build

Обозначенная выше команда, размещённая в post-build, может оказаться нецелесообразной в использовании, если выполняется копирование большого количества файлов. В подобных случаях процесс сборки проекта может занимать времени больше, чем нам бы того хотелось. Да и вообще, каждый раз выполнять копирование файлов, не подвергавшихся изменению, не целесообразно...

Порой нам нужно копировать только такие файлы, которых ещё нет целевом каталоге. Например, это могут быть файлы библиотек сторонних разработчиков. Чтобы копировать только отсутствующие в целевом каталоге файлы, в нашем post-build предыдущий вариант команды можно заменить таким:

For %%F In ("$(ProjectDir)teigha_vc11_amd64dll\*.*") Do If Not Exist "$(TargetDir)%%~nxF" Copy "%%F" "$(TargetDir)%%~nxF"

Внимание!
Обратите внимание на то, что все символы % в данном случае должны быть продублированы. В этом нет необходимости в BAT-файлах, но при использовании подобных выражений в составе pre-build или post-build проектов Visual Studio такая потребность имеется.

Примечание
Несмотря на то, что решения открываемые через сетевой диск отображаются в группе Recent вкладки Start Page, тем не менее Visual Studio 2015 Update 2 не умеет их открывать через соответствующую ссылку, если пытаться сделать это сразу после запуска IDE. При попытке сделать это, появляется такое окошко:


Чтобы открыть решение через сетевой диск, сразу после запуска Visual Studio, придётся выбирать пункт Open Project на вкладке Start Page, или же сделать это через меню File -> Open Project/Solution. Кроме того, работает и способ открытия sln-файла решения (из сетевого диска) в Проводнике Windows.

Если затем закрыть решение, не завершая при этом работу IDE (т.е. при помощи пункта меню  File -> Close Solution), то соответствующая ссылка на решение в группе Recent будет работать. Причём работать будет и в том случае, если выбрав пункт меню File -> Open Project/Solution затем перейти в каталог решения и нажать кнопку Cancel - после этого, соответствующая ссылка в Recent сможет открывать решение. Правда всё это работает только до перезапуска IDE...


Об использовании событий pre-build и post-build в Visual Studio

В некоторых проектах, создаваемых при помощи Visual Studo, возникает необходимость выполнения различного рода дополнительных операций в pre-build [и | или] post-build.

Если исходный код проекта находится в сети, а не на локальном диске, то открывать его следует в Visual Studio через предварительно подключенный сетевой диск. Т.е. например, если исходный код проекта находится в каталоге "\\hyprostr\dfs\groups\developers\src\DwgSaveAs\", то следует предварительно создать сетевой диск при помощи команды NET ADD:

net add Y: "\\hyprostr\dfs\groups\developers"

После этого, открывать в IDE проект, находящийся в сети, всегда следует путём указания каталога "Y:\src\DwgSaveAs\", вместо его сетевого имени "\\hyprostr\dfs\groups\developers\src\DwgSaveAs". В этом случае значения переменных ProjectDir, TargetDir и т.п. будут так же содержать значения, начинающиеся с "Y:\", а не с "\\hyprostr\". Это позволит в pre-build и post-build использовать команды такие как COPY, т.е. такие, которые обычно не могут работать с UNC-путями.

Предположим, что в событии post-build нашего проекта размещена такая команда:

COPY /Y "$(ProjectDir)teigha_vc11_amd64dll\*" "$(TargetDir)*"

Если проект будет открыт в IDE с использованием сетевого пути ("\\hyprostr\..."), а не сетевого диска "Y:\...", то попытка выполнить операцию, обозначенную в post-build будет неудачной. Если же проект будет открыть с использованием сетевого диска, то обозначенная в команде операция будет выполнена успешно.

Циклы в pre-build и post-build

Обозначенная выше команда, размещённая в post-build, может оказаться нецелесообразной в использовании, если выполняется копирование большого количества файлов. В подобных случаях процесс сборки проекта может занимать времени больше, чем нам бы того хотелось. Да и вообще, каждый раз выполнять копирование файлов, не подвергавшихся изменению, не целесообразно...

Порой нам нужно копировать только такие файлы, которых ещё нет целевом каталоге. Например, это могут быть файлы библиотек сторонних разработчиков. Чтобы копировать только отсутствующие в целевом каталоге файлы, в нашем post-build предыдущий вариант команды можно заменить таким:

For %%F In ("$(ProjectDir)teigha_vc11_amd64dll\*.*") Do If Not Exist "$(TargetDir)%%~nxF" Copy "%%F" "$(TargetDir)%%~nxF"

Внимание!
Обратите внимание на то, что все символы % в данном случае должны быть продублированы. В этом нет необходимости в BAT-файлах, но при использовании подобных выражений в составе pre-build или post-build проектов Visual Studio такая потребность имеется.

Примечание
Несмотря на то, что решения открываемые через сетевой диск отображаются в группе Recent вкладки Start Page, тем не менее Visual Studio 2015 Update 2 не умеет их открывать через соответствующую ссылку, если пытаться сделать это сразу после запуска IDE. При попытке сделать это, появляется такое окошко:


Чтобы открыть решение через сетевой диск, сразу после запуска Visual Studio, придётся выбирать пункт Open Project на вкладке Start Page, или же сделать это через меню File -> Open Project/Solution. Кроме того, работает и способ открытия sln-файла решения (из сетевого диска) в Проводнике Windows.

Если затем закрыть решение, не завершая при этом работу IDE (т.е. при помощи пункта меню  File -> Close Solution), то соответствующая ссылка на решение в группе Recent будет работать. Причём работать будет и в том случае, если выбрав пункт меню File -> Open Project/Solution затем перейти в каталог решения и нажать кнопку Cancel - после этого, соответствующая ссылка в Recent сможет открывать решение. Правда всё это работает только до перезапуска IDE...


Книги, которые перевернут вашу жизнь

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

Первой книгой однозначно станет БИБЛИЯ. Это книга, к которой вы должны прийти. Это не та книга, которую нужно заставлять себя читать. Всему свое время.

«Атлант расправил плечи» также является достаточно интересной и полезной книгой. Это книга, которая меняет ваше впечатление, снимая розовые очки. Данная книга расскажет о том, что абсолютно каждый человек должен заниматься своим делом, а не приносить себя в жертву другим обстоятельствам. Самопожертвование тут рассматривается как самое ужасное, что может произойти у человека. Не нужно пытаться спасти мир. Намного полезнее будет, если каждый будет хорош выполнять то, что он умеет.

«Как завоевывать друзей и оказывать влияние на людей» — это книга известного Дейла Корнеги. Его творения пользуются прососом во всем мире и переведены на огромное количество языков. Его книги позволяют нам задуматься о том, как правильно выстраивать взаимоотношения с друзьями и близкими, а также завоевывать новых сторонников и единомышленников.

«Сказать жизни Да!» — отличная книга, которая расскажет вам про историю психолога, который сумел выжить в концлагере. При этом его рассказ о концлагере будет настолько жизнерадостным, что все ваши беды покажутся вам сущим пустяком. Это та книга, которая поможет в самую трудную минуту и которая навсегда изменит ваше представление о сложной ситуации.

«Поллианна. Юность Поллианны» — обязательно закиньте эту книгу в вашу электронную читалку. Как до сих пор не приобрети? Тогда вам нужно обратить внимание на сайт vivostore.ua, где и представлено огромное множество. Эта книга научит вас играть в достаточно интересную и полезную игру, которая называется «радость». Смысл этой игры заключается в том, что бы абсолютно в любой жизненной ситуации увидеть какой то позитив. По рассуждениями Полианны абсолютно любая ситуация имеет положительную сторону. Ваша задача — ее найти.

Сто лет одиночества безумно интересная и проверенная временем книга. Здесь множество героев со своими особенными судьбами, со своими проблемами и путями выхода их кризиса. И каждый герой принимает свой собственный выбор, самое главное, что правильный выбор. Пересказать эту книгу невозможно но абсолютно каждый должен, обязан прочитать.

Planing Poker

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

К решению были предъявлены следующие требования:
1. Простота
2. До окончания оценки никто не видит оценок остальных участников.
3. Считать среднюю оценку.
Пункт два возник из-за того, что как только первый ставит оценку (мы до этого использовали для совместной оценки Skype), все остальные начинают под нее подстраиваться, особенно если этот первый программист с большим опытом.
Ну а пункт три это к вопросу о том, что в долгое время работающих в одном составе командах, оценки особо не нужны (подробнее писал ранее здесь).
Итак, что собой представляет приложение.
Для простоты оно состоит из вебсервиса (без базы данных и с отсутствующей персистентностью), который отвечает за взаимодействие клиентов и клиентского приложения, которое запускают у себя участвующие в оценке.
Вот так выглядит главное окно (картинки кликабельны):
При входе необходимо указать имя и с какой ролью входит участник. А дальше для ведущего есть возможность указывать номер оцениваемого требования и завершать оценку, для всех есть возможность перейти по ссылке (номер оцениваемого требования) в систему управления задачами и вторая доступная возможность поставить оценку. Ведущий и все участники оценки имеют возможность видеть кто уже оценил (минус - оценки еще нет, плюс - оценку участник уже поставил). Как только все оценили (оценку если что можно и менять в процессе обсуждения), ведущий нажимает кнопку показать результаты оценки:
Показывается кто как оценил и среднее. Если оценки очень сильно разняться, можно еще раз обсудить, но в  большинстве случаев можно сразу брать среднее и ставить его в требование.
Вот такое простенькое приложение нам немного облегчает жизнь каждые две недели.

Время идет, ничего не меняется


Это самое ужасное рассуждение: если я не могу всего — значит, я ничего не буду делать.
 -- Лев Николаевич Толстой

Вот здесь, несколько картинок и рассуждений по Chaos Report 2015. Кому интересно, можно пойти и посмотреть в оригинале. Пару картинок которые мне показались интересными, я утащил под кат.

Первая картинка самая говорящая и именно она послужила причиной такого заголовка у этой заметки. Действительно, за последние 5 лет особо заметных изменений нет (картинки кликабельны):
Как была полностью успешна треть проектов, так и остается. Ровно половина проектов завершается со срывом сроков, запланированного объема работ или бюджета. И почти пятая часть от всех проектов так и не доходит до пользователей.
Вдумайтесь, за эти пять лет прошли тысячи конференций, выпущены миллионы книг и все это про то как писать код, управлять требованиями, проектировать архитектуру и в целом управлять проектами. В этот же период на смену четвертому PMBook вышел пятый. А воз и ныне там. Может мы не тем занимаемся?
Еще интересная картинка:
Из всех успешных проектов за 5 лет 62% это маленькие проекты! Т.е. если запускаешь средний или больше проект, шансы уложиться в срок и деньги составляют менее 7%. Одна пятнадцатая. Шансы вообще его хоть как-то выпустить в этом случае составляют 25%. Четверть! Впечатляет.
Ну и последняя картинка. Какие факторы наиболее важны для попадания в треть счастливчиков:
Как видно из картинки успех проекта на 60% состоит из поддержки руководства, эмоциональной зрелости (насколько люди хорошо взаимодействую друг с другом), вовлеченности пользователей и оптимизации процессов (в том числе, разбиением крупных проектов на мелкие).
Самое забавное, это Agile находящийся на 7 позиции. А анекдот здесь в том, что именно Agile говорит что надо взаимодействовать с пользователями, выпускать продукт инкрементально (в виде небольших проектиков закрываемых за две недели и поставляемых пользователю), а уж оптимизация процессов в Agile это один из ключевых моментов. Но ладно пусть будет седьмое место.
Вот так и живем...

Книги в PDF формате, доступные для скачивания

На ресурсе http://www.allitebooks.com/ выкладываются книги в формате PDF, доступные для свободного скачивания. Библиотека пополняется ежедневно (ну или почти ежедневно). Пользуюсь давно.  По указанной ссылке книги не испорчены (как это зачастую бывает в наше время) переводом с английского на русский язык. Я редко встречал качественный перевод, в виду чего с некоторых пор предпочитаю читать на языке оригинала.

Если кто-то знает адреса подобных (качественных!) ресурсов - обозначение их в комментариях темы приветствуется.

Книги в PDF формате, доступные для скачивания

На ресурсе http://www.allitebooks.com/ выкладываются книги в формате PDF, доступные для свободного скачивания. Библиотека пополняется ежедневно (ну или почти ежедневно). Пользуюсь давно.  По указанной ссылке книги не испорчены (как это зачастую бывает в наше время) переводом с английского на русский язык. Я редко встречал качественный перевод, в виду чего с некоторых пор предпочитаю читать на языке оригинала.

Если кто-то знает адреса подобных (качественных!) ресурсов - обозначение их в комментариях темы приветствуется.

Цитата дня


Проблема в том, что идиоты — самоуверены, а умные — полны сомнений.
 -- Бертран Рассел
P.s. Я понимаю, что объясненный анекдот, это не анекдот, но рекомендую посмотреть что писал  в своих философских трудах автор этой цитаты по поводу религии.