Размещение ASP.NET Core в службе WindowsHost ASP.NET Core in a Windows Service

Авторы: Люк Латэм (Luke Latham) и Tom Dykstra (Том Дайкстра)By Luke Latham and Tom Dykstra

Приложение ASP.NET Core можно разместить в Windows в качестве службы Windows без использования IIS.An ASP.NET Core app can be hosted on Windows as a Windows Service without using IIS. При размещении в качестве службы Windows приложение автоматически запускается после перезагрузки сервера.When hosted as a Windows Service, the app automatically starts after server reboots.

Просмотреть или скачать образец кода (как скачивать)View or download sample code (how to download)

Предварительные требованияPrerequisites

Шаблон службы рабочей ролиWorker Service template

Шаблон службы рабочей роли ASP.NET Core может служить отправной точкой для написания длительно выполняющихся приложений служб.The ASP.NET Core Worker Service template provides a starting point for writing long running service apps. Чтобы использовать шаблон в качестве основы для приложения службы Windows, выполните указанные ниже действия.To use the template as a basis for a Windows Service app:

  1. Создайте приложение службы рабочей роли на основе шаблона .NET Core.Create a Worker Service app from the .NET Core template.
  2. Согласно указаниям в разделе Конфигурация приложения измените приложение службы рабочей роли так, чтобы оно могло выполняться как служба Windows.Follow the guidance in the App configuration section to update the Worker Service app so that it can run as a Windows Service.
  1. Создайте новый проект.Create a new project.
  2. Выберите Новое веб-приложение ASP.NET Core.Select ASP.NET Core Web Application. Выберите Далее.Select Next.
  3. В поле Имя проекта укажите имя проекта или оставьте имя по умолчанию.Provide a project name in the Project name field or accept the default project name. Выберите Создать.Select Create.
  4. В диалоговом окне Создание веб-приложения ASP.NET Core убедитесь в том, что выбраны платформы .NET Core и ASP.NET Core 3.0.In the Create a new ASP.NET Core Web Application dialog, confirm that .NET Core and ASP.NET Core 3.0 are selected.
  5. Выберите шаблон Служба рабочей роли.Select the Worker Service template. Выберите Создать.Select Create.

Конфигурация приложенияApp configuration

IHostBuilder.UseWindowsService в составе пакета Microsoft.Extensions.Hosting.WindowsServices вызывается при создании узла.IHostBuilder.UseWindowsService, provided by the Microsoft.Extensions.Hosting.WindowsServices package, is called when building the host. Если приложение выполняется как служба Windows, метод отвечает за следующие действия:If the app is running as a Windows Service, the method:

  • Задает для узла время существования WindowsServiceLifetime.Sets the host lifetime to WindowsServiceLifetime.
  • Задает корневой каталог содержимого.Sets the content root.
  • Включает ведение журнала событий с именем приложения в качестве имени источника по умолчанию.Enables logging to the event log with the application name as the default source name.
    • Уровень ведения журнала можно задать с помощью ключа Logging:LogLevel:Default в файле appsettings.Production.json.The log level can be configured using the Logging:LogLevel:Default key in the appsettings.Production.json file.
    • Только администраторы могут создавать источники событий.Only administrators can create new event sources. Если источник событий создать нельзя, используя имя приложения, для источника Приложение регистрируется предупреждение и журналы событий отключаются.When an event source can't be created using the application name, a warning is logged to the Application source and event logs are disabled.
public class Program
{
    public static async Task Main(string[] args)
    {
        await CreateHostBuilder(args).Build().RunAsync();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseWindowsService()
            .ConfigureAppConfiguration((context, config) =>
            {
                // Configure the app here.
            })
            .ConfigureServices((hostContext, services) =>
            {
                services.AddHostedService<ServiceA>();
                services.AddHostedService<ServiceB>();
            })
            // Only required if the service responds to requests.
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

Приложение требует ссылки на пакеты для Microsoft.AspNetCore.Hosting.WindowsServices и Microsoft.Extensions.Logging.EventLog.The app requires package references for Microsoft.AspNetCore.Hosting.WindowsServices and Microsoft.Extensions.Logging.EventLog.

Для тестирования и отладки при работе вне службы добавьте код, чтобы определить, как выполняется приложение: в качестве службы или консольного приложения.To test and debug when running outside of a service, add code to determine if the app is running as a service or a console app. Проверьте, присоединен ли отладчик или присутствует ли параметр --console.Inspect if the debugger is attached or a --console switch is present. Если одно из условий имеет значение true (приложение выполняется не в качестве службы), вызовите Run.If either condition is true (the app isn't run as a service), call Run. Если условия имеют значение false (приложение выполняется в качестве службы), сделайте следующее:If the conditions are false (the app is run as a service):

Так как поставщик конфигурации командной строки требует указания пар "имя-значение" для аргументов командной строки, параметр --console удаляется из аргументов, прежде чем CreateDefaultBuilder получит их.Because the Command-line Configuration Provider requires name-value pairs for command-line arguments, the --console switch is removed from the arguments before CreateDefaultBuilder receives the arguments.

Для записи данных в журнал событий Windows добавьте поставщик EventLog в ConfigureLogging.To write to the Windows Event Log, add the EventLog provider to ConfigureLogging. Задайте уровень ведения журнала с помощью ключа Logging:LogLevel:Default в файле appsettings.Production.json.Set the logging level with the Logging:LogLevel:Default key in the appsettings.Production.json file.

В следующем примере RunAsCustomService вызывается вместо RunAsService для обработки событий времени существования в приложении.In the following example from the sample app, RunAsCustomService is called instead of RunAsService in order to handle lifetime events within the app. Дополнительные сведения см. в разделе Обработка событий запуска и остановки.For more information, see the Handle starting and stopping events section.

public class Program
{
    public static void Main(string[] args)
    {
        var isService = !(Debugger.IsAttached || args.Contains("--console"));
        
        if (isService)
        {
            var pathToExe = Process.GetCurrentProcess().MainModule.FileName;
            var pathToContentRoot = Path.GetDirectoryName(pathToExe);
            Directory.SetCurrentDirectory(pathToContentRoot);
        }

        var builder = CreateWebHostBuilder(
            args.Where(arg => arg != "--console").ToArray());

        var host = builder.Build();

        if (isService)
        {
            // To run the app without the CustomWebHostService change the
            // next line to host.RunAsService();
            host.RunAsCustomService();
        }
        else
        {
            host.Run();
        }
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureLogging((hostingContext, logging) =>
            {
                logging.AddEventLog();
            })
            .ConfigureAppConfiguration((context, config) =>
            {
                // Configure the app here.
            })
            .UseStartup<Startup>();
}

Тип развертыванияDeployment type

Дополнительные сведения и рекомендации по сценариям развертывания см. в статье Развертывание приложений .NET Core.For information and advice on deployment scenarios, see .NET Core application deployment.

Зависящее от платформы развертывание (FDD)Framework-dependent deployment (FDD)

Зависящее от платформы развертывание (FDD) требует наличия в целевой системе общей для всей системы версии .NET Core.Framework-dependent deployment (FDD) relies on the presence of a shared system-wide version of .NET Core on the target system. Если сценарий с FDD используется согласно инструкций в этой статье, пакет SDK создаcт исполняемый файл ( .exe), который называется исполняемым файлом, зависящим от платформы.When the FDD scenario is adopted following the guidance in this article, the SDK produces an executable (.exe), called a framework-dependent executable.

Добавьте следующие элементы свойства в файл проекта:Add the following property elements to the project file:

  • <OutputType> — тип выходных данных приложения (Exe для исполняемого файла).<OutputType> – The app's output type (Exe for executable).
  • <LangVersion> — версия языка C# (latest или preview).<LangVersion> – The C# language version (latest or preview).

Файл web.config, который обычно создается при публикации приложения ASP.NET Core, не требуется для приложения служб Windows.A web.config file, which is normally produced when publishing an ASP.NET Core app, is unnecessary for a Windows Services app. Отмените создание файла web.config, добавив свойство <IsTransformWebConfigDisabled> со значением true.To disable the creation of the web.config file, add the <IsTransformWebConfigDisabled> property set to true.

<PropertyGroup>
  <TargetFramework>netcoreapp3.0</TargetFramework>
  <OutputType>Exe</OutputType>
  <LangVersion>preview</LangVersion>
  <IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>
</PropertyGroup>

Идентификатор среды выполнения Windows (<RuntimeIdentifier>) содержит целевую версию платформы.The Windows Runtime Identifier (RID) (<RuntimeIdentifier>) contains the target framework. В следующем примере для RID задано значение win7-x64.In the following example, the RID is set to win7-x64. Свойству <SelfContained> задано значение false.The <SelfContained> property is set to false. Эти свойства указывают пакету SDK создать исполняемый файл ( .exe) для Windows и приложение, которое зависит от общей платформы .NET Core.These properties instruct the SDK to generate an executable (.exe) file for Windows and an app that depends on the shared .NET Core framework.

Файл web.config, который обычно создается при публикации приложения ASP.NET Core, не требуется для приложения служб Windows.A web.config file, which is normally produced when publishing an ASP.NET Core app, is unnecessary for a Windows Services app. Отмените создание файла web.config, добавив свойство <IsTransformWebConfigDisabled> со значением true.To disable the creation of the web.config file, add the <IsTransformWebConfigDisabled> property set to true.

<PropertyGroup>
  <TargetFramework>netcoreapp2.2</TargetFramework>
  <RuntimeIdentifier>win7-x64</RuntimeIdentifier>
  <SelfContained>false</SelfContained>
  <IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>
</PropertyGroup>

Идентификатор среды выполнения Windows (<RuntimeIdentifier>) содержит целевую версию платформы.The Windows Runtime Identifier (RID) (<RuntimeIdentifier>) contains the target framework. В следующем примере для RID задано значение win7-x64.In the following example, the RID is set to win7-x64. Свойству <SelfContained> задано значение false.The <SelfContained> property is set to false. Эти свойства указывают пакету SDK создать исполняемый файл ( .exe) для Windows и приложение, которое зависит от общей платформы .NET Core.These properties instruct the SDK to generate an executable (.exe) file for Windows and an app that depends on the shared .NET Core framework.

Свойству <UseAppHost> задано значение true.The <UseAppHost> property is set to true. Это свойство предоставляет службу с путем активации (исполняемый файл, EXE) для FDD.This property provides the service with an activation path (an executable, .exe) for an FDD.

Файл web.config, который обычно создается при публикации приложения ASP.NET Core, не требуется для приложения служб Windows.A web.config file, which is normally produced when publishing an ASP.NET Core app, is unnecessary for a Windows Services app. Отмените создание файла web.config, добавив свойство <IsTransformWebConfigDisabled> со значением true.To disable the creation of the web.config file, add the <IsTransformWebConfigDisabled> property set to true.

<PropertyGroup>
  <TargetFramework>netcoreapp2.1</TargetFramework>
  <RuntimeIdentifier>win7-x64</RuntimeIdentifier>
  <UseAppHost>true</UseAppHost>
  <SelfContained>false</SelfContained>
  <IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>
</PropertyGroup>

Автономное развертываниеSelf-contained deployment (SCD)

Для автономного развертывания необязательно наличие общей платформы в системе размещения.Self-contained deployment (SCD) doesn't rely on the presence of a shared framework on the host system. Среда выполнения и зависимости приложения развертываются с приложением.The runtime and the app's dependencies are deployed with the app.

Идентификатор среды выполнения Windows включается в <PropertyGroup>, где содержится целевая платформа:A Windows Runtime Identifier (RID) is included in the <PropertyGroup> that contains the target framework:

<RuntimeIdentifier>win7-x64</RuntimeIdentifier>

Чтобы выполнить публикацию для нескольких идентификаторов RID, сделайте следующее.To publish for multiple RIDs:

  • Укажите список идентификаторов RID, разделив их точкой с запятой.Provide the RIDs in a semicolon-delimited list.
  • Используйте имя свойства <RuntimeIdentifiers> (во множественном числе).Use the property name <RuntimeIdentifiers> (plural).

Дополнительные сведения см. в каталоге RID для .NET Core.For more information, see .NET Core RID Catalog.

Для свойства <SelfContained> задано значение true:A <SelfContained> property is set to true:

<SelfContained>true</SelfContained>

Учетная запись пользователя службыService user account

Создайте для службы учетную запись пользователя с помощью командлета New-LocalUser в административной оболочке PowerShell 6.To create a user account for a service, use the New-LocalUser cmdlet from an administrative PowerShell 6 command shell.

Обновление Windows 10 за октябрь 2018 г. (версия 1809, сборка 10.0.17763) или более поздней версии:On Windows 10 October 2018 Update (version 1809/build 10.0.17763) or later:

New-LocalUser -Name {NAME}

Версия Windows, предшествующая обновлению Windows 10 за октябрь 2018 г. (версия 1809, сборка 10.0.17763):On Windows OS earlier than the Windows 10 October 2018 Update (version 1809/build 10.0.17763):

powershell -Command "New-LocalUser -Name {NAME}"

Укажите надежный пароль при появлении соответствующего запроса.Provide a strong password when prompted.

Параметр срока действия учетной записи DateTime можно задать с помощью параметра -AccountExpires, передаваемого в командлет New-LocalUser.Unless the -AccountExpires parameter is supplied to the New-LocalUser cmdlet with an expiration DateTime, the account doesn't expire.

Дополнительные сведения см. в статьях Microsoft.PowerShell.LocalAccounts и Service User Accounts (Учетные записи пользователей служб).For more information, see Microsoft.PowerShell.LocalAccounts and Service User Accounts.

Альтернативный подход к управлению пользователями при работе с Active Directory заключается в применении управляемых учетных записей служб.An alternative approach to managing users when using Active Directory is to use Managed Service Accounts. Дополнительные сведения см. в обзоре групповых управляемых учетных записей службы.For more information, see Group Managed Service Accounts Overview.

Права на вход в качестве службыLog on as a service rights

Чтобы настроить право Вход в качестве службы для учетной записи пользователя службы, сделайте следующее:To establish Log on as a service rights for a service user account:

  1. Откройте редактор локальной политики безопасности, запустив secpol.msc.Open the Local Security Policy editor by running secpol.msc.
  2. Разверните узел Локальные политики и выберите Назначение прав пользователя.Expand the Local Policies node and select User Rights Assignment.
  3. Откройте политику Вход в качестве службы.Open the Log on as a service policy.
  4. Щелкните Добавить пользователя или группу.Select Add User or Group.
  5. Укажите имя объекта (учетная запись пользователя) одним из следующих способов:Provide the object name (user account) using either of the following approaches:
    1. Укажите учетную запись пользователя ({DOMAIN OR COMPUTER NAME\USER}) в поле для имени объекта и нажмите ОК, чтобы назначить политику пользователю.Type the user account ({DOMAIN OR COMPUTER NAME\USER}) in the object name field and select OK to add the user to the policy.
    2. Выберите Дополнительно.Select Advanced. Нажмите Найти.Select Find Now. Выберите учетную запись пользователя из списка.Select the user account from the list. Нажмите кнопку ОК.Select OK. Нажмите ОК еще раз, чтобы назначить политику пользователю.Select OK again to add the user to the policy.
  6. Нажмите ОК или Применить, чтобы сохранить изменения.Select OK or Apply to accept the changes.

Создание службы Windows и управление еюCreate and manage the Windows Service

Создание службыCreate a service

Зарегистрируйте службу с помощью команды PowerShell.Use PowerShell commands to register a service. В административной оболочке PowerShell 6 выполните следующие команды:From an administrative PowerShell 6 command shell, execute the following commands:

$acl = Get-Acl "{EXE PATH}"
$aclRuleArgs = {DOMAIN OR COMPUTER NAME\USER}, "Read,Write,ReadAndExecute", "ContainerInherit,ObjectInherit", "None", "Allow"
$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($aclRuleArgs)
$acl.SetAccessRule($accessRule)
$acl | Set-Acl "{EXE PATH}"

New-Service -Name {NAME} -BinaryPathName {EXE FILE PATH} -Credential {DOMAIN OR COMPUTER NAME\USER} -Description "{DESCRIPTION}" -DisplayName "{DISPLAY NAME}" -StartupType Automatic
  • {EXE PATH} — путь к папке приложения на узле (например, d:\myservice).{EXE PATH} – Path to the app's folder on the host (for example, d:\myservice). Не включайте исполняемый файл приложения в путь.Don't include the app's executable in the path. Завершающая косая черта не требуется.A trailing slash isn't required.
  • {DOMAIN OR COMPUTER NAME\USER} —учетная запись пользователя службы (например, Contoso\ServiceUser).{DOMAIN OR COMPUTER NAME\USER} – Service user account (for example, Contoso\ServiceUser).
  • {NAME} — имя службы (например, MyService).{NAME} – Service name (for example, MyService).
  • {EXE FILE PATH} — путь к исполняемому файлу приложения (например, d:\myservice\myservice.exe).{EXE FILE PATH} – The app's executable path (for example, d:\myservice\myservice.exe). Включите имя исполняемого файла с расширением.Include the executable's file name with extension.
  • {DESCRIPTION} — описание службы (например, My sample service).{DESCRIPTION} – Service description (for example, My sample service).
  • {DISPLAY NAME} — отображаемое имя службы (например, My Service).{DISPLAY NAME} – Service display name (for example, My Service).

Запуск службыStart a service

Запустите службу с помощью следующей команды PowerShell 6:Start a service with the following PowerShell 6 command:

Start-Service -Name {NAME}

Команде потребуется несколько секунд, чтобы запустить службу.The command takes a few seconds to start the service.

Определение состояния службыDetermine a service's status

Чтобы проверить состояние службы, используйте следующую команду PowerShell 6:To check the status of a service, use the following PowerShell 6 command:

Get-Service -Name {NAME}

Состояние отображается одним из следующих значений:The status is reported as one of the following values:

  • Starting
  • Running
  • Stopping
  • Stopped

Остановка службыStop a service

Остановите службу с помощью следующей команды PowerShell 6:Stop a service with the following Powershell 6 command:

Stop-Service -Name {NAME}

Удаление службыRemove a service

После небольшой задержки для остановки службы удалите службу с помощью следующей команды Powershell 6:After a short delay to stop a service, remove a service with the following Powershell 6 command:

Remove-Service -Name {NAME}

Обработка событий запуска и остановкиHandle starting and stopping events

Чтобы обработать события OnStarting, OnStarted и OnStopping, сделайте следующее:To handle OnStarting, OnStarted, and OnStopping events:

  1. Создайте класс, производный от WebHostService, с методами OnStarting, OnStarted и OnStopping:Create a class that derives from WebHostService with the OnStarting, OnStarted, and OnStopping methods:

    [DesignerCategory("Code")]
    internal class CustomWebHostService : WebHostService
    {
        private ILogger _logger;
    
        public CustomWebHostService(IWebHost host) : base(host)
        {
            _logger = host.Services
                .GetRequiredService<ILogger<CustomWebHostService>>();
        }
    
        protected override void OnStarting(string[] args)
        {
            _logger.LogInformation("OnStarting method called.");
            base.OnStarting(args);
        }
    
        protected override void OnStarted()
        {
            _logger.LogInformation("OnStarted method called.");
            base.OnStarted();
        }
    
        protected override void OnStopping()
        {
            _logger.LogInformation("OnStopping method called.");
            base.OnStopping();
        }
    }
    
  2. Создайте метод расширения для IWebHost, который передает CustomWebHostService в Run:Create an extension method for IWebHost that passes the CustomWebHostService to Run:

    public static class WebHostServiceExtensions
    {
        public static void RunAsCustomService(this IWebHost host)
        {
            var webHostService = new CustomWebHostService(host);
            ServiceBase.Run(webHostService);
        }
    }
    
  3. В Program.Main вызовите метод расширения RunAsCustomService вместо RunAsService:In Program.Main, call the RunAsCustomService extension method instead of RunAsService:

    host.RunAsCustomService();
    

    Чтобы узнать расположение RunAsService в Program.Main, см. пример кода из раздела Тип развертывания.To see the location of RunAsService in Program.Main, refer to the code sample shown in the Deployment type section.

Сценарии использования прокси-сервера и подсистемы балансировки нагрузкиProxy server and load balancer scenarios

Для служб, которые взаимодействуют с запросами из Интернета или корпоративной сети и размещаются за прокси-сервером или подсистемой балансировки нагрузки, может потребоваться дополнительная настройка.Services that interact with requests from the Internet or a corporate network and are behind a proxy or load balancer might require additional configuration. Дополнительные сведения можно найти по адресу: Настройка ASP.NET Core для работы с прокси-серверами и подсистемами балансировки нагрузки.For more information, see Настройка ASP.NET Core для работы с прокси-серверами и подсистемами балансировки нагрузки.

Настройка HTTPSConfigure HTTPS

Чтобы настроить службу с защищенной конечной точкой, сделайте следующее:To configure a service with a secure endpoint:

  1. Создайте сертификат X.509 для системы размещения с помощью механизмов получения и развертывания сертификата вашей платформы.Create an X.509 certificate for the hosting system using your platform's certificate acquisition and deployment mechanisms.

  2. Укажите конфигурацию конечной точки HTTPS для сервера Kestrel, чтобы использовать сертификат.Specify a Kestrel server HTTPS endpoint configuration to use the certificate.

Использование сертификата разработки ASP.NET Core HTTPS для защиты конечной точки службы не поддерживается.Use of the ASP.NET Core HTTPS development certificate to secure a service endpoint isn't supported.

Текущий каталог и корневой каталог содержимогоCurrent directory and content root

Для службы Windows GetCurrentDirectory возвращает текущий рабочий каталог C:\WINDOWS\system32.The current working directory returned by calling GetCurrentDirectory for a Windows Service is the C:\WINDOWS\system32 folder. Папка system32 не подходит для хранения файлов службы (например, файлов параметров).The system32 folder isn't a suitable location to store a service's files (for example, settings files). Используйте один из следующих методов для сохранения ресурсов и файлов параметров службы и доступа к ним.Use one of the following approaches to maintain and access a service's assets and settings files.

Использование ContentRootPath или ContentRootFileProviderUse ContentRootPath or ContentRootFileProvider

Используйте IHostEnvironment.ContentRootPath или ContentRootFileProvider для поиска ресурсов приложения.Use IHostEnvironment.ContentRootPath or ContentRootFileProvider to locate an app's resources.

Указание папки приложения в качестве пути корневого каталога содержимогоSet the content root path to the app's folder

ContentRootPath — это тот же путь, который предоставляется аргументу binPath при создании службы.The ContentRootPath is the same path provided to the binPath argument when a service is created. Чтобы не вызывать метод GetCurrentDirectory для создания путей к файлам параметров, вызовите SetCurrentDirectory с указанным путем к корневому каталогу содержимого приложения.Instead of calling GetCurrentDirectory to create paths to settings files, call SetCurrentDirectory with the path to the app's content root.

В Program.Main определите путь к папке с исполняемым файлом службы и используйте этот путь, чтобы создать корневой каталог содержимого приложения.In Program.Main, determine the path to the folder of the service's executable and use the path to establish the app's content root:

var pathToExe = Process.GetCurrentProcess().MainModule.FileName;
var pathToContentRoot = Path.GetDirectoryName(pathToExe);
Directory.SetCurrentDirectory(pathToContentRoot);

CreateWebHostBuilder(args)
    .Build()
    .RunAsService();

Хранение файлов службы в подходящем расположении на дискеStore a service's files in a suitable location on disk

Укажите абсолютный путь к папке, содержащей файлы, с помощью SetBasePath при использовании IConfigurationBuilder.Specify an absolute path with SetBasePath when using an IConfigurationBuilder to the folder containing the files.

Дополнительные ресурсыAdditional resources