1

Windows の Visual Studio 2019 で .NET Core コンソール アプリケーション (Windows 10 を搭載したサーバーで Windows サービスとして実行する準備ができている) を開発しており、継続的な開発ツールは CentOS 8 (GoCD) にあります。

そのアプリケーションを Windows で公開し、サービスとして実行すると、すべてがうまくいきます。Linux で公開し、ビルドしたアプリケーションを Windows 10 で実行しようとすると、次のようになります。

未処理の例外。System.PlatformNotSupportedException: ServiceController を使用すると、Windows サービスの操作とアクセスが可能になり、他のオペレーティング システムには適用されません。/opt/gocd-agent-1/go-agent-19.12.0/pipelines/app-SCHEDULER-PRODUCTION/ の appIV.Scheduler.ServiceBaseLifetime..ctor(IApplicationLifetime applicationLifetime) の System.ServiceProcess.ServiceBase..ctor() でapp-SCHEDULER-PRODUCTION/appIV/appIV.Scheduler/Service/ServiceBaseLifetime.cs:15行目

CentOS 8 での環境:

dotnet --list-runtimes
Microsoft.AspNetCore.App 3.1.3 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 3.1.3 [/usr/share/dotnet/shared/Microsoft.NETCore.App]

dotnet --list-sdks
3.1.201 [/usr/share/dotnet/sdk]

次のコマンドでアプリケーションを公開します

dotnet publish -o /tmp/app/scheduler/bin/Release/netcoreapp3.1/win-x64/publish/ -c Release -r win-x64 --self-contained true

-r win-x64パラメーターは、Windows をターゲットとする Linux で dotnet 公開するのに十分であると考えていましたが、明らかに間違っています。アプリケーションは、通常のコンソール アプリケーションとして実行されている限り動作しています ( --console パラメータを使用して、そのサービスをコンソール アプリケーションとして実行できます)。しかし、何らかの理由で、Linux で公開されたアプリケーションが Windows でサービスとして実行できないことを理解していません。

エラーが発生したサービスとして実行を管理するクラス:

using Microsoft.Extensions.Hosting;
using NLog;
using System;
using System.ServiceProcess;
using System.Threading;
using System.Threading.Tasks;

namespace App.Scheduler
{
    public class ServiceBaseLifetime : ServiceBase, IHostLifetime
{
    private readonly TaskCompletionSource<object> _delayStart = new TaskCompletionSource<object>();
    private NLog.Logger _logger = LogManager.GetCurrentClassLogger();

    public ServiceBaseLifetime(IApplicationLifetime applicationLifetime)
    {
        ApplicationLifetime = applicationLifetime ?? throw new ArgumentNullException(nameof(applicationLifetime));
    }

    private IApplicationLifetime ApplicationLifetime { get; }

    public Task WaitForStartAsync(CancellationToken cancellationToken)
    {
        _logger.Debug("WaitForStartAsync");
        cancellationToken.Register(() => _delayStart.TrySetCanceled());
        ApplicationLifetime.ApplicationStopping.Register(Stop);

        new Thread(Run).Start(); // Otherwise this would block and prevent IHost.StartAsync from finishing.
        return _delayStart.Task;
    }

    private void Run()
    {
        try
        {
            _logger.Debug("Run");
            Run(this); // This blocks until the service is stopped.
            _delayStart.TrySetException(new InvalidOperationException("Stopped without starting"));
        }
        catch (Exception ex)
        {
            _logger.Error(ex.Message);
            _delayStart.TrySetException(ex);
        }
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.Debug("StopAsync");
        Stop();
        return Task.CompletedTask;
    }

    // Called by base.Run when the service is ready to start.
    protected override void OnStart(string[] args)
    {
        _logger.Debug("OnStart");
        _delayStart.TrySetResult(null);
        base.OnStart(args);
    }

    // Called by base.Stop. This may be called multiple times by service Stop, ApplicationStopping, and StopAsync.
    // That's OK because StopApplication uses a CancellationTokenSource and prevents any recursion.
    protected override void OnStop()
    {
        _logger.Debug("OnStop");
        ApplicationLifetime.StopApplication();
        base.OnStop();
    }
}

}

4

0 に答える 0