开机自动后台运行,在Windows服务中托管ASP.NET Core

在 Windows 服务中托管 ASP.NET Core

使用 IIS 时,可以在 Windows 上将 ASP.NET Core 应用作为 Windows 服务进行托管。 作为 Windows 服务进行托管时,应用将在服务器重新启动后自动启动。

先决条件

辅助角色服务模板

ASP.NET Core 辅助角色服务模板可作为编写长期服务应用的起点。 要使用该模板作为编写 Windows 服务应用的基础:

  1. 从 .NET Core 模板创建辅助角色服务应用。
  2. 安装 NuGet 包 Microsoft.Extensions.Hosting.WindowsServices
  3. 按照应用配置部分中的指导来更新辅助角色服务应用,以便它可以作为 Windows 服务运行。
  1. 创建新项目。
  2. 选择"辅助角色服务"。 选择"下一步"。
  3. 在"项目名称"字段提供项目名称,或接受默认项目名称。 选择"创建"。
  4. 在"创建辅助角色服务"对话框中,选择"创建"。

应用配置

更新Program.cs以调用 AddWindowsService。 应用作为 Windows 服务运行时,调用 AddWindowsService

  • 将主机生存期设置为 WindowsServiceLifetime
  • 内容根设置为 AppContext.BaseDirectory。 有关详细信息,请参阅当前目录和内容根部分。
  • 为事件日志启用日志记录:
    • 应用名称用作默认源名称。
    • 对于基于 ASP.NET Core 模板且调用 生成主机的应用,默认日志级别为"警告"或更高级别。
    • Logging:EventLog:LogLevel:Default``appsettings.json/ 或其他配置提供程序中,使用 appsettings.{Environment}.json 键覆盖默认日志级别。
    • 只有管理员可以创建新的事件源。 无法使用应用程序名称创建事件源时,应用程序源将记录一条警告,并禁用事件源。

请考虑使用以下 ServiceA 类:

C#复制

cs 复制代码
namespace SampleApp.Services;

public class ServiceA : BackgroundService
{
    public ServiceA(ILoggerFactory loggerFactory)
    {
        Logger = loggerFactory.CreateLogger<ServiceA>();
    }

    public ILogger Logger { get; }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        Logger.LogInformation("ServiceA is starting.");

        stoppingToken.Register(() => Logger.LogInformation("ServiceA is stopping."));

        while (!stoppingToken.IsCancellationRequested)
        {
            Logger.LogInformation("ServiceA is doing background work.");

            await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
        }

        Logger.LogInformation("ServiceA has stopped.");
    }
}

以下 Program.cs 调用 AddHostedService 来注册 ServiceA

C#复制

复制代码
using SampleApp.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddWindowsService();
builder.Services.AddHostedService<ServiceA>();

var app = builder.Build();

app.MapRazorPages();

app.Run();

本主题附带了以下示例应用:

  • 后台辅助角色服务示例:一个基于辅助角色服务模板的非 Web 应用示例,该模板使用托管服务执行后台任务。
  • Web 应用服务示例:一个作为 Windows 服务运行的 Razor Pages Web 应用示例,通过托管服务执行后台任务。

有关 MVC 指南,请参阅 ASP.NET Core MVC 概述从 ASP.NET Core 2.2 迁移到 3.0 下的文章。

部署类型

有关部署方案的信息和建议,请参阅 .NET Core 应用程序部署

SDK

对于使用 Razor Pages 或 MVC 框架的基于 Web 应用的服务,请在项目文件中指定 Web SDK:

XML复制

复制代码
<Project Sdk="Microsoft.NET.Sdk.Web">

如果服务仅执行后台任务(例如 托管服务),请在项目文件中指定辅助角色 SDK:

XML复制

复制代码
<Project Sdk="Microsoft.NET.Sdk.Worker">

依赖框架的部署 (FDD)

依赖框架的部署 (FDD) 依赖目标系统上存在共享系统级版本的 .NET Core。 按照本文中的指南采用 FDD 方案时,SDK 会生成一个称为"依赖框架的可执行文件"的可执行文件 (.exe)。

如果使用 Web SDK,则 web.config 文件(通常在发布 ASP.NET Core 应用时生成)不是 Windows 服务应用的必要文件。 若要禁止创建 web.config 文件,请将 属性集添加到 <IsTransformWebConfigDisabled>

XML复制

复制代码
<PropertyGroup>
  <TargetFramework>net7.0</TargetFramework>
  <IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>
</PropertyGroup>

独立部署 (SCD)

独立部署 (SCD) 不依赖主机系统上存在的共享框架。 运行时和应用的依赖项将与应用一起部署。

将 Windows 运行时标识符 (RID) 添加到包含目标框架的 <PropertyGroup> 中:

XML复制

复制代码
<RuntimeIdentifier>win-x64</RuntimeIdentifier>

要发布多个 RID:

  • 通过以分号分隔的列表提供 RID。
  • 使用属性名称 <RuntimeIdentifiers>(复数)。

有关详细信息,请参阅 .NET Core RID 目录

服务用户帐户

在管理 PowerShell 6 命令行界面中运行 New-LocalUser cmdlet,为服务创建用户帐户。

对于 Windows 10 2018 年 10 月更新(版本 1809/内部版本 10.0.17763)或更高版本:

PowerShell复制

复制代码
New-LocalUser -Name {SERVICE NAME}

对于 Windows 10 2018 年 10 月更新(版本 1809/内部版本 10.0.17763)之前的 Windows 操作系统:

控制台复制

复制代码
powershell -Command "New-LocalUser -Name {SERVICE NAME}"

在系统提示时,提供强密码

除非将 -AccountExpires 参数提供给到期时间为 的 DateTime cmdlet,否则用户帐户不会到期。

有关详细信息,请参阅 Microsoft.PowerShell.LocalAccounts服务用户帐户

使用 Active Directory 时管理用户的另一种方法是使用托管服务帐户。 有关详细信息,请参阅组托管服务帐户概述

以服务身份登录权限

为服务用户帐户创建"以服务身份登录"权限:

  1. 通过运行 secpool.msc,打开本地安全策略编辑器。
  2. 展开"本地策略"节点,选择"用户权限分配"。
  3. 打开"以服务身份登录"策略。
  4. 选择"添加用户或组"。
  5. 使用下列方法之一提供对象名称(用户帐户):
    1. 在对象名称字段键入用户帐户 ({DOMAIN OR COMPUTER NAME\USER}),然后选择"确定",以将此用户添加到策略。
    2. 选择"高级"。 选择"开始查找"。 从列表中选择该用户帐户。 选择"确定"。 再次选择"确定",以将该用户添加到策略。
  6. 选择"确定"或"应用",以接受更改。

创建和管理 Windows 服务

创建服务

使用 PowerShell 注册服务。 从 PowerShell 6 命令行界面,执行以下命令:

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 {SERVICE NAME} -BinaryPathName "{EXE FILE PATH} --contentRoot {EXE FOLDER PATH}" -Credential "{DOMAIN OR COMPUTER NAME\USER}" -Description "{DESCRIPTION}" -DisplayName "{DISPLAY NAME}" -StartupType Automatic
  • {EXE PATH}:应用程序在主机上的可执行文件的路径(例如 d:\myservice)。 不要在路径中包含应用程序的可执行文件名。 尾部反斜杠是非必需项。
  • {DOMAIN OR COMPUTER NAME\USER}:服务用户帐户(如 Contoso\ServiceUser)。
  • {SERVICE NAME}:服务名称(如 MyService)。
  • {EXE FILE PATH}:应用程序的完整可执行文件路径(例如 d:\myservice\myservice.exe)。 请将可执行文件的文件名和扩展名包括在内。
  • {EXE FOLDER PATH}:应用程序的完整可执行文件夹路径(例如 d:\myservice)。
  • {DESCRIPTION}:服务说明(如 My sample service)。
  • {DISPLAY NAME}:服务显示名称(如 My Service)。

启动服务

使用以下 PowerShell 6 命令启动服务:

复制代码
Start-Service -Name {SERVICE NAME}

此命令需要几秒钟才能启动服务。

确信服务状态

要检查服务的状态,请使用以下 PowerShell 6 命令:

PowerShell复制

复制代码
Get-Service -Name {SERVICE NAME}

状态报告为以下值之一:

  • Starting
  • Running
  • Stopping
  • Stopped

停止服务

使用以下 PowerShell 6 命令停止服务:

PowerShell复制

复制代码
Stop-Service -Name {SERVICE NAME}

删除服务

在停止服务一小段时间后,使用以下 PowerShell 6 命令删除服务:

PowerShell复制

复制代码
Remove-Service -Name {SERVICE NAME}

代理服务器和负载均衡器方案

与来自 Internet 或公司网络的请求进行交互且在代理或负载均衡器后方的服务可能需要其他配置。 有关详细信息,请参阅配置 ASP.NET Core 以使用代理服务器和负载均衡器

配置终结点

默认情况下,ASP.NET Core 绑定到 http://localhost:5000。 通过设置 ASPNETCORE_URLS 环境变量来配置 URL 和端口。

有关其他 URL 和端口配置方法,请参阅相关服务器文章:

上述指南介绍了对 HTTPS 终结点的支持。 例如,在使用 Windows 服务进行身份验证时,为 HTTPS 配置应用。

备注

不支持使用 ASP.NET Core HTTPS 开发证书保护服务终结点。

当前目录和内容根

通过为 Windows 服务调用 GetCurrentDirectory 返回的当前工作目录是 C:\WINDOWS\system32 文件夹。 system32 文件夹不是存储服务文件(如设置文件)的合适位置。 使用以下方法之一来维护和访问服务的资产和设置文件。

使用 ContentRootPath 或 ContentRootFileProvider

使用 IHostEnvironment.ContentRootPathContentRootFileProvider 查找应用的资源。

应用作为服务运行时,UseWindowsServiceContentRootPath 设置为 AppContext.BaseDirectory

通过appsettings.json,从应用的内容根加载应用的默认设置文件 appsettings.{Environment}.json 和 。

对于 ConfigureAppConfiguration 中的开发人员代码加载的其他设置文件,无需调用 SetBasePath。 在下面的示例中,custom_settings.json 文件位于应用的内容根,加载它时未显式设置基本路径:

C#复制

复制代码
public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseWindowsService()
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddJsonFile("custom_settings.json");
            })
            .ConfigureServices((hostContext, services) =>
            {
                services.AddHostedService<Worker>();
            });
}

请勿尝试使用 GetCurrentDirectory 来获取资源路径,因为 Windows 服务应用会返回"C:\WINDOWS\system32"文件夹作为其当前目录。

将服务的文件存储在磁盘中的合适位置

使用 SetBasePath 时,使用 IConfigurationBuilder 指定到包含文件的文件夹的绝对路径。

疑难解答

若要对 Windows 服务应用进行故障排除,请参阅 ASP.NET Core 项目故障排除和调试

常见错误

  • 正在使用 PowerShell 的早期版本或预发布版本。
  • 注册的服务未使用来自 dotnet publish 命令的应用的已发布输出。 应用部署不支持 dotnet build 命令的输出。 已发布的资产位于以下文件夹之一中,具体取决于部署类型:
    • bin/Release/{TARGET FRAMEWORK}/publish (FDD)
    • bin/Release/{TARGET FRAMEWORK}/{RUNTIME IDENTIFIER}/publish (SCD)
  • 服务未处于"正在运行"状态。
  • 应用使用的资源(例如证书)的路径不正确。 Windows 服务的基本路径是"c:\Windows\System32"。
  • 用户没有"以服务身份登录"权限。
  • 在执行 New-Service PowerShell 命令时,用户密码已过期,或以不正确的方式传递。
  • 应用需要进行 ASP.NET Core 身份验证,但是未配置安全连接 (HTTPS)。
  • 请求 URL 端口不正确或未在应用中正确配置。

系统和应用程序事件日志

访问系统和应用程序事件日志:

  1. 打开"开始"菜单,搜索"事件查看器",然后选择"事件查看器"应用。
  2. 在"事件查看器"中,打开"Windows 日志"节点。
  3. 选择"系统",以打开系统事件日志。 选择"应用程序"以打开应用程序事件日志。
  4. 搜索与失败应用相关联的错误。

在命令提示符处运行应用

许多启动错误未在事件日志中生成有用信息。 可以通过在托管系统上在命令提示符处运行应用来找到某些错误的原因。 若要记录应用中的其他详细信息,则降低日志级别,或在开发环境中运行此应用。

清除包缓存

正常运行的应用在开发计算机上升级 .NET Core SDK 或在应用内更改包版本后可能会立即出现故障。 在某些情况下,不同的包可能在执行主要升级时中断应用。 可以按照以下说明来修复其中大部分问题:

  1. 删除 bin 和 obj 文件夹。

  2. 通过从命令行界面执行 dotnet nuget locals all --clear 清除包缓存。

    清除包缓存还可通过使用 nuget.exe 工具并执行命令 nuget locals all -clear 来完成。 nuget.exe 不是与 Windows 桌面操作系统的捆绑安装,必须从 NuGet 网站中单独获取。

  3. 还原并重新生成项目。

  4. 在重新部署应用前,在服务器上删除部署文件夹中的所有文件。

应用缓慢或无响应

故障转储是系统内存的一个快照,可帮助确定应用崩溃、启动故障或应用速度缓慢等状况的原因。

应用崩溃或引发异常

Windows 错误报告 (WER) 中获取转储并进行分析:

  1. 创建文件夹,将崩溃转储文件保存在 c:\dumps

  2. 使用应用程序可执行文件名称运行 EnableDumps PowerShell 脚本

    复制代码
    .\EnableDumps {APPLICATION EXE} c:\dumps
  3. 在造成崩溃的条件下运行应用。

  4. 出现崩溃后,运行 DisableDumps PowerShell 脚本

    复制代码
    .\DisableDumps {APPLICATION EXE}

在应用崩溃并完成转储收集后,即可正常终止应用。 PowerShell 脚本会 WER 来按应用收集转储(最多收集 5 个)。

警告 崩溃转储可能会占用大量磁盘空间(每个最多占用数 GB)。

应用无响应、在启动期间失败或正常运行

如果应用停止响应但不崩溃、在启动期间失败或者正常运行,请参阅用户模式转储文件:选择最佳工具,以选择适合用于生成转储的工具。

分析转储

可采用几种方法来分析转储。 有关详细信息,请参阅分析用户模式转储文件

其他资源

相关推荐
SimonKing23 分钟前
无需重启!动态修改日志级别的神技,运维开发都哭了
java·后端·程序员
架构精进之路42 分钟前
多智能体系统不是银弹
后端·架构·aigc
涡能增压发动积1 小时前
MySQL数据库为何逐渐黯淡,PostgreSQL为何能新王登基
人工智能·后端
架构精进之路2 小时前
多智能体系统架构解析
后端·架构·ai编程
Java中文社群2 小时前
重磅!Ollama发布UI界面,告别命令窗口!
java·人工智能·后端
程序员清风2 小时前
程序员代码有Bug别怕,人生亦是如此!
java·后端·面试
就是帅我不改2 小时前
告别996!高可用低耦合架构揭秘:SpringBoot + RabbitMQ 让订单系统不再崩
java·后端·面试
用户6120414922132 小时前
C语言做的区块链模拟系统(极简版)
c语言·后端·敏捷开发
Mintopia3 小时前
🎬《Next 全栈 CRUD 的百老汇》
前端·后端·next.js