Posts Tagged ‘.NET’

BLToolkit появился в галерее NuGet

Posted in Программирование on Июнь 4th, 2011 by yallie – Be the first to comment

Отличная новость: для BLToolkit теперь есть NuGet package. В пакете три комплекта бинарников для разных платформ: FX3.5, FX4 и SL4.

На тот случай, если требуется инструкция — вот она:

  1. Установите NuGet (это плагин для Visual Studio 2010).
  2. В ваш проект добавьте ссылку с помощью пункта меню Add Library Package Reference…
  3. В появившемся окне будет список пакетов NuGet, найдите там BLToolkit.
  4. Нажмите кнопку Install — пакет скачается и установится, а в проект добавится ссылка на библиотеку BLToolkit нужной версии.
  5. Убедитесь, что в вашем проекте Target Framework указан полный (Client Profile для компиляции не подойдет).

То же самое в виде комикса:

BLTNuget0 BLTNuget1 BLTNuget2 BLTNuget3

Zyan Framework

Posted in Программирование on Апрель 4th, 2011 by yallie – Be the first to comment

Близится выпуск второй версии проекта Zyan Framework, в котором я участвую в качестве разработчика. Думаю, к выпуску стоит приурочить перевод документации с немецкого языка. На английский я уже все перевел, осталось перевести на русский. Все статьи буду параллельно публиковать здесь. Итак, начнем со вступления:

Описание проекта

Zyan — это инфраструктура, упрощающая разработку распределенных приложений. Используя Zyan, вы можете опубликовать любой .NET-класс для удаленного взаимодействия. Zyan гибко настраивается и предоставляет все необходимые инструменты для построения модульных распределенных приложений.

Zyan требует для работы Microsoft .NET Framework 3.5 Client Profile, либо Mono 2.8 или выше (поддерживаются платформы Linux & Mac; см. скриншот).

Особенности

  • Интуитивный программный интерфейс
  • Широкий выбор вариантов хостинга .NET-компонентов (локальных или удаленных)
  • Два режима активации компонентов: сингльтон и режим одиночных вызовов
  • Поддержка TCP, HTTP и именованных каналов (для других протоколов возможно написать собственные плагины)
  • Дуплексный TCP-канал позволяет серверу взаимодействовать с клиентами, находящимся за NAT-ом или брандмауэром
  • Поддержка шифрованных каналов, не требующая сертификатов и наличия служб Active Directory
  • Простая в использовании расширяемая система аутентификации
    • Поддержка интегрированной аутентификации Windows (единый вход в систему)
    • Поддержка базовой аутентификации на серверах SAM (удобно при отсутствии служб Active Directory)
  • Расширяемое управление сессиями
    • Быстрый и легкий однопроцессный менеджер сессий (сессии хранятся в памяти сервера)
    • Масштабируемый менеджер сессии на базе SQL-сервера (сессии хранятся в СУБД)
    • Переменные сессий поддерживаются обоими вариантами менеджера сессий
  • Распределенные события обрабатываются так же просто, как button_Click в Windows.Forms-приложениях
  • Поддержка связывания распределенных EBC-компонентов (Event Based Components)

Простейший пример распределенного приложения

Публикация компонента:

// Создаем сервер ZyanDemo и привязываем его к TCP-порту 8080
var host = new ZyanComponentHost("ZyanDemo", 8080);
 
// Регистрируем тип и интерфейс компонента
host.RegisterComponent();

Вот и все, что нужно, чтобы компонент HelloWorldService стал доступным для удаленного взаимодействия.

Классу HelloWorldService не требуется наследование от MarshalByRefObject. Кроме того, не требуется разметка класса атрибутами ServiceContract и OperationContract. Любой .NET-класс может быть опубликован для удаленного взаимодействия. Единственное требование к нему — наличие интерфейса, через который будут осуществляться вызовы методов.

Получение доступа к службе с удаленного компьютера:

// Соединяемся с сервером
var connection = new ZyanConnection("tcp://localhost:8080/ZyanDemo");
 
// Создаем прокси-объект для HelloWorldService
var proxy = connection.CreateProxy();
 
// Вызываем метод (точно так же, как метод локального объекта)
proxy.SayHello("HelloWorld");

Дальнейшие подробности см. в разделе Документация.

Entity Framework и Oracle

Posted in Программирование on Март 25th, 2011 by yallie – Be the first to comment

Некоторое время назад вышла бета-версия провайдера ODP.NET с поддержкой Entity Framework (пока только 32-битная). Скачать провайдер можно на официальном сайте. Устанавливать ODP.NET нужно вместе с Oracle Developers Tools for Visual Studio (просто оставьте при установке выбранными все галочки, которые там стоят по умолчанию). Чтобы собрать простой проект и проверить работу провайдера в действии, понадобится рабочая база Oracle. Если под рукой нет тестовой базы, можно поставить и настроить Express-версию Oracle на своем обычном рабочем компьютере.

Создаем проект и подключаемся к серверу

После установки ODAC первым делом, конечно, нужно настроить файл TNSNAMES.ORA. Проще всего взять пустую болванку, которая после установки будет лежать в папке %ORACLE_HOME%/Network/Admin/Sample/tnsnames.ora, подправить и переместить на одну папку вверх (в Network/Admin). Выглядеть этот файл будет примерно так:

read more »

NotifyIcon в консольном приложении

Posted in Программирование on Февраль 27th, 2011 by yallie – Be the first to comment

Я постоянно имею дело с консольными программами, которые используются для хостинга служб WCF или .NET Remoting. Для отладки это самый удобный вариант: запускается быстро, консоль при случае используется для отладочной печати, и так далее. Выглядит такая программа обычно как-нибудь так (в случае с Remoting):

static void Main(string[] args)
{
    // Запускаем сервер
    var config = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
    RemotingConfiguration.Configure(config, false);
 
    // Работаем, пока не нажмут Enter
    Console.WriteLine("Server started. Press ENTER to quit.");
    Console.ReadLine();
}

Запустил, минимизировал такое окошко и крутится там себе сервер на фоне. Частенько бывает, что таких серверов запущено несколько (штуки три-четыре), и они постоянно торчат на панели задач. Изредка развернешь, чтобы прочитать, что там на консоли напечатано, а большую часть времени они только зря место занимают. Мне, честно говоря, это никогда особо не мешало. Пару недель назад один мой товарищ в разговоре заметил, что такие программки хорошо бы куда-нибудь прятать, оставляя одну иконку в системном трее. И с тех пор меня эти кнопки на панели задач стали раздражать.

Это такой мыслевирус, как кернинг: если человек не знает, что это такое, он живет себе спокойно. А если ему рассказать, да еще и показать на примере, чем плохой кернинг отличается от хорошего, — покой навеки утрачен. Теперь плохой кернинг постоянно будет ему бросаться в глаза на вывесках, объявлениях и рекламе в метро.

Короче говоря, пришлось-таки сделать небольшую библиотечку для сворачивания консоли в трей-иконку. Проблем тут, собственно, немного, но они есть (поэтому наивный вариант решения задачи — добавить компонент NotifyIcon с обработчиком DoubleClick, по которому что-нибудь там делать — не работает):

  • В .NET Framework нету легального способа получить в свое распоряжение окно консоли
  • В консольных приложениях нет конвейера сообщений

То есть, грубо говоря, добавить NotifyIcon можно (и в системном трее она будет нормально показываться), но обработчик события Click или DoubleClick вызываться не будет. Поскольку конвейера нет, событие просто некому переправить на обработку. А если и получится вызвать такой обработчик, непонятно, что в этом обработчике делать с консолью.

Чтобы справиться с этими проблемами, нужно 1) запустить свой конвейер сообщений в отдельном потоке и 2) заполучить хэндл окна консоли и прятать/показывать его средствами WinAPI. Выглядит так, как будто весь компонент будет состоять из сплошных вызовов p/invoke, то есть решение не будет блистать изяществом.

Однако выяснилось, что на деле не все так страшно. Оказывается, конвейеру WinForms — Application.Run(…) — вовсе не требуется главная форма. Он вполне сносно будет работать, если вместо этой формы ему подсунуть компонент NotifyIcon. То есть, первая часть задачи на самом деле сводится к запуску отдельного потока, в котором будет создаваться NotifyIcon и запускаться конвейер. И никакого p/invoke, что весьма приятно.

Хендл окна консоли, как выяснилось, иногда можно получить вот так: Process.GetCurrentProcess().MainWindowHandle. Здесь, разумеется, все портит слово «иногда»: на моем ноутбуке этот способ работает (Win7 x64), а на рабочем компьютере (WinXP x32) — нет. Вместо хендла возвращается IntPtr.Zero (MSDN говорит, что так задумано).

Так что для второй части задачи — прятать/показывать окно консоли — p/invoke все же нужен. Во-первых, нужен хендл консольного окна, во-вторых — метод ShowWindow(), который прячет или показывает окно по его хендлу. Весь WinAPI-мусор выносится в отдельный файл строчек примерно на 50 — ничего страшного. Жаль, правда, что портабельным этот вариант не будет, ну да хрен с ним, я и не претендовал на универсальность.

А дальше можно сделать приемлемую обертку, на иконку прицепить контекстное меню и заполнять его каким-нибудь fluent-интерфейсом:

using (var tools = new ConsoleTools())
{
    // настраиваем иконку в системном трее
    tools.SetNotifyIcon(SystemIcons.Shield)
        .SetTooltip(Console.Title + ": double click to toggle visibility")
 
        // добавляем обработчики событий (конвейер их обработает)
        .OnClick((s, e) => Console.WriteLine("NotifyIcon clicked!"))
        .OnDoubleClick((s, e) => tools.ConsoleVisible = !tools.ConsoleVisible)
 
        // добавляем пункты контекстного меню
        .AddMenuItem("About", SystemIcons.Question, ShowAboutBox)
        .AddMenuSeparator()
        .AddMenuItem("Hide console", (s, e) => tools.ConsoleVisible = false)
        .AddMenuItem("Show console", (s, e) => tools.ConsoleVisible = true)
        .AddMenuSeparator()
 
        // метод CloseConsole() работает как нажатие кнопки [x] на окне консоли
        .AddMenuItem("Close console",
            SystemIcons.Error, (s, e) => tools.CloseConsole());
 
    // А тут все как обычно, к примеру, RemotingConfiguration.Configure(...)
    Console.WriteLine("Press Enter to exit...");
    Console.ReadLine();
}

Остается только причесать немножко библиотеку и запустить ее куда-нибудь на CodePlex.

Exepack.NET 0.02 alpha

Posted in Программирование, Программы on Январь 25th, 2010 by yallie – 7 Comments

Не прошло и года, как я доделал Windows-версию упаковщика Exepack.NET. Правда, помимо интерфейса WinForms тут добавлена еще целая куча разных улучшений.

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

Системные требования:

  • .NET Framework версии 2.0 или выше (используется DeflateStream)
  • Windows XP или выше (используются системные процедуры для загрузки ресурсов)

Новые возможности версии 0.02 alpha:

  • Исполняемый файл генерируется с помощью Reflection.Emit
  • Ресурсы иконок и VersionInfo копируются из исходного файла
  • В Windows-версии можно добавлять в список дополнительные сборки для упаковки в тот же исполняемый файл
  • Добавлена защита от дизассемблирования Red Gate .NET Reflector-ом
  • Ну и, разумеется, добавлены новые исправлены старые ошибки.

Справа — скриншот Рефлектора, который пытается декомпилировать упакованный файл. Попытка декомпилировать в C# (и любой другой высокоуровневый язык) приводит к ошибке. Дизассемблирование в IL, разумеется, работает, как и ILDasm (любую программу, которая загружается и запускается под .NET Framework, можно дизассемблировать в IL-код).

P.S. Стоит иметь в виду, что это по-прежнему альфа-версия. Любое использование исключительно на свой страх и риск. Замечания об ошибках и неполадках приветствуются.

Хранилище для временных файлов

Posted in Программирование on Март 6th, 2009 by yallie – Be the first to comment

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

Сегодня я очередной раз написал такой класс-хранилище, и получилось вполне симпатично. Пользоваться им нужно вот так:

using (TempFileManager temp = new TempFileManager())
{
  using (FileStream fs = File.Create(temp["my-temp-file.txt"]))
  {
    // файл my-temp-file.txt создался во временной папке
    // и будет удален вместе с ней
  }
}

Класс TempFileManager создает временную папку…

Декларативный интерфейс

Posted in Программирование on Февраль 14th, 2009 by yallie – Be the first to comment

Декларативный интерфейсДля большинства небольших программ на WinForms отлично подходит дизайнер меню и панелей инструментов. Самый подходящий случай — это небольшая монолитная программка с более-менее фиксированным набором функций. Например, какой-нибудь простой текстовый редактор.

А самый неподходящий вариант — модульная программа, построенная на плагинах. Что если плагин должен иметь возможность добавлять команды в главное меню или кнопки на панель инструментов? Давать плагину доступ к меню небезопасно, поэтому обычно поступают наоборот: программа спрашивает у плагина, какие команды он поддерживает и сама добавляет их в свое меню. Для этого плагин должен поддерживать метод типа GetPluginCommands(), возвращающий коллекцию доступных команд.

В результате…

Exepack.NET, часть 3

Posted in Программирование on Февраль 7th, 2009 by yallie – Be the first to comment

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

Итак, упаковщик работает по такой схеме:

  1. Загружает главную исполняемую сборку (*.exe)
  2. Составляет список используемых библиотек классов (*.dll)
  3. Упаковывает все сборки, сохраняет во временные файлы
  4. Готовит исходник для загрузчика (loader.cs)
  5. Компилирует загрузчик, добавляя временные файлы как ресурсы
  6. Удаляет временные файлы

Список библиотек для упаковки, конечно, можно было бы задавать явно (например, в командной строке) . Но согласитесь, гораздо приятнее, если упаковщик сам его составит, тем более, что это сделать совсем несложно. Стандартный класс-обертка Assembly, который позволяет более-менее успешно манипулировать .NET-сборками, дает возможность получить список модулей, на которые ссылается загруженная сборка: Assembly.GetReferencedAssemblies().

Повторяя этот процесс рекурсивно, мы получим…

Exepack.NET, часть 2

Posted in Программирование on Январь 31st, 2009 by yallie – Be the first to comment

Программа app.exe в дизассемблере ILDASM

Попробуем усложнить задачу. Возьмем какое-нибудь реальное .NET-приложение, которое состоит из нескольких сборок. Как правило, это один EXE-файл и несколько дополнительных DLL-библиотек.

Модули (файлы *.netmodule) я рассматривать не буду, никогда не видел, чтобы ими кто-то пользовался. Я могу ошибаться, но по-моему, в Visual Studio нет для них полноценной поддержки: проекты компилируются в монолитные сборки, а не в набор модулей. Теоретически, конечно, это может быть реализовано по-разному на разных платформах, но я пока не ставил себе цели написать полностью переносимый EXE-упаковщик.

Чтобы не искать готовое приложение, я за минуту написал небольшую программку из двух файлов: app.cs и applib.cs. На картинке показано, как такая программа выглядит в дизассемблере ILDASM (красным выделена ссылка на сборку-библиотеку).

Теперь я модифицирую загрузчик так, чтобы он мог…

Exepack.NET, часть 1

Posted in Программирование on Январь 24th, 2009 by yallie – 1 Comment

Концепция загрузчикаДавно мечтал написать exe-packer — упаковщик для исполняемых файлов. Дурацкая мечта, прямо скажем, но у меня в запасе еще много таких.

Как недавно мне удалось выяснить, написать такой упаковщик для .NET-программ можно за три часа. Наверное, можно и быстрее, но у меня получилось за три с копейками. Это такая приятная особенность .NET: почти все уже сделано до нас.

А сделано до нас вот что:…