6

踩坑 Windows 服务来宿主 .NET 程序

 2 years ago
source link: https://www.cnblogs.com/kklldog/p/host-net-on-windows-service.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

本文所指的 .NET 程序为 .NET6 的程序。因为 .NET 的版本更新很快,所以方式、方法也有变化,所以网上搜到的方法有些也过时了。以下是最近我实践下来的一点心得(坑)。
上一篇说到 不安装运行时运行 .NET 程序 后我们的程序已经只有一个 dll/exe 了,但是在 windows 上运行的时候会是一个控制台程序,很容易人不小心关闭了。所以想着把我们的程序部署成 windows 服务,这样不会误关,重启服务器的时候也会自动启动。所以最近折腾了一下把 .NET 程序,特别是 ASP.NET Core 程序部署为 windows 服务。本来以为网上随便搜一搜就很容易,事实上没想得这么美好。

Worker Service#

如果你的服务只想执行一些后台任务,比如定时任务,并不提供网站的服务。那么使用 Worker service 项目模板新建一个项目是最合适的。

workerservice.png


新建完项目后使用 nuget 安装:

Microsoft.Extensions.Hosting.WindowsServices

修改 program.cs 文件

using WorkerService1;

IHost host = Host.CreateDefaultBuilder(args)
    .UseWindowsService()
    .ConfigureServices(services =>
    {
        services.AddHostedService<Worker>();
    })
    .Build();

await host.RunAsync();

其中就只添加一句 UseWindowsService 就可以了。
编译之后使用 sc 命令就可以注册为服务了。

sc create "wsTest" binPath=wsTest.exe
sc start "wsTest"
pause

我们把它写成一个 bat 文件方便执行。使用管理权限运行这个 bat 文件服务会被注册并且直接运行:

%E4%BC%81%E4%B8%9A%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20220831183904.png

ASP.NET Core#

以上尝试了一下 worker service 模式注册为服务,感觉简单的很。但是下面把 ASP.NET Core 程序注册为服务的时候就没那么简单啦。我查了一些文章,写的时间有些早了,所以还是安照微软官方的文档 Host ASP.NET Core in a Windows Service 的提示来操作。这篇文章虽然叫 Host ASP.NET Core in a Windows Service ,但其实里面的内容说的是上面的 worker service 。当按照上面的步骤尝试把 asp.net core 程序部署为服务的时候死活起不来,一直报未找到文件的异常。
我们新建一个最简单的 asp.net core 程序来演示一下:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Host.UseWindowsService();

var app = builder.Build();

app.UseStaticFiles();
app.UseRouting();
await app.RunAsync();

这是一个最简单的 asp.net core razor pages 程序。我们按照文档安装扩展包:

Microsoft.Extensions.Hosting.WindowsServices

然后调用 UseWindowsService 方法

builder.Host.UseWindowsService();

同样使用 sc 命令注册为服务并运行它。很遗憾它会报错。

20220831185410.png

经过多种尝试方法都不行。最后翻了一下微软仓库里的 sample 代码才发现原来他们自己的 sample 代码里多了几行代码 。

注意下面的代码了啊 !!!

在构建 builder 的时候需要多传几个参数:

var options = new WebApplicationOptions
{
    Args = args,
    ContentRootPath = WindowsServiceHelpers.IsWindowsService() ? AppContext.BaseDirectory : default
};
var builder = WebApplication.CreateBuilder(options);

只要使用这段代码来构建 builder ,服务就可以顺利的运行起来。根据以往的经验,可能还是作为服务运行的时候程序根目录的问题,通过以上方法来指定 AppContext.BaseDirectory 来作为程序的根目录,不然就有可能被定位到 system32 目录下。
吐槽。。。虽然解决方案很简单,但是微软没有在文档里把这么关键的代码给些出来,着实有点坑啊,辛亏现在代码都在 github 上,很容易翻到,不然得折腾死人。

PS#

就在今天2022/09/02微软的英文文档已经更新了示例代码,中文版还没更新:
https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/windows-service?view=aspnetcore-6.0&tabs=visual-studio#app-configuration-1

关注我的公众号一起玩转技术#

qrcode.jpg

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK