Hospedar o ASP.NET Core em um serviço WindowsHost ASP.NET Core in a Windows Service

Por Luke Latham e Tom DykstraBy Luke Latham and Tom Dykstra

Um aplicativo ASP.NET Core pode ser hospedado no Windows somo um Serviço Windows sem usar o IIS.An ASP.NET Core app can be hosted on Windows as a Windows Service without using IIS. Quando hospedado como um Serviço Windows, o aplicativo é iniciado automaticamente após a reinicialização.When hosted as a Windows Service, the app automatically starts after reboots.

Exibir ou baixar código de exemplo (como baixar)View or download sample code (how to download)

Pré-requisitosPrerequisites

Observação

Para sistemas operacionais do Windows anteriores à atualização do Windows 10 de outubro de 2018 (versão 1809/build 10.0.17763), o módulo Microsoft.PowerShell.LocalAccounts deve ser importado com o módulo WindowsCompatibility para acessar o cmdlet New-LocalUser usado na seção Criar uma conta de usuário:For Windows OS earlier than the Windows 10 October 2018 Update (version 1809/build 10.0.17763), the Microsoft.PowerShell.LocalAccounts module must be imported with the WindowsCompatibility module to gain access to the New-LocalUser cmdlet used in the Create a user account section:

Install-Module WindowsCompatibility -Scope CurrentUser
Import-WinModule Microsoft.PowerShell.LocalAccounts

Tipo de implantaçãoDeployment type

Você pode criar uma implantação de Serviço Windows dependente de estrutura ou autocontida.You can create either a framework-dependent or self-contained Windows Service deployment. Para saber mais e obter conselhos sobre cenários de implantação, consulte Implantação de aplicativos .NET Core.For information and advice on deployment scenarios, see .NET Core application deployment.

Implantação dependente de estruturaFramework-dependent deployment

A FDD (Implantação Dependente de Estrutura) se baseia na presença de uma versão compartilhada em todo o sistema do .NET Core no sistema de destino.Framework-dependent deployment (FDD) relies on the presence of a shared system-wide version of .NET Core on the target system. Quando o cenário FDD é usado com um aplicativo de Serviço Windows do ASP.NET Core, o SDK produz um executável (*.exe), chamado de executável dependente de estrutura.When the FDD scenario is used with an ASP.NET Core Windows Service app, the SDK produces an executable (*.exe), called a framework-dependent executable.

Implantação autocontidaSelf-contained deployment

A SCD (Implantação Autocontida) não se baseia na presença de componentes compartilhados no sistema de destino.Self-contained deployment (SCD) doesn't rely on the presence of shared components on the target system. O tempo de execução e as dependências do aplicativo são implantados com o aplicativo para o sistema de hospedagem.The runtime and the app's dependencies are deployed with the app to the hosting system.

Converter um projeto em um serviço WindowsConvert a project into a Windows Service

Faça as seguintes alterações em um projeto ASP.NET Core existente para executar o aplicativo como um serviço:Make the following changes to an existing ASP.NET Core project to run the app as a service:

Atualizações de arquivo de projetoProject file updates

Com base na sua escolha de tipo de implantação, atualize o arquivo de projeto:Based on your choice of deployment type, update the project file:

FDD (Implantação dependente de estrutura)Framework-dependent Deployment (FDD)

Adicione um RID (Identificador do Tempo de Execução) do Windows ao <PropertyGroup> que contém a estrutura de destino.Add a Windows Runtime Identifier (RID) to the <PropertyGroup> that contains the target framework. No exemplo a seguir, o RID é especificado como win7-x64.In the following example, the RID is set to win7-x64. Adicione a propriedade <SelfContained> definida como false.Add the <SelfContained> property set to false. Essas propriedades instruem o SDK a gerar um arquivo executável (.exe) para Windows.These properties instruct the SDK to generate an executable (.exe) file for Windows.

O arquivo web.config, que normalmente é gerado durante a publicação de um aplicativo ASP.NET Core, é desnecessário para um aplicativo de serviços do Windows.A web.config file, which is normally produced when publishing an ASP.NET Core app, is unnecessary for a Windows Services app. Para desabilitar a criação de um arquivo web.config, adicione a propriedade <IsTransformWebConfigDisabled> definida como 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>

Adicione a propriedade <UseAppHost> definida como true.Add the <UseAppHost> property set to true. Essa propriedade fornece o serviço com um caminho de ativação (um arquivo executável .exe) para FDD.This property provides the service with an activation path (an executable, .exe) for an FDD.

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

SCD (Implantação Autossuficiente)Self-contained Deployment (SCD)

Confirme a presença de um RID (Identificador de Tempo de Execução) do Windows ou adicione um RID ao <PropertyGroup> que contém a estrutura de destino.Confirm the presence of a Windows Runtime Identifier (RID) or add a RID to the <PropertyGroup> that contains the target framework. Desabilite a criação de um arquivo web.config adicionando a propriedade <IsTransformWebConfigDisabled> definida como true.Disable the creation of a web.config file by adding the <IsTransformWebConfigDisabled> property set to true.

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

Para publicar para vários RIDs:To publish for multiple RIDs:

  • Forneça os RIDs em uma lista delimitada por ponto e vírgula.Provide the RIDs in a semicolon-delimited list.

  • Use o nome da propriedade <RuntimeIdentifiers> (plural).Use the property name <RuntimeIdentifiers> (plural).

    Para obter mais informações, consulte Catálogo de RID do .NET Core.For more information, see .NET Core RID Catalog.

Adicionar uma referência de pacote para Microsoft.AspNetCore.Hosting.WindowsServices.Add a package reference for Microsoft.AspNetCore.Hosting.WindowsServices.

Para habilitar o registro em log do Log de Eventos do Windows, adicione uma referência de pacote para Microsoft.Extensions.Logging.EventLog.To enable Windows Event Log logging, add a package reference for Microsoft.Extensions.Logging.EventLog.

Para saber mais, consulte a seção Manipular eventos de início e de parada.For more information, see the Handle starting and stopping events section.

Atualizações de Program.MainProgram.Main updates

Faça as seguintes alterações em Program.Main:Make the following changes in Program.Main:

  • Para testar e depurar quando a execução estiver sendo feita fora de um serviço, adicione código para determinar se o aplicativo está sendo executado como um serviço ou aplicativo de console.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. Verifique se o depurador está anexado ou se há um argumento de linha de comado do --console presente.Inspect if the debugger is attached or a --console command-line argument is present.

    Se uma dessas condições for verdadeira (o aplicativo não for executado como um serviço), chame Run no Host da Web.If either condition is true (the app isn't run as a service), call Run on the Web Host.

    Se as condições forem falsas (o aplicativo for executado como um serviço):If the conditions are false (the app is run as a service):

    Como o Provedor de Configuração da Linha de Comando requer pares nome-valor para argumentos de linha de comando, a opção --console é removida dos argumentos antes de o CreateDefaultBuilder recebê-los.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 them.

  • Para gravar no Log de Eventos do Windows, adicione o Provedor de Log de Eventos a ConfigureLogging.To write to the Windows Event Log, add the EventLog provider to ConfigureLogging. Defina o nível de log com a chave Logging:LogLevel:Default no arquivo appsettings.Production.JSON.Set the logging level with the Logging:LogLevel:Default key in the appsettings.Production.json file. Para fins de teste e demonstração, o arquivo de configurações de Produção do aplicativo de exemplo define o nível de log para Information.For demonstration and testing purposes, the sample app's Production settings file sets the logging level to Information. Na produção, o valor normalmente é definido como Error.In production, the value is typically set to Error. Para obter mais informações, consulte Registro em log no ASP.NET Core.For more information, see Registro em log no ASP.NET Core.

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>();
}

Publique o aplicativoPublish the app

Publique o aplicativo usando dotnet publish, um perfil de publicação do Visual Studio ou o Visual Studio Code.Publish the app using dotnet publish, a Visual Studio publish profile, or Visual Studio Code. Ao usar o Visual Studio, selecione o FolderProfile e configure o Local de destino antes de selecionar o botão Publicar.When using Visual Studio, select the FolderProfile and configure the Target Location before selecting the Publish button.

Para publicar o aplicativo de exemplo usando as ferramentas da CLI (Interface de Linha de Comando), execute o comando dotnet publish em um shell de comando do Windows na pasta do projeto, passando a configuração de uma versão para a opção -c|--configuration.To publish the sample app using command-line interface (CLI) tools, run the dotnet publish command in a Windows command shell from the project folder with a Release configuration passed to the -c|--configuration option. Use a opção -o|--output com um caminho para publicar em uma pasta fora do aplicativo.Use the -o|--output option with a path to publish to a folder outside of the app.

Publicar uma FDD (Implantação Dependente de Estrutura)Publish a Framework-dependent Deployment (FDD)

No exemplo a seguir, o aplicativo é publicado na pasta c:\svc:In the following example, the app is published to the c:\svc folder:

dotnet publish --configuration Release --output c:\svc

Publicar uma SCD (Implantação Autossuficiente)Publish a Self-contained Deployment (SCD)

O RID deve ser especificado na propriedade <RuntimeIdenfifier> (ou <RuntimeIdentifiers>) do arquivo de projeto.The RID must be specified in the <RuntimeIdenfifier> (or <RuntimeIdentifiers>) property of the project file. Insira o tempo de execução na opção -r|--runtime do comando dotnet publish.Supply the runtime to the -r|--runtime option of the dotnet publish command.

No exemplo a seguir, o aplicativo é publicado para o tempo de execução win7-x64 para a pasta c:\svc:In the following example, the app is published for the win7-x64 runtime to the c:\svc folder:

dotnet publish --configuration Release --runtime win7-x64 --output c:\svc

Criar uma conta de usuárioCreate a user account

Crie uma conta de usuário para o serviço usando o cmdlet New-LocalUser de um shell de comando administrativo do PowerShell 6:Create a user account for the service using the New-LocalUser cmdlet from an administrative PowerShell 6 command shell:

New-LocalUser -Name {NAME}

Forneça uma senha forte quando solicitado.Provide a strong password when prompted.

Crie uma conta de usuário com o nome ServiceUser para o aplicativo de exemplo.For the sample app, create a user account with the name ServiceUser.

New-LocalUser -Name ServiceUser

A conta só expirará se o parâmetro -AccountExpires for fornecido ao cmdlet New LocalUser com uma data de validade DateTime.Unless the -AccountExpires parameter is supplied to the New-LocalUser cmdlet with an expiration DateTime, the account doesn't expire.

Confira mais informações em Microsoft.PowerShell.LocalAccounts e Contas de usuário do serviço.For more information, see Microsoft.PowerShell.LocalAccounts and Service User Accounts.

Uma abordagem alternativa ao gerenciamento de usuários ao usar o Active Directory é usar Contas de Serviço Gerenciado.An alternative approach to managing users when using Active Directory is to use Managed Service Accounts. Para saber mais, confira Visão geral das Contas de Serviço Gerenciado em Grupo.For more information, see Group Managed Service Accounts Overview.

Definir permissão: Fazer logon como serviçoSet permission: Log on as a service

Conceda acesso de gravação/leitura/execução à pasta do aplicativo usando o comando icacls de um shell de comando administrativo do PowerShell 6.Grant write/read/execute access to the app's folder using the icacls command an administrative PowerShell 6 command shell.

icacls "{PATH}" /grant "{USER ACCOUNT}:(OI)(CI){PERMISSION FLAGS}" /t
  • {PATH} – Caminho para a pasta do aplicativo.{PATH} – Path to the app's folder.
  • {USER ACCOUNT} – A conta de usuário (SID).{USER ACCOUNT} – The user account (SID).
  • (OI) – O sinalizador de Herança de Objeto propaga as permissão para os arquivos subordinados.(OI) – The Object Inherit flag propagates permissions to subordinate files.
  • (CI) – O sinalizador de Herança de Contêiner propaga as permissão para as pastas subordinadas.(CI) – The Container Inherit flag propagates permissions to subordinate folders.
  • {PERMISSION FLAGS} – Define as permissões de acesso do aplicativo.{PERMISSION FLAGS} – Sets the app's access permissions.
    • Gravar (W)Write (W)
    • Ler (R)Read (R)
    • Executar (X)Execute (X)
    • Completo (F)Full (F)
    • Modificar (M)Modify (M)
  • /t – Aplique recursivamente aos arquivos e pastas subordinadas existentes./t – Apply recursively to existing subordinate folders and files.

Use o comando a seguir de um shell de comando administrativo do PowerShell 6 para o aplicativo de exemplo publicado na pasta c:\svc e a conta ServiceUser com permissões de gravação/leitura/execução.For the sample app published to the c:\svc folder and the ServiceUser account with write/read/execute permissions, use the following command an administrative PowerShell 6 command shell.

icacls "c:\svc" /grant "ServiceUser:(OI)(CI)WRX" /t

Para obter mais informações, confira icacls.For more information, see icacls.

Criar o serviçoCreate the service

Use o script RegisterService.ps1 do PowerShell para registrar o serviço.Use the RegisterService.ps1 PowerShell script to register the service. Em um shell de comando administrativo do PowerShell 6, execute o script com o seguinte comando:From an administrative PowerShell 6 command shell, execute the script with the following command:

.\RegisterService.ps1 
    -Name {NAME} 
    -DisplayName "{DISPLAY NAME}" 
    -Description "{DESCRIPTION}" 
    -Exe "{PATH TO EXE}\{ASSEMBLY NAME}.exe" 
    -User {DOMAIN\USER}

Observe o seguinte aplicativo de exemplo:In the following example for the sample app:

  • O nome do serviço é MyService.The service is named MyService.
  • O serviço publicado reside na pasta c:\svc.The published service resides in the c:\svc folder. O executável do aplicativo é chamado de SampleApp.exe.The app executable is named SampleApp.exe.
  • O serviço é executado na conta ServiceUser.The service runs under the ServiceUser account. No comando de exemplo a seguir, o nome do computador local é Desktop-PC.In the following example command, the local machine name is Desktop-PC. Substitua Desktop-PC pelo nome do computador ou do domínio do seu sistema.Replace Desktop-PC with the computer name or domain for your system.
.\RegisterService.ps1 
    -Name MyService 
    -DisplayName "My Cool Service" 
    -Description "This is the Sample App service." 
    -Exe "c:\svc\SampleApp.exe" 
    -User Desktop-PC\ServiceUser

Gerenciar o serviçoManage the service

Iniciar o serviçoStart the service

Inicie o serviço com o comando Start-Service -Name {NAME} do PowerShell 6.Start the service with the Start-Service -Name {NAME} PowerShell 6 command.

Para iniciar o serviço de aplicativo de exemplo, use o seguinte comando:To start the sample app service, use the following command:

Start-Service -Name MyService

O comando leva alguns segundos para iniciar o serviço.The command takes a few seconds to start the service.

Determinar o status do serviçoDetermine the service status

Para verificar o status do serviço, use o comando Get-Service -Name {NAME} do PowerShell 6.To check the status of the service, use the Get-Service -Name {NAME} PowerShell 6 command. O status é relatado como um dos seguintes valores:The status is reported as one of the following values:

  • Starting
  • Running
  • Stopping
  • Stopped

Use o seguinte comando para verificar o status do serviço de aplicativo de exemplo:Use the following command to check the status of the sample app service:

Get-Service -Name MyService

Procurar um serviço de aplicativo WebBrowse a web app service

Quando o serviço estiver no estado RUNNING e se o serviço for um aplicativo Web, procure o aplicativo em seu caminho (por padrão, http://localhost:5000, que redireciona para https://localhost:5001 ao usar Middleware de Redirecionamento HTTPS).When the service is in the RUNNING state and if the service is a web app, browse the app at its path (by default, http://localhost:5000, which redirects to https://localhost:5001 when using HTTPS Redirection Middleware).

Para o serviço de aplicativo de exemplo, procure o aplicativo em http://localhost:5000.For the sample app service, browse the app at http://localhost:5000.

Parar o serviçoStop the service

Pare o serviço com o comando Stop-Service -Name {NAME} do PowerShell 6.Stop the service with the Stop-Service -Name {NAME} Powershell 6 command.

O comando a seguir interrompe o serviço de aplicativo de exemplo:The following command stops the sample app service:

Stop-Service -Name MyService

Remover o serviçoRemove the service

Após um pequeno atraso para interromper um serviço, remova o serviço com o comando Remove-Service -Name {NAME} do PowerShell 6.After a short delay to stop a service, remove the service with the Remove-Service -Name {NAME} Powershell 6 command.

O comando a seguir remove o serviço de aplicativo de exemplo:The following command removes the sample app service:

Remove-Service -Name MyService

Manipular eventos de início e de paradaHandle starting and stopping events

Para manipular os eventos OnStarting, OnStarted e OnStopping, faça as seguintes alterações adicionais:To handle OnStarting, OnStarted, and OnStopping events, perform the following additional changes:

  1. Crie uma classe que derive de WebHostService com os métodos OnStarting, OnStarted e OnStopping:Create a class that derives from WebHostService with the OnStarting, OnStarted, and OnStopping methods:

    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. Crie um método de extensão para IWebHost que passe o CustomWebHostService para 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. Em Program.Main, chame o método de extensão RunAsCustomService, em vez de RunAsService:In Program.Main, call the RunAsCustomService extension method instead of RunAsService:

    host.RunAsCustomService();
    

    Para ver o local do RunAsService no Program.Main, consulte o exemplo de código mostrado na seção Converter um projeto em um Serviço Windows.To see the location of RunAsService in Program.Main, refer to the code sample shown in the Convert a project into a Windows Service section.

Servidor proxy e cenários de balanceador de cargaProxy server and load balancer scenarios

Serviços que interagem com solicitações da Internet ou de uma rede corporativa e estão atrás de um proxy ou de um balanceador de carga podem exigir configuração adicional.Services that interact with requests from the Internet or a corporate network and are behind a proxy or load balancer might require additional configuration. Para obter mais informações, consulte Configure o ASP.NET Core para trabalhar com servidores proxy e balanceadores de carga.For more information, see Configure o ASP.NET Core para trabalhar com servidores proxy e balanceadores de carga.

Configurar o HTTPSConfigure HTTPS

Para configurar o serviço com um ponto de extremidade seguro:To configure the service with a secure endpoint:

  1. Crie um certificado X.509 para o sistema de hospedagem usando os mecanismos de implantação e aquisição do certificado da sua plataforma.Create an X.509 certificate for the hosting system using your platform's certificate acquisition and deployment mechanisms.

  2. Especifique uma Configuração do ponto de extremidade HTTPS do servidor Kestrel para usar o certificado.Specify a Kestrel server HTTPS endpoint configuration to use the certificate.

Não há suporte para uso do certificado de desenvolvimento HTTPS do ASP.NET Core para proteger um ponto de extremidade de serviço.Use of the ASP.NET Core HTTPS development certificate to secure a service endpoint isn't supported.

Diretório atual e a raiz do conteúdoCurrent directory and content root

O diretório de trabalho atual retornado ao chamar GetCurrentDirectory de um serviço Windows é a pasta C:\WINDOWS\system32.The current working directory returned by calling GetCurrentDirectory for a Windows Service is the C:\WINDOWS\system32 folder. A pasta system32 não é um local adequado para armazenar os arquivos de um serviço (por exemplo, os arquivos de configurações).The system32 folder isn't a suitable location to store a service's files (for example, settings files). Use uma das seguintes abordagens para manter e acessar ativos e os arquivos de configuração de um serviço.Use one of the following approaches to maintain and access a service's assets and settings files.

Defina o caminho da raiz do conteúdo para a pasta do aplicativoSet the content root path to the app's folder

O ContentRootPath é o mesmo caminho fornecido para o argumento binPath quando o serviço é criado.The ContentRootPath is the same path provided to the binPath argument when the service is created. Em vez de chamar GetCurrentDirectory para criar caminhos para arquivos de configuração, chame SetCurrentDirectory com o caminho para a raiz do conteúdo do aplicativo.Instead of calling GetCurrentDirectory to create paths to settings files, call SetCurrentDirectory with the path to the app's content root.

No Program.Main, determine o caminho para a pasta do executável do serviço e use o caminho para estabelecer a raiz do conteúdo do aplicativo: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();

Armazene os arquivos do serviço em um local adequado no discoStore the service's files in a suitable location on disk

Especifique um caminho absoluto com SetBasePath quando usar um IConfigurationBuilder para a pasta que contém os arquivos.Specify an absolute path with SetBasePath when using an IConfigurationBuilder to the folder containing the files.

Recursos adicionaisAdditional resources