--- title: Host ASP.NET Core in a Windows Service author: guardrex description: Learn how to host an ASP.NET Core app in a Windows Service. monikerRange: '>= aspnetcore-2.1' ms.author: tdykstra ms.custom: mvc ms.date: 06/03/2019 uid: host-and-deploy/windows-service --- # Host ASP.NET Core in a Windows Service By [Luke Latham](https://github.com/guardrex) and [Tom Dykstra](https://github.com/tdykstra) An ASP.NET Core app can be hosted on Windows as a [Windows Service](/dotnet/framework/windows-services/introduction-to-windows-service-applications) without using IIS. When hosted as a Windows Service, the app automatically starts after server reboots. [View or download sample code](https://github.com/aspnet/AspNetCore.Docs/tree/master/aspnetcore/host-and-deploy/windows-service/) ([how to download](xref:index#how-to-download-a-sample)) ## Prerequisites * [ASP.NET Core SDK 2.1 or later](https://dotnet.microsoft.com/download) * [PowerShell 6.2 or later](https://github.com/PowerShell/PowerShell) ::: moniker range=">= aspnetcore-3.0" ## Worker Service template The ASP.NET Core Worker Service template provides a starting point for writing long running service apps. To use the template as a basis for a Windows Service app: 1. Create a Worker Service app from the .NET Core template. 1. Follow the guidance in the [App configuration](#app-configuration) section to update the Worker Service app so that it can run as a Windows Service. # [Visual Studio](#tab/visual-studio) 1. Create a new project. 1. Select **ASP.NET Core Web Application**. Select **Next**. 1. Provide a project name in the **Project name** field or accept the default project name. Select **Create**. 1. In the **Create a new ASP.NET Core Web Application** dialog, confirm that **.NET Core** and **ASP.NET Core 3.0** are selected. 1. Select the **Worker Service** template. Select **Create**. # [Visual Studio Code / .NET Core CLI](#tab/visual-studio-code+netcore-cli) Use the Worker Service (`worker`) template with the [dotnet new](/dotnet/core/tools/dotnet-new) command from a command shell. In the following example, a Worker Service app is created named `ContosoWorkerService`. A folder for the `ContosoWorkerService` app is created automatically when the command is executed. ```console dotnet new worker -o ContosoWorkerService ``` --- ::: moniker-end ## App configuration ::: moniker range=">= aspnetcore-3.0" `IHostBuilder.UseWindowsService`, provided by the [Microsoft.Extensions.Hosting.WindowsServices](https://www.nuget.org/packages/Microsoft.Extensions.Hosting.WindowsServices) package, is called when building the host. If the app is running as a Windows Service, the method: * 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. * 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. [!code-csharp[](windows-service/samples/3.x/AspNetCoreService/Program.cs?name=snippet_Program)] ::: moniker-end ::: moniker range="< aspnetcore-3.0" The app requires package references for [Microsoft.AspNetCore.Hosting.WindowsServices](https://www.nuget.org/packages/Microsoft.AspNetCore.Hosting.WindowsServices) and [Microsoft.Extensions.Logging.EventLog](https://www.nuget.org/packages/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. Inspect if the debugger is attached or a `--console` switch is present. If either condition is true (the app isn't run as a service), call . If the conditions are false (the app is run as a service): * Call and use a path to the app's published location. Don't call to obtain the path because a Windows Service app returns the *C:\\WINDOWS\\system32* folder when is called. For more information, see the [Current directory and content root](#current-directory-and-content-root) section. This step is performed before the app is configured in `CreateWebHostBuilder`. * Call to run the app as a service. Because the [Command-line Configuration Provider](xref:fundamentals/configuration/index#command-line-configuration-provider) requires name-value pairs for command-line arguments, the `--console` switch is removed from the arguments before receives the arguments. To write to the Windows Event Log, add the EventLog provider to . Set the logging level with the `Logging:LogLevel:Default` key in the *appsettings.Production.json* file. In the following example from the sample app, `RunAsCustomService` is called instead of in order to handle lifetime events within the app. For more information, see the [Handle starting and stopping events](#handle-starting-and-stopping-events) section. [!code-csharp[](windows-service/samples/2.x/AspNetCoreService/Program.cs?name=snippet_Program)] ::: moniker-end ## Deployment type For information and advice on deployment scenarios, see [.NET Core application deployment](/dotnet/core/deploying/). ### Framework-dependent deployment (FDD) Framework-dependent deployment (FDD) relies on the presence of a shared system-wide version of .NET Core on the target system. When the FDD scenario is adopted following the guidance in this article, the SDK produces an executable (*.exe*), called a *framework-dependent executable*. ::: moniker range=">= aspnetcore-3.0" Add the following property elements to the project file: * `` – The app's output type (`Exe` for executable). * `` – The C# language version (`latest` or `preview`). A *web.config* file, which is normally produced when publishing an ASP.NET Core app, is unnecessary for a Windows Services app. To disable the creation of the *web.config* file, add the `` property set to `true`. ```xml netcoreapp3.0 Exe preview true ``` ::: moniker-end ::: moniker range="= aspnetcore-2.2" The Windows [Runtime Identifier (RID)](/dotnet/core/rid-catalog) ([\](/dotnet/core/tools/csproj#runtimeidentifier)) contains the target framework. In the following example, the RID is set to `win7-x64`. The `` property is set to `false`. These properties instruct the SDK to generate an executable (*.exe*) file for Windows and an app that depends on the shared .NET Core framework. A *web.config* file, which is normally produced when publishing an ASP.NET Core app, is unnecessary for a Windows Services app. To disable the creation of the *web.config* file, add the `` property set to `true`. ```xml netcoreapp2.2 win7-x64 false true ``` ::: moniker-end ::: moniker range="= aspnetcore-2.1" The Windows [Runtime Identifier (RID)](/dotnet/core/rid-catalog) ([\](/dotnet/core/tools/csproj#runtimeidentifier)) contains the target framework. In the following example, the RID is set to `win7-x64`. The `` property is set to `false`. These properties instruct the SDK to generate an executable (*.exe*) file for Windows and an app that depends on the shared .NET Core framework. The `` property is set to `true`. This property provides the service with an activation path (an executable, *.exe*) for an FDD. A *web.config* file, which is normally produced when publishing an ASP.NET Core app, is unnecessary for a Windows Services app. To disable the creation of the *web.config* file, add the `` property set to `true`. ```xml netcoreapp2.1 win7-x64 true false true ``` ::: moniker-end ### 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. A Windows [Runtime Identifier (RID)](/dotnet/core/rid-catalog) is included in the `` that contains the target framework: ```xml win7-x64 ``` To publish for multiple RIDs: * Provide the RIDs in a semicolon-delimited list. * Use the property name [\](/dotnet/core/tools/csproj#runtimeidentifiers) (plural). For more information, see [.NET Core RID Catalog](/dotnet/core/rid-catalog). ::: moniker range="< aspnetcore-3.0" A `` property is set to `true`: ```xml true ``` ::: moniker-end ## Service user account To create a user account for a service, use the [New-LocalUser](/powershell/module/microsoft.powershell.localaccounts/new-localuser) cmdlet from an administrative PowerShell 6 command shell. On Windows 10 October 2018 Update (version 1809/build 10.0.17763) or later: ```PowerShell New-LocalUser -Name {NAME} ``` On Windows OS earlier than the Windows 10 October 2018 Update (version 1809/build 10.0.17763): ```console powershell -Command "New-LocalUser -Name {NAME}" ``` Provide a [strong password](/windows/security/threat-protection/security-policy-settings/password-must-meet-complexity-requirements) when prompted. Unless the `-AccountExpires` parameter is supplied to the [New-LocalUser](/powershell/module/microsoft.powershell.localaccounts/new-localuser) cmdlet with an expiration , the account doesn't expire. For more information, see [Microsoft.PowerShell.LocalAccounts](/powershell/module/microsoft.powershell.localaccounts/) and [Service User Accounts](/windows/desktop/services/service-user-accounts). 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](/windows-server/security/group-managed-service-accounts/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. Open the Local Security Policy editor by running *secpool.msc*. 1. Expand the **Local Policies** node and select **User Rights Assignment**. 1. Open the **Log on as a service** policy. 1. Select **Add User or Group**. 1. Provide the object name (user account) using either of the following approaches: 1. Type the user account (`{DOMAIN OR COMPUTER NAME\USER}`) in the object name field and select **OK** to add the user to the policy. 1. Select **Advanced**. Select **Find Now**. Select the user account from the list. Select **OK**. Select **OK** again to add the user to the policy. 1. Select **OK** or **Apply** to accept the changes. ## Create and manage the Windows Service ### Create a service Use PowerShell commands to register a service. From an administrative PowerShell 6 command shell, execute the following commands: ```powershell $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}` – 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}` – Service user account (for example, `Contoso\ServiceUser`). * `{NAME}` – Service name (for example, `MyService`). * `{EXE FILE PATH}` – The app's executable path (for example, `d:\myservice\myservice.exe`). Include the executable's file name with extension. * `{DESCRIPTION}` – Service description (for example, `My sample service`). * `{DISPLAY NAME}` – Service display name (for example, `My Service`). ### Start a service Start a service with the following PowerShell 6 command: ```powershell Start-Service -Name {NAME} ``` The command takes a few seconds to start the service. ### Determine a service's status To check the status of a service, use the following PowerShell 6 command: ```powershell Get-Service -Name {NAME} ``` The status is reported as one of the following values: * `Starting` * `Running` * `Stopping` * `Stopped` ### Stop a service Stop a service with the following Powershell 6 command: ```powershell Stop-Service -Name {NAME} ``` ### Remove a service After a short delay to stop a service, remove a service with the following Powershell 6 command: ```powershell Remove-Service -Name {NAME} ``` ::: moniker range="< aspnetcore-3.0" ## Handle starting and stopping events To handle , , and events: 1. Create a class that derives from with the `OnStarting`, `OnStarted`, and `OnStopping` methods: [!code-csharp[](windows-service/samples/2.x/AspNetCoreService/CustomWebHostService.cs?name=snippet_CustomWebHostService)] 2. Create an extension method for that passes the `CustomWebHostService` to : [!code-csharp[](windows-service/samples/2.x/AspNetCoreService/WebHostServiceExtensions.cs?name=ExtensionsClass)] 3. In `Program.Main`, call the `RunAsCustomService` extension method instead of : ```csharp host.RunAsCustomService(); ``` To see the location of in `Program.Main`, refer to the code sample shown in the [Deployment type](#deployment-type) section. ::: moniker-end ## 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. For more information, see . ## Configure HTTPS To configure a service with a secure endpoint: 1. Create an X.509 certificate for the hosting system using your platform's certificate acquisition and deployment mechanisms. 1. Specify a [Kestrel server HTTPS endpoint configuration](xref:fundamentals/servers/kestrel#endpoint-configuration) to use the certificate. Use of the ASP.NET Core HTTPS development certificate to secure a service endpoint isn't supported. ## Current directory and content root The current working directory returned by calling for a Windows Service is the *C:\\WINDOWS\\system32* folder. 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. ::: moniker range=">= aspnetcore-3.0" ### Use ContentRootPath or ContentRootFileProvider Use [IHostEnvironment.ContentRootPath](xref:Microsoft.Extensions.Hosting.IHostEnvironment.ContentRootPath) or to locate an app's resources. ::: moniker-end ::: moniker range="< aspnetcore-3.0" ### Set the content root path to the app's folder The is the same path provided to the `binPath` argument when a service is created. Instead of calling `GetCurrentDirectory` to create paths to settings files, call with the path to the app's content root. 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: ```csharp var pathToExe = Process.GetCurrentProcess().MainModule.FileName; var pathToContentRoot = Path.GetDirectoryName(pathToExe); Directory.SetCurrentDirectory(pathToContentRoot); CreateWebHostBuilder(args) .Build() .RunAsService(); ``` ::: moniker-end ### Store a service's files in a suitable location on disk Specify an absolute path with when using an to the folder containing the files. ## Additional resources ::: moniker range=">= aspnetcore-3.0" * [Kestrel endpoint configuration](xref:fundamentals/servers/kestrel#endpoint-configuration) (includes HTTPS configuration and SNI support) * * ::: moniker-end ::: moniker range="< aspnetcore-3.0" * [Kestrel endpoint configuration](xref:fundamentals/servers/kestrel#endpoint-configuration) (includes HTTPS configuration and SNI support) * * ::: moniker-end