AspNetCore.Docs/aspnetcore/host-and-deploy/windows-service.md

238 lines
11 KiB
Markdown
Raw Normal View History

---
title: Host ASP.NET Core in a Windows Service
2018-06-09 11:27:43 +08:00
author: guardrex
description: Learn how to host an ASP.NET Core app in a Windows Service.
2018-01-29 23:21:31 +08:00
ms.author: tdykstra
ms.custom: mvc
2018-06-09 11:27:43 +08:00
ms.date: 06/04/2018
uid: host-and-deploy/windows-service
---
# Host ASP.NET Core in a Windows Service
2018-06-09 11:27:43 +08:00
By [Luke Latham](https://github.com/guardrex) and [Tom Dykstra](https://github.com/tdykstra)
2018-06-09 11:27:43 +08:00
An ASP.NET Core app can be hosted on Windows without using IIS as a [Windows Service](/dotnet/framework/windows-services/introduction-to-windows-service-applications). When hosted as a Windows Service, the app can automatically start after reboots and crashes without requiring human intervention.
2018-07-10 23:05:42 +08:00
[View or download sample code](https://github.com/aspnet/Docs/tree/master/aspnetcore/host-and-deploy/windows-service/samples) ([how to download](xref:tutorials/index#how-to-download-a-sample))
2018-06-09 11:27:43 +08:00
## Get started
2018-06-09 11:27:43 +08:00
The following minimum changes are required to set up an existing ASP.NET Core project to run in a service:
1. In the project file:
1. Confirm the presence of the runtime identifier or add it to the **\<PropertyGroup>** that contains the target framework:
2018-07-10 23:05:42 +08:00
::: moniker range=">= aspnetcore-2.1"
```xml
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeIdentifier>win7-x64</RuntimeIdentifier>
</PropertyGroup>
```
2018-07-10 23:05:42 +08:00
::: moniker-end
::: moniker range="= aspnetcore-2.0"
```xml
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<RuntimeIdentifier>win7-x64</RuntimeIdentifier>
</PropertyGroup>
```
::: moniker-end
::: moniker range="< aspnetcore-2.0"
```xml
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
<RuntimeIdentifier>win7-x64</RuntimeIdentifier>
</PropertyGroup>
```
::: moniker-end
1. Add a package reference for [Microsoft.AspNetCore.Hosting.WindowsServices](https://www.nuget.org/packages/Microsoft.AspNetCore.Hosting.WindowsServices/).
2018-06-09 11:27:43 +08:00
1. Make the following changes in `Program.Main`:
2018-06-09 11:27:43 +08:00
* Call [host.RunAsService](/dotnet/api/microsoft.aspnetcore.hosting.windowsservices.webhostwindowsserviceextensions.runasservice) instead of `host.Run`.
* Call [UseContentRoot](xref:fundamentals/host/web-host#content-root) and use a path to the app's published location instead of `Directory.GetCurrentDirectory()`.
2018-06-09 11:27:43 +08:00
::: moniker range=">= aspnetcore-2.0"
[!code-csharp[](windows-service/samples/2.x/AspNetCoreService/Program.cs?name=ServiceOnly&highlight=8-9,16)]
2018-06-09 11:27:43 +08:00
::: moniker-end
2018-04-05 07:51:35 +08:00
2018-06-09 11:27:43 +08:00
::: moniker range="< aspnetcore-2.0"
2018-07-10 23:05:42 +08:00
[!code-csharp[](windows-service/samples_snapshot/1.x/AspNetCoreService/Program.cs?name=ServiceOnly&highlight=3-4,8,13)]
2018-06-09 11:27:43 +08:00
::: moniker-end
2018-05-11 08:58:40 +08:00
2018-07-29 06:50:01 +08:00
1. Publish the app. Use [dotnet publish](/dotnet/articles/core/tools/dotnet-publish) or a [Visual Studio publish profile](xref:host-and-deploy/visual-studio-publish-profiles). When using a Visual Studio, select the **FolderProfile**.
2018-06-09 11:27:43 +08:00
To publish the sample app from the command line, run the following command in a console window from the project folder:
2018-05-11 08:58:40 +08:00
2018-06-09 11:27:43 +08:00
```console
dotnet publish --configuration Release
2018-06-09 11:27:43 +08:00
```
1. Use the [sc.exe](https://technet.microsoft.com/library/bb490995) command-line tool to create the service. The `binPath` value is the path to the app's executable, which includes the executable file name. **The space between the equal sign and the quote character at the start of the path is required.**
```console
sc create <SERVICE_NAME> binPath= "<PATH_TO_SERVICE_EXECUTABLE>"
```
2018-07-29 06:50:01 +08:00
For a service published in the project folder, use the path to the *publish* folder to create the service. In the following example:
2018-07-29 06:50:01 +08:00
* The project resides in the `c:\my_services\AspNetCoreService` folder.
* The project is published in `Release` configuration.
* The Target Framework Moniker (TFM) is `netcoreapp2.1`.
* The Runtime Identifer (RID) is `win7-x64`.
* The app executable is named *AspNetCoreService.exe*.
* The service is named **MyService**.
2018-07-29 06:50:01 +08:00
Example:
2018-06-09 11:27:43 +08:00
```console
2018-07-29 06:50:01 +08:00
sc create MyService binPath= "c:\my_services\AspNetCoreService\bin\Release\netcoreapp2.1\win7-x64\publish\AspNetCoreService.exe"
2018-06-09 11:27:43 +08:00
```
> [!IMPORTANT]
> Make sure the space is present between the `binPath=` argument and its value.
To publish and start the service from a different folder:
2018-07-29 06:50:01 +08:00
1. Use the [--output &lt;OUTPUT_DIRECTORY&gt;](/dotnet/core/tools/dotnet-publish#options) option on the `dotnet publish` command. If using Visual Studio, configure the **Target Location** in the **FolderProfile** publish property page before selecting the **Publish** button.
1. Create the service with the `sc.exe` command using the output folder path. Include the name of the service's executable in the path provided to `binPath`.
2018-06-09 11:27:43 +08:00
1. Start the service with the `sc start <SERVICE_NAME>` command.
To start the sample app service, use the following command:
```console
sc start MyService
```
2018-06-09 11:27:43 +08:00
The command takes a few seconds to start the service.
1. The `sc query <SERVICE_NAME>` command can be used to check the status of the service to determine its status:
* `START_PENDING`
* `RUNNING`
* `STOP_PENDING`
* `STOPPED`
Use the following command to check the status of the sample app service:
```console
sc query MyService
```
1. 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](xref:security/enforcing-ssl)).
2018-06-09 11:27:43 +08:00
For the sample app service, browse the app at `http://localhost:5000`.
2018-06-09 11:27:43 +08:00
1. Stop the service with the `sc stop <SERVICE_NAME>` command.
2018-06-09 11:27:43 +08:00
The following command stops the sample app service:
```console
sc stop MyService
```
1. After a short delay to stop a service, uninstall the service with the `sc delete <SERVICE_NAME>` command.
Check the status of the sample app service:
```console
sc query MyService
```
When the sample app service is in the `STOPPED` state, use the following command to uninstall the sample app service:
```console
sc delete MyService
```
## Provide a way to run outside of a service
It's easier to test and debug when running outside of a service, so it's customary to add code that calls `RunAsService` only under certain conditions. For example, the app can run as a console app with a `--console` command-line argument or if the debugger is attached:
2018-06-09 11:27:43 +08:00
::: moniker range=">= aspnetcore-2.0"
2018-05-11 08:58:40 +08:00
2018-07-10 23:05:42 +08:00
[!code-csharp[](windows-service/samples/2.x/AspNetCoreService/Program.cs?name=ServiceOrConsole)]
2018-06-09 11:27:43 +08:00
Because ASP.NET Core configuration requires name-value pairs for command-line arguments, the `--console` switch is removed before the arguments are passed to [CreateDefaultBuilder](/dotnet/api/microsoft.aspnetcore.webhost.createdefaultbuilder).
2018-07-10 23:05:42 +08:00
> [!NOTE]
> `isService` isn't passed from `Main` into `CreateWebHostBuilder` because the signature of `CreateWebHostBuilder` must be `CreateWebHostBuilder(string[])` in order for [integration testing](xref:test/integration-tests) to work properly.
2018-06-09 11:27:43 +08:00
::: moniker-end
::: moniker range="< aspnetcore-2.0"
2018-05-11 08:58:40 +08:00
2018-07-10 23:05:42 +08:00
[!code-csharp[](windows-service/samples_snapshot/1.x/AspNetCoreService/Program.cs?name=ServiceOrConsole)]
2018-06-09 11:27:43 +08:00
::: moniker-end
2018-05-11 08:58:40 +08:00
## Handle stopping and starting events
2018-06-09 11:27:43 +08:00
To handle [OnStarting](/dotnet/api/microsoft.aspnetcore.hosting.windowsservices.webhostservice.onstarting), [OnStarted](/dotnet/api/microsoft.aspnetcore.hosting.windowsservices.webhostservice.onstarted), and [OnStopping](/dotnet/api/microsoft.aspnetcore.hosting.windowsservices.webhostservice.onstopping) events, make the following additional changes:
2018-06-09 11:27:43 +08:00
1. Create a class that derives from [WebHostService](/dotnet/api/microsoft.aspnetcore.hosting.windowsservices.webhostservice):
2018-07-10 23:05:42 +08:00
[!code-csharp[](windows-service/samples/2.x/AspNetCoreService/CustomWebHostService.cs?name=NoLogging)]
2018-06-09 11:27:43 +08:00
2. Create an extension method for [IWebHost](/dotnet/api/microsoft.aspnetcore.hosting.iwebhost) that passes the custom `WebHostService` to [ServiceBase.Run](/dotnet/api/system.serviceprocess.servicebase.run):
2018-07-10 23:05:42 +08:00
[!code-csharp[](windows-service/samples/2.x/AspNetCoreService/WebHostServiceExtensions.cs?name=ExtensionsClass)]
2018-06-09 11:27:43 +08:00
3. In `Program.Main`, call the new extension method, `RunAsCustomService`, instead of [RunAsService](/dotnet/api/microsoft.aspnetcore.hosting.windowsservices.webhostwindowsserviceextensions.runasservice):
::: moniker range=">= aspnetcore-2.0"
[!code-csharp[](windows-service/samples/2.x/AspNetCoreService/Program.cs?name=HandleStopStart&highlight=17)]
2018-07-10 23:05:42 +08:00
> [!NOTE]
> `isService` isn't passed from `Main` into `CreateWebHostBuilder` because the signature of `CreateWebHostBuilder` must be `CreateWebHostBuilder(string[])` in order for [integration testing](xref:test/integration-tests) to work properly.
2018-05-11 08:58:40 +08:00
2018-06-09 11:27:43 +08:00
::: moniker-end
2018-06-09 11:27:43 +08:00
::: moniker range="< aspnetcore-2.0"
2018-05-11 08:58:40 +08:00
2018-07-10 23:05:42 +08:00
[!code-csharp[](windows-service/samples_snapshot/1.x/AspNetCoreService/Program.cs?name=HandleStopStart&highlight=27)]
2018-06-09 11:27:43 +08:00
::: moniker-end
2018-05-11 08:58:40 +08:00
2018-06-09 11:27:43 +08:00
If the custom `WebHostService` code requires a service from dependency injection (such as a logger), obtain it from the [IWebHost.Services](/dotnet/api/microsoft.aspnetcore.hosting.iwebhost.services) property:
2018-07-10 23:05:42 +08:00
[!code-csharp[](windows-service/samples/2.x/AspNetCoreService/CustomWebHostService.cs?name=Logging&highlight=7-8)]
## 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 <xref:host-and-deploy/proxy-load-balancer>.
2018-08-01 08:42:13 +08:00
## Configure HTTPS
Specify a [Kestrel server HTTPS endpoint configuration](xref:fundamentals/servers/kestrel#endpoint-configuration).
## Current directory and content root
The current working directory returned by calling `Directory.GetCurrentDirectory()` 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 with [FileConfigurationExtensions.SetBasePath](/dotnet/api/microsoft.extensions.configuration.fileconfigurationextensions.setbasepath) when using an [IConfigurationBuilder](/dotnet/api/microsoft.extensions.configuration.iconfigurationbuilder):
* Use the content root path. The `IHostingEnvironment.ContentRootPath` is the same path provided to the `binPath` argument when the service is created. Instead of using `Directory.GetCurrentDirectory()` to create paths to settings files, use the content root path and maintain the files in the app's content root.
* Store the files in a suitable location on disk. Specify an absolute path with `SetBasePath` to the folder containing the files.
## Additional resources
* [Kestrel endpoint configuration](xref:fundamentals/servers/kestrel#endpoint-configuration) (includes HTTPS configuration and SNI support)
* <xref:fundamentals/host/web-host>