Требуется ли службе .NET Windows вызов ServiceBase.Run()

#c# #.net-3.5 #windows-services

#c# #.net-3.5 #windows-services

Вопрос:

Я довольно новичок в работе со службами Windows, но я обнаружил необычный инцидент и хотел бы получить некоторые разъяснения. У меня есть служба Windows, написанная на C #, которую я устанавливаю и запускаю с помощью командной строки (отличные инструкции можно найти в stackoverflow). Основной метод моего сервиса выглядит следующим образом:

     static void Main(string[] args)
    {
        if (args.Length == 0)
        {
            ServiceBase.Run(new MyServiceName());
        }
        else if (args.Length == 1)
        {
            const string name = "MyServiceName";
            Type type = typeof(MyAssembly);
            switch (args[0])
            {
                case "-install":
                    ServiceUtils.InstallService(name, type);
                    ServiceUtils.StartService(args, name);
                    break;
                case "-uninstall":
                    ServiceUtils.StopService(name);
                    ServiceUtils.UninstallService(name, type);
                    break;
                default:
                    throw new NotImplementedException();
            }
        }
    }
  

При отладке я ВСЕГДА отправляю один параметр (-install) приложению. Из-за этого первая инструкция if (if (args.Length == 0) НИКОГДА не выполняется. Это ожидаемо, и моя служба установлена и запущена просто отлично. Однако, если я удалю это выражение if и просто оставлю if (args.Length == 1) инструкцию, моя служба установится правильно, но не запустится, и я получу следующую ошибку:

Не удается запустить MyServiceName на компьютере ‘.’

Мой вопрос таков: Зачем нужен код в первом операторе if, если он НИКОГДА не выполняется в моем приложении?

Вот вспомогательный код для методов InstallService и startService (который я также получил из stackoverflow):

     public static void InstallService(string serviceName, Type t)
    {
        if (IsInstalled(serviceName)) return;

        try
        {
            Assembly a = t.Assembly;
            using (AssemblyInstaller installer = GetInstaller(a))
            {
                IDictionary state = new Hashtable();
                try
                {
                    installer.Install(state);
                    installer.Commit(state);
                }
                catch
                {
                    try
                    {
                        installer.Rollback(state);
                    }
                    catch
                    { }
                    throw;
                }
            }
        }
        catch
        {
            throw;
        }
    }

    public static void StartService(string[] args, string serviceName)
    {
        if (!IsInstalled(serviceName)) return;

        Console.WriteLine("Service is installed.  Attempting to start service.");

        ServiceController sc = new ServiceController();
        sc.ServiceName = serviceName;

        if (sc.Status == ServiceControllerStatus.Stopped)
        {
            Console.WriteLine("Starting {0}: ", sc.ServiceName);
            try
            {
                sc.Start(args);
                sc.WaitForStatus(ServiceControllerStatus.Running);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
  

Ответ №1:

первый оператор if (если (аргументы.Длина == 0) НИКОГДА не выполняется

Это неверно, оно выполняется. С помощью ServiceController.Start(). Вы не можете этого увидеть, потому что контроллер службы снова запускает ваш EXE-файл, создавая другой процесс. На этот раз это сервисный процесс, а не процесс консоли. Тот, к которому у вас нет подключенного отладчика. Если вы удалите это выражение if, то служба немедленно завершит работу после начала работы. И контроллер службы правильно жалуется на это сообщением об исключении «Не удается запустить MyServiceName».

Ответ №2:

 if (args.Length == 0)
{            
    ServiceBase.Run(new MyServiceName());
}
  

запускается, когда служба запускается контроллером службы, поскольку контроллер службы не передает никаких аргументов в Main().

Если вы этого не сделаете ServiceBase.Run(new MyServiceName()) , то ваша служба не будет отвечать ни на какие команды от контроллера службы, и вы получите ошибки, подобные тем, которые вы видите.

Комментарии:

1. На самом деле я запускаю ServiceController. Start() с помощью string[]. Для этого существует перегрузка. [ссылка] msdn.microsoft.com/en-us/library/9c38b683.aspx . Вы хотите сказать, что независимо от того, запускаю я свое приложение с параметром или нет, я всегда должен предоставлять точку входа в main с параметрами 0?

2. ДА. Вам нужно вызвать ServiceBase.Run() список служб в этом exe-файле, чтобы службы заработали, и вы не хотите вызывать его ни при каких других обстоятельствах.

Ответ №3:

Main() по-прежнему является точкой входа приложения. Процесс запускается как отдельный шаг после запуска службы (ов) внутри.

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