Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой статье показано, как создать приложение службы Windows для .NET Framework в Visual Studio. Служба просто записывает сообщения в журнал событий.
Замечание
Эта статья не относится к размещенным службам в .NET. Последние сведения об использовании Microsoft.Extensions.Hosting.BackgroundService служб Windows и шаблоне рабочей службы см. в следующих статье:
Создание сервиса
Чтобы начать, создайте проект и задайте значения, необходимые для правильной работы службы.
В меню "Файл Visual Studio" выберите новый>проект (или нажмите клавиши CTRL SHIFT++N), чтобы открыть окно "Новый проект".
Найдите и выберите шаблон проекта службы Windows (.NET Framework ).
Замечание
Если шаблон службы Windows не отображается, может потребоваться установить рабочую среду разработки настольных приложений .NET с помощью Visual Studio Installer.
В поле "Имя проекта" введите MyNewService и нажмите кнопку "Создать".
Откроется вкладка "Конструктор" (Service1.cs [конструктор] или Service1.vb [конструктор].
Шаблон проекта включает класс компонента с именем
Service1, наследуемым от System.ServiceProcess.ServiceBase. Он включает большую часть базового кода службы, например код для запуска службы.
Переименование службы
Переименуйте службу из Service1 в MyNewService.
В обозревателе решений выберите Service1.cs или Service1.vb и выберите "Переименовать " в контекстном меню. Переименуйте файл в MyNewService.cs или MyNewService.vb, а затем нажмите клавишу ВВОД.
Появится всплывающее окно с запросом на переименование всех ссылок на элемент Code Service1.
Во всплывающем окне нажмите кнопку "Да".
Выберите "Сохранить все" в меню "Файл ".
Добавление функций в службу
В этом разделе описано, как добавить настраиваемый журнал событий в службу Windows. Компонент EventLog является примером типа компонента, который можно добавить в службу Windows.
Добавление функций пользовательского журнала событий
В окне Toolbox раскройте группу Components и перетащите компонент EventLog в дизайнера Service1.cs [Design] или Service1.vb [Design].
Подсказка
Если окно панели элементов не отображается, выберите "Вид>панели элементов".
В обозревателе решений в контекстном меню для MyNewService.cs или MyNewService.vb выберите пункт "Просмотреть код".
Определите пользовательский журнал событий.
Для C# измените существующий
MyNewService()конструктор, как показано в следующем фрагменте кода. Для Visual Basic добавьтеNew()конструктор, как показано в следующем фрагменте кода.public MyNewService() { InitializeComponent(); eventLog1 = new EventLog(); if (!EventLog.SourceExists("MySource")) { EventLog.CreateEventSource("MySource", "MyNewLog"); } eventLog1.Source = "MySource"; eventLog1.Log = "MyNewLog"; }' To access the constructor in Visual Basic, select New from the ' method name drop-down list. Public Sub New() MyBase.New() InitializeComponent() Me.EventLog1 = New System.Diagnostics.EventLog If Not System.Diagnostics.EventLog.SourceExists("MySource") Then System.Diagnostics.EventLog.CreateEventSource("MySource", "MyNewLog") End If EventLog1.Source = "MySource" EventLog1.Log = "MyNewLog" End SubЕсли он еще не существует, добавьте директиву
usingв MyNewService.cs или операторImportsв MyNewService.vb для пространства имен System.Diagnostics:using System.Diagnostics;Imports System.DiagnosticsВыберите "Сохранить все" в меню "Файл ".
Определение того, что происходит при запуске службы
В редакторе кода для MyNewService.cs или MyNewService.vb найдите OnStart метод. Visual Studio автоматически создал пустое определение метода при создании проекта. Добавьте код, который записывает запись в журнал событий при запуске службы:
protected override void OnStart(string[] args)
{
eventLog1.WriteEntry("In OnStart.");
}
' To access the OnStart in Visual Basic, select OnStart from the
' method name drop-down list.
Protected Overrides Sub OnStart(ByVal args() As String)
EventLog1.WriteEntry("In OnStart")
End Sub
Голосование
Так как служебное приложение предназначено для длительного выполнения, обычно оно опрашивает или отслеживает систему, которую вы настраиваете в методе OnStart. Метод OnStart должен вернуться в операционную систему после начала операции службы, чтобы система не была заблокирована.
Чтобы настроить простой механизм опроса, используйте System.Timers.Timer компонент. Таймер инициирует событие Elapsed через регулярные интервалы, в тот момент ваша служба может выполнять мониторинг. Вы используете компонент Timer следующим образом:
- Задайте свойства Timer компонента в методе
MyNewService.OnStart. - Запустите таймер, вызвав Start метод.
Настройка механизма опроса
usingДобавьте директиву в MyNewService.cs илиImportsинструкцию в MyNewService.vb для этого пространства имен:using System.Timers;Imports System.TimersДобавьте следующий код в
MyNewService.OnStartсобытие, чтобы настроить механизм опроса:// Set up a timer that triggers every minute. Timer timer = new Timer { Interval = 60000 // 60 seconds }; timer.Elapsed += new ElapsedEventHandler(this.OnTimer); timer.Start();' Set up a timer that triggers every minute. Dim timer As Timer = New Timer() timer.Interval = 60000 ' 60 seconds AddHandler timer.Elapsed, AddressOf Me.OnTimer timer.Start()MyNewServiceВ классе добавьте переменную-член. Он содержит идентификатор следующего события для записи в журнал событий:private int eventId = 1;Private eventId As Integer = 1MyNewServiceВ классе добавьтеOnTimerметод для обработки Timer.Elapsed события:public void OnTimer(object sender, ElapsedEventArgs args) { // TODO: Insert monitoring activities here. eventLog1.WriteEntry("Monitoring the System", EventLogEntryType.Information, eventId++); }Private Sub OnTimer(sender As Object, e As Timers.ElapsedEventArgs) ' TODO: Insert monitoring activities here. eventLog1.WriteEntry("Monitoring the System", EventLogEntryType.Information, eventId) eventId = eventId + 1 End Sub
Вместо выполнения всей работы в основном потоке можно выполнять задачи с помощью фоновых рабочих потоков. Дополнительные сведения см. в разделе System.ComponentModel.BackgroundWorker.
Определение того, что происходит при остановке службы
Вставьте строку кода в метод, который добавляет запись в OnStop журнал событий при остановке службы:
protected override void OnStop()
{
eventLog1.WriteEntry("In OnStop.");
}
Protected Overrides Sub OnStop()
EventLog1.WriteEntry("In OnStop.")
End Sub
Определите другие действия для службы
Можно переопределить методы OnPause, OnContinue и OnShutdown, чтобы определить дополнительную обработку для вашего компонента.
В следующем коде показано, как переопределить OnContinue метод в MyNewService классе:
protected override void OnContinue()
{
eventLog1.WriteEntry("In OnContinue.");
}
Protected Overrides Sub OnContinue()
EventLog1.WriteEntry("In OnContinue.")
End Sub
Настройка состояния службы
Службы сообщают о состоянии диспетчера управления службами , чтобы пользователь смог определить, работает ли служба правильно. По умолчанию служба, наследующая от ServiceBase, сообщает ограниченный набор параметров состояния, включая SERVICE_STOPPED, SERVICE_PAUSED и SERVICE_RUNNING. Если служба занимает некоторое время для запуска, полезно сообщить SERVICE_START_PENDING о состоянии.
Вы можете установить SERVICE_START_PENDING и SERVICE_STOP_PENDING настройки статуса, добавив код, вызывающий функцию Windows SetServiceStatus.
usingДобавьте директиву в MyNewService.cs илиImportsинструкцию в MyNewService.vb для этого пространства имен:using System.Runtime.InteropServices;Imports System.Runtime.InteropServicesДобавьте следующее перечисление и структуру в MyNewService.cs или MyNewService.vb, чтобы объявить значения и добавить структуру для статуса, которую вы будете использовать в вызове функции платформы.
public enum ServiceState { SERVICE_STOPPED = 0x00000001, SERVICE_START_PENDING = 0x00000002, SERVICE_STOP_PENDING = 0x00000003, SERVICE_RUNNING = 0x00000004, SERVICE_CONTINUE_PENDING = 0x00000005, SERVICE_PAUSE_PENDING = 0x00000006, SERVICE_PAUSED = 0x00000007, } [StructLayout(LayoutKind.Sequential)] public struct ServiceStatus { public int dwServiceType; public ServiceState dwCurrentState; public int dwControlsAccepted; public int dwWin32ExitCode; public int dwServiceSpecificExitCode; public int dwCheckPoint; public int dwWaitHint; };Public Enum ServiceState SERVICE_STOPPED = 1 SERVICE_START_PENDING = 2 SERVICE_STOP_PENDING = 3 SERVICE_RUNNING = 4 SERVICE_CONTINUE_PENDING = 5 SERVICE_PAUSE_PENDING = 6 SERVICE_PAUSED = 7 End Enum <StructLayout(LayoutKind.Sequential)> Public Structure ServiceStatus Public dwServiceType As Long Public dwCurrentState As ServiceState Public dwControlsAccepted As Long Public dwWin32ExitCode As Long Public dwServiceSpecificExitCode As Long Public dwCheckPoint As Long Public dwWaitHint As Long End StructureЗамечание
Диспетчер управления службами использует
dwWaitHintиdwCheckpointчлены структуры SERVICE_STATUS , чтобы определить время ожидания запуска или завершения работы службы Windows. Если ваши методыOnStartиOnStopвыполняются долго, служба может выделить больше времени, вызываяSetServiceStatusеще раз с увеличенным значениемdwCheckPoint.В классе
MyNewServiceобъявите функцию SetServiceStatus, используя Platform Invoke:[DllImport("advapi32.dll", SetLastError = true)] private static extern bool SetServiceStatus(System.IntPtr handle, ref ServiceStatus serviceStatus);Declare Auto Function SetServiceStatus Lib "advapi32.dll" (ByVal handle As IntPtr, ByRef serviceStatus As ServiceStatus) As BooleanЧтобы реализовать
SERVICE_START_PENDINGсостояние, добавьте следующий код в начало OnStart метода:// Update the service state to Start Pending. ServiceStatus serviceStatus = new ServiceStatus { dwCurrentState = ServiceState.SERVICE_START_PENDING, dwWaitHint = 100000 }; SetServiceStatus(this.ServiceHandle, ref serviceStatus);' Update the service state to Start Pending. Dim serviceStatus As ServiceStatus = New ServiceStatus() serviceStatus.dwCurrentState = ServiceState.SERVICE_START_PENDING serviceStatus.dwWaitHint = 100000 SetServiceStatus(Me.ServiceHandle, serviceStatus)Добавьте код в конец
OnStartметода, чтобы задать состояниеSERVICE_RUNNINGследующим образом:// Update the service state to Running. serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING; SetServiceStatus(this.ServiceHandle, ref serviceStatus);' Update the service state to Running. serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING SetServiceStatus(Me.ServiceHandle, serviceStatus)(Необязательно) Если OnStop это длительный метод, повторите эту процедуру в методе
OnStop. Реализуйте статусSERVICE_STOP_PENDINGи верните статусSERVICE_STOPPEDперед завершением методаOnStop.Рассмотрим пример.
// Update the service state to Stop Pending. ServiceStatus serviceStatus = new ServiceStatus { dwCurrentState = ServiceState.SERVICE_STOP_PENDING, dwWaitHint = 100000 }; SetServiceStatus(this.ServiceHandle, ref serviceStatus); // Update the service state to Stopped. serviceStatus.dwCurrentState = ServiceState.SERVICE_STOPPED; SetServiceStatus(this.ServiceHandle, ref serviceStatus);' Update the service state to Stop Pending. Dim serviceStatus As ServiceStatus = New ServiceStatus() serviceStatus.dwCurrentState = ServiceState.SERVICE_STOP_PENDING serviceStatus.dwWaitHint = 100000 SetServiceStatus(Me.ServiceHandle, serviceStatus) ' Update the service state to Stopped. serviceStatus.dwCurrentState = ServiceState.SERVICE_STOPPED SetServiceStatus(Me.ServiceHandle, serviceStatus)
Добавление установщиков в службу
Перед запуском службы Windows необходимо установить ее, которая регистрирует ее в диспетчере управления службами. Добавьте установщики в проект для обработки сведений о регистрации.
В обозревателе решений в контекстном меню для MyNewService.cs или MyNewService.vb выберите конструктор представлений.
В режиме конструктора выберите фоновую область, а затем выберите "Добавить установщик " в контекстном меню.
По умолчанию Visual Studio добавляет класс компонента с именем
ProjectInstaller, который содержит два установщика в проект. Эти установочные программы предназначены для вашей службы и связанного с ней процесса.В представлении конструктора для ProjectInstaller выберите serviceInstaller1 для проекта C# или ServiceInstaller1 для проекта Visual Basic, а затем выберите "Свойства" в контекстном меню.
В окне свойств установите свойство ServiceName на значение MyNewService.
Добавьте текст в Description свойство, например пример службы.
Этот текст отображается в столбце "Описание " окна "Службы " и описывает службу пользователю.
Добавьте текст в DisplayName свойство. Например, отображаемое имя MyNewService.
Этот текст отображается в столбце Имя для отображения окна Службы. Это имя может отличаться от ServiceName свойства, которое является именем, которое использует система (например, имя, используемое для команды для
net startзапуска службы).StartType Задайте для свойства Automatic значение из раскрывающегося списка.
По завершении окна свойств должны выглядеть следующим образом:
В представлении конструктора для ProjectInstaller выберите serviceProcessInstaller1 для проекта C# или ServiceProcessInstaller1 для проекта Visual Basic, а затем выберите "Свойства" в контекстном меню. Account Задайте для свойства LocalSystem значение из раскрывающегося списка.
Этот параметр устанавливает службу и запускает ее с помощью локальной системной учетной записи.
Это важно
У LocalSystem учетной записи есть широкие разрешения, включая возможность записи в журнал событий. Используйте эту учетную запись с осторожностью, так как это может увеличить риск атак со стороны вредоносного программного обеспечения. Для других задач рекомендуется использовать LocalService учетную запись, которая выступает в качестве не привилегированного пользователя на локальном компьютере и предоставляет анонимные учетные данные любому удаленному серверу. Однако этот пример завершается ошибкой, если вы пытаетесь использовать учетную запись LocalService, поскольку учетной записи требуется разрешение на запись в журнал событий.
Дополнительные сведения о установщиках см. в статье "Практическое руководство. Добавление установщиков в приложение службы".
(Необязательно) Настройка параметров запуска
Замечание
Прежде чем добавлять параметры запуска, подумайте, является ли это наилучшим способом передачи информации в вашу службу. Хотя их легко использовать и анализировать, и пользователь может легко переопределить их, без документации пользователю может быть сложнее их обнаружить и применять. Как правило, если для службы требуется несколько параметров запуска, вместо этого следует использовать реестр или файл конфигурации.
Служба Windows может принимать аргументы командной строки, также известные как параметры запуска. При добавлении кода для обработки параметров запуска пользователь может запустить службу с собственными настраиваемыми параметрами запуска в окне свойств службы. Однако эти параметры запуска не сохраняются при следующем запуске службы.
Чтобы задать параметры запуска безвозвратно, задайте их в реестре. У каждой службы Windows имеется запись реестра в подразделе HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services. В подразделе каждой службы используйте подраздел Параметры для хранения сведений, к которым может получить доступ ваша служба. Файлы конфигурации приложений можно использовать для службы Windows так же, как и для других типов программ. Пример кода см. в разделе ConfigurationManager.AppSettings.
Добавление параметров запуска
В MyNewService.cs или MyNewService.vb измените
MyNewServiceконструктор, чтобы принять и обработать входной параметр:public MyNewService(string[] args) { InitializeComponent(); string eventSourceName = "MySource"; string logName = "MyNewLog"; if (args.Length > 0) { eventSourceName = args[0]; } if (args.Length > 1) { logName = args[1]; } eventLog1 = new EventLog(); if (!EventLog.SourceExists(eventSourceName)) { EventLog.CreateEventSource(eventSourceName, logName); } eventLog1.Source = eventSourceName; eventLog1.Log = logName; }Public Sub New(ByVal cmdArgs() As String) InitializeComponent() Dim eventSourceName As String = "MySource" Dim logName As String = "MyNewLog" If (cmdArgs.Count() > 0) Then eventSourceName = cmdArgs(0) End If If (cmdArgs.Count() > 1) Then logName = cmdArgs(1) End If eventLog1 = New EventLog() If (Not EventLog.SourceExists(eventSourceName)) Then EventLog.CreateEventSource(eventSourceName, logName) End If eventLog1.Source = eventSourceName eventLog1.Log = logName End SubЭтот код задает имя источника события и журнала в соответствии с параметрами запуска, которые предоставляет пользователь. Если аргументы не указаны, он использует значения по умолчанию.
Выберите Program.cs или MyNewService.Designer.vb, а затем выберите "Просмотреть код " в контекстном меню. В методе
Mainизмените код, чтобы добавить входной параметр и передать его конструктору службы:static void Main(string[] args) { ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new MyNewService(args) }; ServiceBase.Run(ServicesToRun); }Shared Sub Main(ByVal cmdArgs() As String) Dim ServicesToRun() As System.ServiceProcess.ServiceBase = New System.ServiceProcess.ServiceBase() {New MyNewService(cmdArgs)} System.ServiceProcess.ServiceBase.Run(ServicesToRun) End SubЧтобы указать аргументы командной строки, добавьте следующий код в
ProjectInstallerкласс в ProjectInstaller.cs или ProjectInstaller.vb:protected override void OnBeforeInstall(IDictionary savedState) { string parameter = "MySource1\" \"MyLogFile1"; Context.Parameters["assemblypath"] = "\"" + Context.Parameters["assemblypath"] + "\" \"" + parameter + "\""; base.OnBeforeInstall(savedState); }Protected Overrides Sub OnBeforeInstall(ByVal savedState As IDictionary) Dim parameter As String = "MySource1"" ""MyLogFile1" Context.Parameters("assemblypath") = """" + Context.Parameters("assemblypath") + """ """ + parameter + """" MyBase.OnBeforeInstall(savedState) End SubКак правило, это значение содержит полный путь к исполняемому файлу для службы Windows. Для правильного запуска службы пользователь должен заключить в кавычки путь и каждый отдельный параметр. Пользователь может изменить параметры в записи реестра ImagePath , чтобы изменить параметры запуска для службы Windows. Однако лучше изменить значение программным способом и предоставить функциональность в удобном для пользователя способе, например с помощью служебной программы управления или конфигурации.
Создание службы
В обозревателе решений выберите "Свойства " в контекстном меню проекта MyNewService .
На вкладке "Приложение" в списке объектов startup выберите MyNewService.Program (или Sub Main для проектов Visual Basic).
Чтобы создать проект, в обозревателе решений выберите "Сборка" из контекстного меню проекта (или нажмите клавиши CTRL SHIFT++B).
Установка службы
Теперь, когда вы создали службу Windows, ее можно установить. Чтобы установить службу Windows, необходимо иметь учетные данные администратора на компьютере, на котором он установлен.
Откройте командную строку разработчика для Visual Studio с учетными данными администратора.
В командной строке разработчика для Visual Studio перейдите в папку, содержащую выходные данные проекта (по умолчанию — подкаталог \bin\Debug проекта).
Введите следующую команду:
installutil MyNewService.exeЕсли служба установлена успешно, команда сообщает об этом.
Если система не может найти installutil.exe, убедитесь, что она существует на компьютере. Это средство устанавливается вместе с .NET Framework в папку %windir%\Microsoft.NET\Framework[64]\<версия framework>.
Если процесс installutil.exe завершается ошибкой, проверьте журнал установки, чтобы узнать, почему. По умолчанию журнал находится в той же папке, что и исполняемый файл службы. Установка может завершиться ошибкой, если:
- Класс RunInstallerAttribute отсутствует в
ProjectInstallerклассе. - Атрибут не задан значением
true. - Класс
ProjectInstallerне определен какpublic. - Вы не открыли командную строку разработчика для VS от имени администратора.
- Класс RunInstallerAttribute отсутствует в
Дополнительные сведения см. в разделе "Практическое руководство. Установка и удаление служб".
Запуск и работа службы
В Windows откройте классическое приложение "Службы" : нажмите клавишу Windows+R , чтобы открыть поле запуска , введите services.msc и нажмите клавишу ВВОД или нажмите кнопку "ОК".
Вы должны видеть, что ваша служба отображается в Службах, отображаемая в алфавитном порядке по отображаемому имени, которое вы установили для неё.
Чтобы запустить службу, выберите "Пуск " из контекстного меню службы.
Чтобы остановить службу, выберите "Остановить " в контекстном меню службы.
(Необязательно) В командной строке используйте имя< службы net start > и имя< службы net stop>, чтобы запустить и остановить службу.
Проверка выходных данных журнала событий службы
В Windows откройте классическое приложение "Средство просмотра событий": введите "Средство просмотра событий" в строке поиска Windows и выберите "Средство просмотра событий" в результатах поиска.
Подсказка
В Visual Studio вы можете получить доступ к журналам событий, открыв обозреватель серверов в меню "Вид " (или нажав клавиши CTRL+ALT+S) и расширив узел журналов событий для локального компьютера.
В средстве просмотра событий разверните журналы приложений и служб.
Найдите список для MyNewLog (или MyLogFile1 , если вы выполнили процедуру для добавления аргументов командной строки) и разверните его. Вы увидите записи для двух действий (запуска и остановки), выполненных службой.
Очистите ресурсы
Если вам больше не нужен приложение службы Windows, его можно удалить.
Откройте командную строку разработчика для Visual Studio с учетными данными администратора.
В командной строке разработчика для Visual Studio перейдите в папку, содержащую исполняемый файл проекта.
Введите следующую команду:
installutil.exe /u MyNewService.exeЕсли служба успешно удаляется, команда сообщает, что служба успешно удалена. Дополнительные сведения см. в разделе "Практическое руководство. Установка и удаление служб".
Дальнейшие шаги
Теперь, когда вы создали службу, вы можете:
Создайте автономную программу установки, которую могли бы использовать другие пользователи для установки службы Windows. Используйте набор инструментов WiX для создания установщика для службы Windows. Другие идеи см. в разделе "Создание пакета установщика".
Изучите ServiceController компонент, который позволяет отправлять команды в установленную вами службу.
Вместо создания журнала событий при запуске приложения используйте установщик для создания журнала событий при установке приложения. Журнал событий удаляется установщиком при удалении приложения. Дополнительные сведения см. в разделе EventLogInstaller.