Показаны сообщения с ярлыком Windows Service. Показать все сообщения
Показаны сообщения с ярлыком Windows Service. Показать все сообщения

четверг, 4 июля 2013 г.

Размещение WCF библиотеки в службе Windows.

В этой статье хочу рассказать как правильно разместить службу WCF (Windows Communication Foundation) в службе Windows 7.

Создадим новый проект WCF Service Library.

В Solution Explorer находим файл app.config, нажимаем на нем правой кнопкой и выбираем Edit WCF Configuration.

Переходим к пункту Host. Выбираем базовый адрес и нажимаем кнопку "Edit"

И вписываем адрес: net.tcp://localhost:8732/Service1/

Должно выглядеть вот так:

На пункте Binding нажимаем правую кнопку и выбираем New Binding Configuration

Далее выбираем netTcpBinding


Переходим к пункту serviceMetadata и меняем значение HttpGetEnabled на False.

Переходим к пункту Service Endpoint и меняет Binding на netTcpBinding


В BindingConfiguration ставим NewBinding0

Переходим ко второму пункту (Empty Name) и в Binding указываем mexTcpBinding

На этом настройка конфигурации закончена. Нажимаем File - Save.

В проект добавляем службу Windows.

На дизайнере службы нажимаем правую кнопку и добавляем установщик (Add Installer).
 

Выбираем появившийся serviceProcessInstaller1 и меняет Account с User на LocalSystem

Добавляем в проект WindowsService1 ссылку на проект WcfLibraryService (Add reference)
Выбираем serviceInstaller1, переключаемся на вкладку событий, и дважды щелкаем по событию AfterInstall.

Переходим к коду, добавляем using System.Management;
В процедуру serviceInstaller1_AfterInstall вписываем следующий код:

Code Snippet
  1. private void serviceInstaller1_AfterInstall(object sender, InstallEventArgs e)
  2. {
  3.     ConnectionOptions coOptions = new ConnectionOptions();
  4.     coOptions.Impersonation = ImpersonationLevel.Impersonate;
  5.  
  6.     ManagementScope mgmtScope = new System.Management.ManagementScope(@"root\CIMV2", coOptions);
  7.     mgmtScope.Connect();
  8.  
  9.     using (ManagementObject wmiService = new ManagementObject("Win32_Service.Name='" + serviceInstaller1.ServiceName + "'"))
  10.     {
  11.         ManagementBaseObject InParam = wmiService.GetMethodParameters("Change");
  12.         InParam["DesktopInteract"] = true;
  13.         wmiService.InvokeMethod("Change", InParam, null);
  14.     }
  15. }

Это действие позволит службе взаимодействовать с рабочим столом пользователя.
Хотя в Windows 7 это уже не актуально. И только добавляем больше проблем.

Весь код файла выглядит так:

Code Snippet
  1. using System.ComponentModel;
  2. using System.Configuration.Install;
  3. using System.Management;
  4.  
  5.  
  6. namespace WindowsService1
  7. {
  8.     [RunInstaller(true)]
  9.     public partial class ProjectInstaller : System.Configuration.Install.Installer
  10.     {
  11.         public ProjectInstaller()
  12.         {
  13.             InitializeComponent();
  14.         }
  15.  
  16.         private void serviceInstaller1_AfterInstall(object sender, InstallEventArgs e)
  17.         {
  18.             ConnectionOptions coOptions = new ConnectionOptions();
  19.             coOptions.Impersonation = ImpersonationLevel.Impersonate;
  20.  
  21.             ManagementScope mgmtScope = new System.Management.ManagementScope(@"root\CIMV2", coOptions);
  22.             mgmtScope.Connect();
  23.  
  24.             using (ManagementObject wmiService = new ManagementObject("Win32_Service.Name='" + serviceInstaller1.ServiceName + "'"))
  25.             {
  26.                 ManagementBaseObject InParam = wmiService.GetMethodParameters("Change");
  27.                 InParam["DesktopInteract"] = true;
  28.                 wmiService.InvokeMethod("Change", InParam, null);
  29.             }
  30.         }
  31.     }
  32. }

В свойствах проекта WcfServiceLibrary на последней вкладке снимаем галочку Start WCF Service Host.

Копируем файл app.config в проекте WcfServiceLibrary

Этот файл нужно вставить в проект WindowsService

Идея такая, что файл app.config должен быть одинаковый в этих двух проектах.
Потому что служба WCF будет вызываться из службы Windows, то в проекте службы Windows должны находиться параметры WCF службы. Эти параметры служба Windows (WindowsService1) не может достать из файла app.config проекта WcfServiceLibrary.

В проекте WindowsService1 на файле Service1 нажимаем правой кнопкой и выбираем View Code


Добавляем ссылку на сборку System.ServiceModel;
И в коде вписываем using System.ServiceModel;

В процедуре OnStart вписываем код:

Code Snippet
  1. protected override void OnStart(string[] args)
  2. {
  3.     if (myServiceHost != null)
  4.     {
  5.         if (myServiceHost.State == CommunicationState.Opened) myServiceHost.Close();
  6.     }
  7.  
  8.     try
  9.     {
  10.         myServiceHost = new ServiceHost(typeof(WcfServiceLibrary1.Service1));
  11.         myServiceHost.Open();
  12.     }
  13.     catch (Exception ex)
  14.     {
  15.         EventLog.WriteEntry(this.ServiceName, ex.Message);
  16.     }
  17. }

Это позволит службе Windows при запуске запустить хостинг WCF службы
В процедуре OnStop вписываем код:

Code Snippet
  1. protected override void OnStop()
  2. {
  3.     if (myServiceHost != null)
  4.     {
  5.         myServiceHost.Close();
  6.         myServiceHost = null;
  7.     }
  8. }

В итоге общий код файла выглядит так:

Code Snippet
  1. using System;
  2. using System.Diagnostics;
  3. using System.ServiceProcess;
  4. using System.ServiceModel;
  5.  
  6. namespace WindowsService1
  7. {
  8.     public partial class Service1 : ServiceBase
  9.     {
  10.         public Service1()
  11.         {
  12.             InitializeComponent();
  13.         }
  14.         private static ServiceHost myServiceHost = null;
  15.  
  16.         protected override void OnStart(string[] args)
  17.         {
  18.             if (myServiceHost != null)
  19.             {
  20.                 if (myServiceHost.State == CommunicationState.Opened) myServiceHost.Close();
  21.             }
  22.  
  23.             try
  24.             {
  25.                 myServiceHost = new ServiceHost(typeof(WcfServiceLibrary1.Service1));
  26.                 myServiceHost.Open();
  27.             }
  28.             catch (Exception ex)
  29.             {
  30.                 EventLog.WriteEntry(this.ServiceName, ex.Message);
  31.             }
  32.         }
  33.  
  34.         protected override void OnStop()
  35.         {
  36.             if (myServiceHost != null)
  37.             {
  38.                 myServiceHost.Close();
  39.                 myServiceHost = null;
  40.             }
  41.         }
  42.     }
  43. }

Добавляем новый проект Windows Forms. И делаем его запускаемым по-умолчанию (Set as Startup project).
Кидаем на форму кнопку и добавляем ссылку на службу (Add Service Reference)
Нажимаем кнопку Discover и выбираем службу Service1


В обработчик нажатия на кнопку вписываем код:

Code Snippet
  1. private void button1_Click(object sender, EventArgs e)
  2. {
  3.     ServiceReference1.Service1Client myService = new ServiceReference1.Service1Client();
  4.     MessageBox.Show(myService.GetData(123), "My Service");
  5.     myService.Close();
  6. }

Весь файл должен выглядеть так:

Code Snippet
  1. using System;
  2. using System.Windows.Forms;
  3.  
  4. namespace WindowsFormsApplication1
  5. {
  6.     public partial class Form1 : Form
  7.     {
  8.         public Form1()
  9.         {
  10.             InitializeComponent();
  11.         }
  12.  
  13.         private void button1_Click(object sender, EventArgs e)
  14.         {
  15.             ServiceReference1.Service1Client myService = new ServiceReference1.Service1Client();
  16.             MessageBox.Show(myService.GetData(123), "My Service");
  17.             myService.Close();
  18.         }
  19.     }
  20. }

Нажимаем F6 - для компиляции проекта. Ошибок быть не должно.
Открываем папку проекта WindowsService1


В эту папку нужно скопировать файл InstallUtil.exe
Чтобы его найти на вашем компьютере воспользуйтесь поиском.

Создадим файл InstallServiceAndStart.bat со следующим текстом:
InstallUtil.exe WindowsService1.exe
net start Service1

Создадим файл UninstallServiceAndStop.bat со следующим текстом:
net stop Service1
InstallUtil.exe /u WindowsService1.exe

В итоге папка должна выглядеть так:

Если вы используете Windows XP то для запуска/удаления службы можно пользоваться этими BAT файлами. Если же Windows 7 - то нужно сделать так:
В меню найдите пункт Microsoft Visual Studio 2010\Visual Studio tools

В этой папке есть "Open Visual Studio Command Prompt (2010)", нажмите на нем правой кнопкой мыши и выберите "Запуск от имени Администратора". Отобразится та же консоль.
Поменяйте текущую папку.

Для установки и запуска службы скопируйте содержимое файла InstallServiceAndStart.bat и вставьте в это окно и нажмите Enter (для Windows 7). Если в Windows 7 запускать файлы, то после каждого удаления службы Windows придется перезагружать компьютер.
Если у вас Windows XP то можно просто запускать батники.


Служба установлена и запущена.
Теперь нужно запустить приложение WindowsFormsApplication1. Возможно что Visual Studio не позволит запустить отладку, т.к.он не сможет заменить файл WindowsService1.exe потому, что он будет выполняться ОС. Я просто открыл папку и запустил WindowsFormsApplication1.exe


Нажимаем кнопку и через несколько секунд получаем сообщение


Это говорит о том, что наша служба Windows работает.
Если в службу вносите изменения то нужно произвести удаление службы.
Для этого в Windows XP просто запустите UninstallServiceAndStop.bat в Windows 7 нужно найти пункт Microsoft Visual Studio 2010\Visual Studio tools

В этой папке есть "Open Visual Studio Command Prompt (2010)", нажмите на нем правой кнопкой мыши и выберите "Запуск от имени Администратора". Поменяйте текущую папку на папку с файлом WindowsService1.exe. Скопируйте текст из файла 

воскресенье, 20 февраля 2011 г.

Visual Studio 2010 - создание службы Windows шаг за шагом

Чтобы написать службу, необходим определенный опыт программирования.
Однако мои инструкции помогут даже новичкам.

1.Открываем Visual Studio, создаем проект Windows Service.

2. На экране окажется пустой дизайнер. Переключимся в режим кода. Нажмем для этого правой кнопкой мыши и выберем View Code.

3. Окно уже будет содержать два обработчика события: OnStart и OnStop. Первый выполняется при запуске службы, второй при остановке. Также можно использовать другие обработчики событий: при выключении, при изменении статуса питания (для ноутбуков), пауза и восстановление и возможен перехват сессии.

4. В блок USING добавим ссылку на System.Threading.

5. Создадим новую процедуру которая будет выполняться при запуске службы. Назовем её MyProcess.

6. Необходимость в этом объясняется тем, что на каждое действие службы не должно уходить более 30сек даже не самом медленном компьютере. Поэтому я рекомендую в обработчике запуска службы создавать только новый поток и запускать его на выполнение. Все функциональность вкладывать в новый поток.

7. Напишем процедуру, которую будем выполнять в другом потоке. Например: Я хочу чтобы при старте сервис загружал RSS с lenta.ru и отображал его в гриде в окне.

8. Добавляем в службу Windows Form.


9. Кладем на форму DataGridView, устанавливаем свойство Anchor в Top, Bottom, Left, Right.


10. Устанавливаем у компонента DataGridView свойство Modifiers = Public.

11. Переходим в редактор кода службы и пишем следующий код:


12. Дописываем обработчик OnStart()


13. Переходим на дизайнер службы. Добавляем инсталер.


14. Выделяем ServiceProcessInstaller и меняем Account с User на LocalSystem


15. Значния ServiceInstaller ставим как на рисунке



16. Наша служба почти готова. С помощью ServiceProcessInstaller служба будет устанавливаться в систему. После этого она появится с списке служб.

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


18. Сделаем это программно. Снова выделяем ServiceProcessInstaller, переходим к событиям. Находим там Commited и создаем для него обработчик события.


19. Добавим ссылку using System.Management;

20. Напишем следующий код:


21. Обратите внимание, я пробовал использовать прямой редактор реестра. Этот код закомментирован. Он не работает. Не используйте его. Вместо этого используйте ManagementObjectSearcher как показано выше

22. Собираем решение. F6.

23. Открываем папку с фрамеворком. Копируем оттуда файл InstalUtil.exe в папку с вашей службой.


24. Создаем пустой текстовый файл. Заполняем его следующим текстом:
InstallUtil.exe WindowsService1.exe

25. Сохраняем под именем Install.bat. (Чтобы можно было назначить тип файла, в свойствах папки должна стоять галочка, отображать имена для зарегистрированных типов файлов).

26. Создаем ещё один текстовый файл. Заполняем его следующим текстом:
InstallUtil.exe /U WindowsService1.exe

27. Сохраняем под именем Uninstall.bat.

28. Создаем ещё один текстовый файл. Заполняем его следующим текстом:
net start MyRSS

29. Сохраняем под именем Start.bat.

30. Создаем ещё один текстовый файл. Заполняем его следующим текстом:
net stop MyRSS

31. Сохраняем под именем Stop.bat.

32. Запускаем Install.bat
33. Запускаем Start.bat

34. Через опр.время должна появиться форма: