Создание инсталлятора службы

Прежде, чем можно будет инсталлировать службу на определенной машине, следует ввести дополнительный тип инсталлятора к текущему проекту CarWinService. В частности, любая служба Windows (написанная на. NET или Win32 API) требует нескольких записей в реестре для того, чтобы позволить операционной системе взаимодействовать с ней. Вместо того чтобы создавать эти записи вручную, можно просто добавить инсталлятор к проекту службы Windows, который корректно сконфигурирует сервис (службу) после установке его на целевой машине.

Чтобы добавить инсталлятор к проекту CarService, откройте в окне Solution Explorer редактор служб (двойным щелчком на файле CarService.cs), после этого щелкните правой клавишей мыши в любом месте дизайнера инсталлятора и выберите в контекстном меню (см. рис.2) пункт Add Installer (Добавить Инсталлятор).

В результате этих операций в проект сервиса будет добавлен новый элемент инсталлятора, унаследованного от базового класса System.Configuration.Install.Installer. В конструкторе инсталлятора будет находится два компонента. Один из них имеет тип serviceInstaller1 и представляет собой инсталлятор конкретной службы в проекте. Если курсором мыши выбрать эту пиктограмму и заглянуть в окно его свойств (Properties), то обнаружится, что свойство ServiceName было установлено в тип класса службы - CarService.

Второй компонент (serviceProcessInstaller1) позволяет установить идентичность (имя, идентификатор), под которой будет выполняться инсталлированная служба. По умолчанию свойство Account установлено в User. Используя окно Properties среды Visual Studio, измените это значение на LocalService (рис.4).

Рис. 4. Установка идентичности для CarService.

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

1.6. Инсталляция службы CarService

Инсталляция CarService.exe на определенной машине (локальной или удаленной) требует выполнения двух шагов.

1. Перенос готовой сборки службы (и всех необходимых ей внешних сборок; в данном примере — CarGeneralAsm.dll) на удаленную машину.

2. Запуск инструмента командной строки installutil.exe с указанием службы в качестве аргумента. (Эту утилиту можно найти, например, в каталоге: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727)

Если первый шаг выполнен, откройте командное окно Visual Studio, перейдите к месту нахождения сборки CarWinService.exe и выполните следующую команду

installutil carwinservice.exe

Обратите внимание, что тот же инструмент может применяться и для деинсталляции службы, но уже с указанием аргумента /u, например, installutil /u carwinservice.exe). Проще всего это сделать, если разместить файлы CarGeneralAsm.dll, carwinservice.exe и installutil.exe в корне каталога, например, каталога d:\.

Как только служба Windows установлена, то можно запускать и конфигурировать ее в аплете Services (Службы) панели управления. Найдя CarService (рис.5), щелкните на ссылке Start (Запуск) для загрузки и запуска программы службы.

Рис.5. Аплет Services

То же самое можно сделать из среды Visual Studio в меню "Вид" выбрать пункт "Обозреватель серверов", в котором открыть папку "Серверы", а внутри нее – "Службы". Если установка службы прошла успешно, то в папке служб вы найдете свою службу " CarService " (рис.5). Если подвести курсор к папке "Службы" и нажать на правую клавишу мыши, то появиться то же самое окно для загрузки и запуска служб, показанное на рис.5.

Рис.5. Окно Visual Studio для просмотра служб, установленных на вашем компьютере.

В результате запуска сервиса CarService мы получаем службу, которая способна выполнять роль полноправного заменителя сервера удаленного объекта, не требующего запуска самого сервера в виде отдельного приложения (хоста).

1.5. Создание консольного приложения клиента.

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

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

//using System.Runtime.Remoting.Channels.Http;

using System.Runtime.Remoting.Channels.Tcp;

using CarGeneralAsm;

using System.Collections.Generic;

namespace CarClient

{

class CarClient

{

static bool rad = false;//Переменная о вкл.\выкл. состоянии радиоприемника

//Статическая функцияпо выводу данных об автомобиле

private static void UseCar(JamesBondCar c)

{

Console.WriteLine("-> Имя: {0}", c.PetName);

Console.WriteLine("-> Максимальная скорость: {0}", c.MaxSpeed);

Console.WriteLine("-> Может двигаться под водой?: {0}",

c.GetSubmerge());

Console.WriteLine("-> Может летать?: {0}", c.GetFly());

Console.WriteLine();

c.TurnOnRadio(rad);

rad =!rad;

}

static void Main(string[] args)

{

Console.WriteLine("Клиент стартовал! Для продолжения нажмите на

клавишу ENTER");

// Конфигурирование клиента с помощью файла конфигурации

// RemotingConfiguration.Configure("CarProviderClient.exe.config", false);

TcpChannel c = new TcpChannel(); // Создание канала

ChannelServices.RegisterChannel(c, false);// Регистрация канала

// Получение ссылки на прокси удаленного объекта

object remoteObj = Activator.GetObject(typeof (CarGeneralAsm.CarProvider),

"tcp://localhost:32469/CarProvider.rem");

// Приведение ссылки на прокси к типу удаленного объекта.

CarProvider cp = (CarProvider)remoteObj;

// Получить автомобиль, стоящий первым в списке.

JamesBondCar qCar = cp.GetJBCByIndex(0);

// Получить весь список автомобилей.

List<JamesBondCar> allJBCs = cp.GetAllAutos();

// Вывести на экран информацию о первом автомобиле.

UseCar(qCar);

// Вывести на экран информацию обо всех автомобилях в списке

foreach (JamesBondCar j in allJBCs)

UseCar(j);

Console.ReadLine();

}

}

}

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

Внешний вид работающего приложения клиента показан на рис.6.

Рис.6. Внешний консольного приложения клиента под управлением службы CarSrvice для доступа к удаленному объекту поставщика автомобилей.

1.6. Создание Windows приложения клиента

В данном примере используется уже имеющаяся сборка библиотеки класса CarProvider и Windows-служба CarService, созданные для консольного приложения. Таким образом, все необходимые изменения касаются только модификации приложения клиента. Основной особенностью данного примера Windows приложения клиента заключается не только в изменении его внешнего вида, но и в иллюстрации возможности использования делегата при обращении к одному из методов удаленного объекта. Вот его программный код:

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

//using System.Runtime.Remoting.Channels.Http;

using System.Runtime.Remoting.Channels.Tcp;

using CarGeneralAsm;

using System.Collections.Generic;

namespace AsyncWKOCarProviderClient

{

public partial class Form2: Form

{

// Обявление типа делегата, задающего сигнатуру функций, с которыми он будет

// работать

internal delegate List<JamesBondCar> GetAllAutosDelegate();

GetAllAutosDelegate CarDelegate = null; // Переменная типа делегата (сам делегат)

// Ссылка на список автомобилей для их отображения на форме приложения клиента

List<JamesBondCar> allJBCs=null;

CarProvider cp = null; // Ссылка на удаленный объект (прокси)

public Form2()

{

InitializeComponent();

//Создание прокси удаленного поставщика

object remoteObj = Activator.GetObject(typeof(CarGeneralAsm.CarProvider),

"tcp://localhost:32469/CarProvider.rem");

cp = (CarProvider)remoteObj; // Инициализация ссылки на удаленный объект (прокси)

//Создание объекта делегата (иницииализация ссылки на объект делегата)

CarDelegate = new GetAllAutosDelegate(cp.GetAllAutos);

}

//Метод для вызова делегата

void CallDelegate()

{

//Асинхронный вызов делегата

IAsyncResult ar = CarDelegate.BeginInvoke(null, null);

if (ar == null)

{

MessageBox.Show("Делегат не хочет вызываться!!!");

return;

}

MessageBox.Show("Удаленный объект заполняет список.");

//Работа делегата (то есть работа метода, включенного в делегат)

while (!ar.IsCompleted) { } // Пока делегат не закончит свою работу, ждем…

allJBCs = CarDelegate.EndInvoke(ar);//Делегат возвращает список автомобилей

string str = "Удаленный объект заполнил весь список! Всего: ";

str += allJBCs.Count.ToString();

str += " Машин";

MessageBox.Show(str);// Отображаем строку str в виде окна с сообщением

}

// Обработчик события при нажатии на клавишу "Добавить автомобиль…"

private void AddCarButton_Click(object sender, EventArgs e)

{

if (cp == null) // если нет ссылки на удаленный объект, то (защита от "дурака")

{

// Получаем ссылку на удаленный объект (его прокси)

object remoteObj = Activator.GetObject(typeof(CarGeneralAsm.CarProvider),

"tcp://localhost:32469/CarProvider.rem");

cp = (CarProvider)remoteObj;

}

if (cp == null) return; //Если ссылки – нет, то выходим из функции

// Добавляем новый автомобиль в список их поставщика на удаленном объекте

cp.AddNewJBCar(NameTextBox.Text, int.Parse(SpeedTextBox.Text),

FlyCheckBox.Checked, SweemCheckBox.Checked);

}

// Обработчик события при нажатии на клавишу "Заполнить список на форме клиента"

private void FillListButton_Click(object sender, EventArgs e)

{

CallDelegate();// Вызов делегата (содержащего соотв. метод удаленного объекта)

List<string> carNames = new List<string>();// Вспомогательный список строк

string str = ""; // Служебная (локальная) переменная типа строки

foreach (JamesBondCar car in allJBCs)// Формирование вспомогательного списка строк

{

str = car.PetName;

str += " Макс.скорость = ";

str += (car.MaxSpeed.ToString()+"; ");

if (car.CanFly) str += "Может летать! ";

else str += "Не может летать. ";

if (car.CanSubmerge) str += "Может плавать!";

else str += "Не может плавать.";

carNames.Add(str);

}

//Связывание вспомогательного списка с содержимым компоненты списка

listBox1.DataSource = carNames;

}

}

}

После компиляции и запуске приложения клиента и включенной службе CarService для хостинга (владения) удаленных объектов типа CarProvider получим приложение способное взаимодействовать с зарегистрированным удаленным объектом. Его внешний вид показан на рис.7.

Рис.7. Внешний вид запущенного Windows приложения клиента.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: