воскресенье, 24 июня 2012 г.

Служба Windows, часть 2

Ладно, шаблон службы есть. Теперь нужно этой службой как - то управлять. На вскидку, делать это можно двумя путями: через файл конфигурации или внешним менеджером.

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


string catalog = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;



    Теперь второй вопрос - как подключиться к службе?
    Я решил не париться и использовать для связи WCF сервис. Служба используется как хостинг для WCF, а WCF  обеспечивает связь между службой и внешней программой. В коде все выглядит достаточно просто.

    Создаем Основной класс службы, вокруг которого будет наращиваться весь функционал. Пусть его зовут

                                                BaseClass

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



class ManagerControlService
    {
        private static ManagerControlService _ManagerControlService;
        private ServiceHost SvHost;


        public static ManagerControlService Service
        {
            get
            {
                _ManagerControlService = _ManagerControlService ?? new ManagerControlService();
                return _ManagerControlService;
            }
        }



        //конструктор
        private ManagerControlService()
        {
            BaseClass base_class = new BaseClass();
            WSHttpBinding myBinding = new WSHttpBinding();
            myBinding.Security.Mode = SecurityMode.None;
            Uri baseAddress = new Uri("http://localhost:8193/load_data_nt_service/Service"); //создается базовый адрес
            ControlService singleton = new ControlService(base_class);

            //SvHost = new ServiceHost(typeof(ControlService), baseAddress);
            SvHost = new ServiceHost(singleton, baseAddress);
            SvHost.AddServiceEndpoint(typeof(IControlService), myBinding, "ControlService");
            ServiceMetadataBehavior smb = new ServiceMetadataBehavior();  //создается бихэвиор
            smb.HttpGetEnabled = true;
            SvHost.Description.Behaviors.Add(smb);
            //ControlService obj = (ControlService)SvHost.SingletonInstance;

        }


        public void Start()
        {
            SvHost.Open();
        }

        public void Stop()
        {
            SvHost.Close();
        }

    }




И сам класс службы.


[ServiceContract] //указывается что это контракт и заодно указывается пространство имен
    public interface IControlService
    {
        [OperationContract]
        string CheckService();

 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    class ControlService : IControlService
    {
         static BaseClass base_class;
             

         public ControlService(BaseClass obj)
         {
             base_class = obj;
        
         }

        public string CheckService()
        {
            /*OperationContext context = OperationContext.Current;
            MessageProperties messageProperties = context.IncomingMessageProperties;

            RemoteEndpointMessageProperty endpointProperty =messageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;

            return "сервис работоспособен"+endpointProperty.Address;*/
            return "сервис работоспособен";
        }
}

В принципе, все это уже разбиралось раньше, но есть небольшие нюансы.
Во первых, в коде, описывающем хостинг, мы создаем объект класса BaseClass ещё до того, как создаем WCF службу

                                  BaseClass base_class = new BaseClass();

Это нужно для того, чтобы этот класс не зависел от WCF сервиса. Затем передаем в WCF сервис ссылку на этот объект.
                                 ControlService singleton = new ControlService(base_class);
 А сам WCF сервис создаем по шаблону singleton, чтобы не было вопросов по взаимодействию нескольких потоков с основным рабочим.


    Собственно, это и все. У организованной таким образом службы работают два потока: BaseClass, реализующий функционал и WCF сервис, который может обращаться к методам базового класса и позволяет управлять им из внешней программы.

Похожие посты:

1 комментарий:

  1. Я так понимаю, BaseClass - это класс Service1 из первой части статьи?

    ОтветитьУдалить