使用 Topshelf 轻松创建 Windows 服务






4.24/5 (11投票s)
.NET Core 中创建 Windows 服务的简短教程 - 包含计划任务/实体框架核心/托管 WebApi 的示例
引言
这些示例的核心库是 Topshelf。它提供了一种非常简单的方式来入门 winservice。本文包含 winservice 的示例,这些 winservice 应该执行计划任务或运行 RestApi。
所有示例都使用依赖注入,如果您不熟悉它,这里有一些关于依赖注入和 Autofac 框架的进一步阅读材料。
入门
- 所有示例均基于 .NET Core 3.1
示例 1 - 基本 winservice
- 查看 Github: BasicWinservice
所需的 NuGet 包
- Topshelf
- Topshelf.Autofac
Topshelf
- 执行 EXE 将在控制台中运行服务
- 可以通过 cmd.exe (以管理员身份运行) 安装 Windowsservice - Service.exe install
- 卸载使用 Service.exe uninstall
Bootstrap.cs
此类用于注册依赖注入的类型。在此示例中,必须注册包含服务逻辑的 BasicService。
示例 2 - Scheduledservice
- 查看 Github: ScheduledWinservice
所需的 NuGet 包
Topshelf
- 执行 EXE 将在控制台中运行服务
- 可以通过 cmd.exe (以管理员身份运行) 安装 Windowsservice - Service.exe install
- 卸载使用 Service.exe uninstall
Bootstrap.cs
此类用于注册依赖注入的类型。
- 注册 Servicecontrollers
- 注册 IConfiguration- 提供读取 appsettings.json
- 注册设置 - 便于访问配置的助手类
- 注册 QuartzModule
- 注册控制器
Quartz
日志记录
如果作业未执行,请开启 Quartz 的日志记录。QuartzConsoleLogProvider.cs 实现了一个记录到控制台的日志记录器。
注册日志提供程序
LogProvider.SetCurrentLogProvider(new QuartzConsoleLogProvider());
作业
Job 是您的服务应该运行的任务。这些必须实现 IJob 接口。如果此作业需要其他数据,您可以使用 JobDataMap。(参见 «QuartzController.cs» 和 MyJob.cs)
触发器
Quarzt 提供了一些在特定时间执行作业的触发器。示例包含在 QuartzController.cs 中
- 执行一次作业。
- 按间隔执行作业。
- 从队列中删除作业。
示例 3 - ScheduledEFCoreWinservice
- 查看 Github: ScheduledEFCoreWinservice
所需的 NuGet 包
- Topshelf
- Topshelf.Autofac
- Quartz
- Autofac.Extras.Quartz
- Microsoft.Extensions.Configuration.Json
- Microsoft.EntityFrameworkCore
- Microsoft.EntityFrameworkCore.SqlServer
- Microsoft.EntityFrameworkCore.Tools
Topshelf
- 执行 EXE 将在控制台中运行服务
- 可以通过 cmd.exe (以管理员身份运行) 安装 Windowsservice - Service.exe install
- 卸载使用 Service.exe uninstall
Bootstrap.cs
此类用于注册依赖注入的类型。
- 注册 Servicecontrollers
- 注册 IConfiguration- 提供读取 appsettings.json
- 注册设置 - Helperclass便于访问配置
- 注册 QuartzModule
- 注册 Controller
- 注册数据库上下文
EF Core 与依赖注入
数据库
示例数据库是免费的 Ip2Location 数据库 的导入。有关下载和导入 MS-SQL 的说明,请查看以下链接:IP2Location™ LITE IP-COUNTRY 数据库。
Bootstrap
InstancePerLifetimeScope - 上下文将为每个作业创建,并在作业完成后将其处理。
builder.RegisterType<ip2locationContext>().InstancePerLifetimeScope();
builder.RegisterType<ip2locationWriteContext>().InstancePerLifetimeScope();
背景
由于构造函数 ip2locationContext(IConfiguration configuration),配置将自动注入。配置用于读取连接字符串。
public partial class ip2locationContext : DbContext
{
    protected readonly IConfiguration _configuration;
    public ip2locationContext(IConfiguration configuration)
    {
        _configuration = configuration;
    }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {
            optionsBuilder.UseSqlServer(_configuration.GetConnectionString("CTX"));
        }
    }
}
ip2locationContextFactory
如果您想要 EF-Core 迁移,您应该实现此类。否则,EF-Core 工具将找不到您的连接字符串。
Quartz
日志记录
如果作业未执行,请开启 Quartz 的日志记录。QuartzConsoleLogProvider.cs 实现了一个记录到控制台的日志记录器。
注册日志提供程序
LogProvider.SetCurrentLogProvider(new QuartzConsoleLogProvider());
作业
Job 是您的服务应该运行的任务。这些必须实现 IJob 接口。如果此作业需要其他数据,您可以使用 JobDataMap。(参见 «QuartzController.cs» 和 MyJob.cs)
触发器
Quarzt 提供了一些在特定时间执行作业的触发器。示例包含在 QuartzController.cs 中
- 执行一次作业。
- 按间隔执行作业。
- 从队列中删除作业。
示例 4 - WebapiWinservice
- 查看 Github: WebapiWinservice
所需的 NuGet 包
- Topshelf
- Topshelf.Autofac
- Microsoft.Extensions.Configuration.Json
- Microsoft.EntityFrameworkCore
- Microsoft.EntityFrameworkCore.SqlServer
- Microsoft.EntityFrameworkCore.Tools
- Microsoft.AspNetCore
- Microsoft.AspNetCore.Core
- Microsoft.AspNetCore.Server.Kestrel.Core
- Microsoft.Extensions.Hosting
- Microsoft.Extensions.Logging.Configuration
Topshelf
- 执行 EXE 将在控制台中运行服务
- 可以通过 cmd.exe (以管理员身份运行) 安装 Windowsservice - Service.exe install
- 卸载使用 Service.exe uninstall
项目设置
- 控制台应用程序 (.NET Core 3.1)- 用于 windowsservice
- 打开项目文件 - 将项目 Sdk 编辑为:<Project Sdk="Microsoft.NET.Sdk.Web">
 
- 类库 (.NET STandard 2.0)- 如果需要 C# 应用程序的响应对象,请创建类库。或者,您也可以只使用从 JSON 解析的动态对象。
 
appsettings.json
- 必须配置 Kestrel和Logging部分。
- "AllowedHosts": "192.168.130.16;test.example.com" - 通过此配置,您可以定义 WebApi 可以从哪些主机访问。
发布提示
- 应配置 AllowedHosts
- 如果 API 只在内部可用,请配置 Windows 防火墙
调试
!!! 不要使用 IIS-Express 执行 !!!
Bootstrap.cs
此类用于注册依赖注入的类型。
BuildContainer
- 注册 servicecontroller
RegisterGlobalTypes
这些类型必须注册两次。一次用于 ASP.NET webhost,一次用于您的 service controller。
- 注册 IConfiguration- 提供读取 appsettings.json
- 注册设置 - Helperclass便于访问配置
WebApi
初始化
构建 webhost
定义 kestrel 服务器的设置
_webHost = Host.CreateDefaultBuilder()
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseStartup<Startup>();
        webBuilder.ConfigureKestrel(serverOptions =>
        {
            serverOptions.Limits.MaxConcurrentConnections = 100;
            serverOptions.Limits.MaxConcurrentUpgradedConnections = 100;
            serverOptions.Limits.MaxRequestBodySize = 30 * 1024 * 1024;
            serverOptions.Limits.MinRequestBodyDataRate =
                new MinDataRate(bytesPerSecond: 100,
                    gracePeriod: TimeSpan.FromSeconds(10));
            serverOptions.Limits.MinResponseDataRate =
                new MinDataRate(bytesPerSecond: 100,
                    gracePeriod: TimeSpan.FromSeconds(10));
            serverOptions.Limits.KeepAliveTimeout =
                TimeSpan.FromMinutes(2);
            serverOptions.Limits.RequestHeadersTimeout =
                TimeSpan.FromMinutes(1);
        });
    })
    .UseServiceProviderFactory(new AutofacServiceProviderFactory())
    .Build();
Startup.cs
ConfigureContainer
注册 Autofac 的类型
public void ConfigureContainer(ContainerBuilder builder)
{
    Bootstrap.RegisterGlobalTypes(builder);
    builder.RegisterType<Ip2LocationController>();
    // is used for determining the client ip
    builder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>().SingleInstance();
    // context per request
    builder.RegisterType<ip2locationContext>().InstancePerLifetimeScope();
}
配置
如果 HostHttpsRedirect 设置为 «1»,服务将自动重定向到 HTTPS。
Settings settings = app.ApplicationServices.GetAutofacRoot().Resolve<Settings>();
if (settings.GetAppSetting("HostHttpsRedirect") == "1")
{
    app.UseHttpsRedirection();
}
开始/停止
// Start
_webHost.StartAsync().ConfigureAwait(false).GetAwaiter().GetResult();
// Stop 
_webHost.StopAsync().ConfigureAwait(false).GetAwaiter().GetResult();
ApiController
- 继承自 ControllerBase
- 设置 Route&ApiController属性
- 实现 HttpGet/HttpPost方法
示例 C# 客户端
项目 «WebapiWinserviceClientExample»。
EF Core 与依赖注入
数据库
示例数据库是免费的 Ip2Location 数据库 的导入。有关下载和导入 MS-SQL 的说明,请查看以下链接:IP2Location™ LITE IP-COUNTRY 数据库。
Bootstrap
InstancePerLifetimeScope - 上下文将为每个作业创建,并在作业完成后将其处理。
builder.RegisterType<ip2locationContext>().InstancePerLifetimeScope();
builder.RegisterType<ip2locationWriteContext>().InstancePerLifetimeScope();
背景
由于构造函数 ip2locationContext(IConfiguration configuration),配置将自动注入。配置用于读取连接字符串。
public partial class ip2locationContext : DbContext
{
    protected readonly IConfiguration _configuration;
    public ip2locationContext(IConfiguration configuration)
    {
        _configuration = configuration;
    }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {
            optionsBuilder.UseSqlServer(_configuration.GetConnectionString("CTX"));
        }
    }
}
ip2locationContextFactory
如果您想要 EF-Core 迁移,您应该实现此类。否则,EF-Core 工具将找不到您的连接字符串。
历史
- 2020 年 3 月 2 日:初始版本


