Удобная отладка Windows служб

Отладка Windows Service приложений не такая тривиальная задача как кажется. Проблема в том, что при отладке этого типа приложений нельзя воспользоваться стандартными средствами Visual Studio такими как точки останова (breakpoints) и прочими полезными инструментами. Всё из-за того, что Windows Service приложение не может быть зыпущено по F5 прямо из Visual Studio. Всё же, MSDN предлагает нам несколько способов для их отладки. Скорее всего многие разработчики даже и не сталкивались с ними до тех пор, пока не стали создавать свою первую службу. Это использование записей в журнал событий и подключение к процессу. Оба этих метода хорошо описаны в MSDN, но они позволяют произовдить отладку только уже запущенной службы. Из-за этого код, который производит сам запуск службы, в методе OnStart(), нельзя протестировать.

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

Сначала нам нужно создать новый проект. Назовем его TestWinService.

image

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

image

Теперь добавим к нашему решению консольный проект, из которого мы, собственно, и будем производить отладку нашей службы. Сразу после создания нового проекта добавим к нему две ссылки. Одна на нашу службу, TestWinService, другая на System.ServiceProcess необходимую для вызова сервиса.

image

Теперь начинается самое интересное. Чтобы отладить код запускающий службу, нам нужно будет создать новый поток, который и будет делать всю необходимую работу. А также два метода – Start() и Stop() для его запуска и завершения. И, соответственно, вызовем их в методах включения и выключения службы. В итоге у нас получится что-то вроде этого.

image

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

image

Все готово! Остается только нажать F5 и убедиться, что отладчик остановился на тестовой строке.

image

С помощью этого метода отладка служб становится ничем не труднее отладки обычного консольного приложения. Надеюсь это кому-нибудь пригодиться.

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 13

    +2
    Спасибо! Мне очень пригодится, а то я все по старинке:
    Debugger.Launch();
    и
    if(Debugegr.Attached)
    Debugger.Break();
      +1
      Если задача состоит только в том чтоб отловить метод старт, то можно принудительно вызвать отладчик методом System.Diagnostics.Debugger.Break();
        +1
        Тут главная идея — это отлаживать службу как обычное приложение.
        +3
        Всегда пользовался следующим методом (и не надо изобретать консольное приложение):
        В коде сервиса:
        public void Start()
        {
        // Тут логика инициализации
        }

        protected override void OnStart(string[] args)
        {
        Start();
        }

        В коде Program (опущу обработку исключений):
        static void Main(string[] args)
        {
        if (Environment.UserInteractive)
        {
        #if DEBUG
        (new MySvc()).Start();
        Thread.Sleep(Timeout.Infinite);
        #else
        MessageBox.Show("Приложение должно быть установлено в виде службы Windows и не может быть запущено интерактивно.");
        #endif
        }
        else
        {
        ServiceBase.Run(new MySvc());
        }
        }


        Минус один — OnStop() таким образом отладить сложнее, но тоже решается.
          0
          Интересный способ. Спасибо, возьму на заметку.
          0
          Способ достаточно старый и проверенный, но… На мой взгляд главная идея OnStart должна быть в передаче управления сборке с логикой, которая в свою очередь должна быть покрыта тестами. Кроме того, иногда необходимо протестировать с правами под которыми была установлена служба. Поэтому мой выбор System.Diagnostics.Debugger.Break(), а Environment.UserInteractive использую для автоматической установки сервиса.
            0
            Я обычно, если у меня есть вин служба, добавляю проект консольного приложения, которое по функциональной логике представляет собой точный аналог вин-службы. В общем случае в вин-службе вызывается только один метод при старте, скажем, DoSomething(). Таким образом, что мешает вызвать этот же метод из консольного приложения, и для тестирования и отладки использовать именно его.
            Так как вообще сам по себе проект вин службы не должен содержать какой-либо логике, единственное, что он должен сделать — это загрузить и вызвать какой-то внешний компонент.
              +1
              Некоторые вещи не получится дебажить таким образом.
              К примеру функций, которые используют привилегии пользователя System.
              Еще время запуска и остановки сервисов необходимо тестить в реальных условиях, ибо система может прибить сервис если он долго будет загружаться/выгружаться.
              Да много еще ньюансов.
              Конечно иметь возможность запускать сервис как консоль это очень полезно, но нужно уметь обходится и без этого.
              Иногда спасает Sleep на старте сервиса, но иногда приходится подтягивать тяжелую артиллерию, а именно — ядерный отладчик.

                0
                делаю нечто похожее

                if (args.Any(s => s.Equals("/console", StringComparison.InvariantCultureIgnoreCase)))
                {
                //запуск сервиса как консольное приложение
                }
                else if (args.Any(s => s.Equals("/i", StringComparison.InvariantCultureIgnoreCase)))
                {
                //инсталляция сервиса
                }
                else if (args.Any(s => s.Equals("/u", StringComparison.InvariantCultureIgnoreCase)))
                {
                //удаление сервиса
                }
                else if (args.Any(s => s.Equals("/help", StringComparison.InvariantCultureIgnoreCase)))
                {
                //список возможных команд
                }
                else
                {
                //запуск сервиса
                }


                преимущество, в том что приложение может использоваться как консольное, а так же как и сервис + привычная отладка
                +1
                Действительно, зачем городить огород, а не использовать обычный «int 3», в сишарпах — Debugger.Break()?
                  +2
                  Есть еще один вариант отладки сервиса, без добавления Debugger.Break/Launch — указание отладчика в Image File Execution Options.
                    0
                    Иногда нормально отладить сервис можно только при помощи ядерного отладчика (WinDBG).
                    К примеру надо отдалить запуск сервиса в автозагрузке, или наоборот его остановку в момент остановки системы…
                      0
                      Кому интересно, есть отличный проект Topshelf: topshelf-project.com/
                      Позволяет стартовать сервис как консольное приложение, так и в виде windows service, предоствляю удобный механизм установки и запуска. Плюс поддерживает горячую замену кода сервиса, а также работает с Mono.

                      Only users with full accounts can post comments. Log in, please.