歡迎光臨
每天分享高質量文章

netcore開發windows普通服務(非Web)並一鍵釋出到伺服器

netcore下開發windows服務如果是web專案的話,由於aspnetcore本身是支援的,把預設的host.Run改為host.RunAsService就可以了。

但是普通的netcore的控制檯專案我終於找到瞭如下方式來實現:

  1. Microsoft.Extensions.Hosting
  2. System.ServiceProcess.ServiceController
public class ServiceBaseLifetime : ServiceBase, IHostLifetime
{
private readonly TaskCompletionSource _delayStart = new TaskCompletionSource();

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

    private IApplicationLifetime ApplicationLifetime { get; }

    public Task WaitForStartAsync(CancellationToken cancellationToken)
    {
        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
        {
            Run(this); // This blocks until the service is stopped.
            _delayStart.TrySetException(new InvalidOperationException("Stopped without starting"));
        }
        catch (Exception ex)
        {
            _delayStart.TrySetException(ex);
        }
    }

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

    // Called by base.Run when the service is ready to start.
    protected override void OnStart(string[] args)
    {
        _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()
    {
        ApplicationLifetime.StopApplication();
        base.OnStop();
    }
}
public static class ServiceBaseLifetimeHostExtensions
{
    public static IHostBuilder UseServiceBaseLifetime(this IHostBuilder hostBuilder)
    {
        return hostBuilder.ConfigureServices((hostContext, services) => services.AddSingleton());
    }

    public static void RunAsService(this IHostBuilder hostBuilder)
    {
        hostBuilder.UseServiceBaseLifetime().Build().Run();
    }

    public static Task RunAsServiceAsync(this IHostBuilder hostBuilder)
    {
        return hostBuilder.UseServiceBaseLifetime().Build().RunAsync(CancellationToken.None);
    }
}
public class TestService: IHostedService,IDisposable
{
readonly System.Timers.Timer tmBak = new System.Timers.Timer();

    public TestService()
    {
        tmBak.Interval = 1000;//1秒執行1次
        tmBak.AutoReset = true;//執行1次false,一直執行true
        tmBak.Enabled = true;
        tmBak.Elapsed += (sender, eventArgs) =>
        {
            using (StreamWriter sw = new StreamWriter("D:\\log.txt",true))
            {
                sw.WriteLine($"AntDeploy Windows服務:{DateTime.Now:yyyy-MM-dd HH:mm:ss}");
            }
        };
    }


    public Task StartAsync(CancellationToken cancellationToken)
    {
        tmBak.Start();
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        tmBak.Stop();
        return Task.CompletedTask;
    }

    public void Dispose()
    {
        this.tmBak.Dispose();
    }
}
class Program
{
// P/Invoke declarations for Windows.
[DllImport("kernel32.dll")] static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")] static extern bool IsWindowVisible(IntPtr hWnd);
public static bool HaveVisibleConsole()
{
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
IsWindowVisible(GetConsoleWindow())
:
Console.WindowHeight > 0;
}

    private static async Task Main(string[] args)
    {
        var pathToExe = Process.GetCurrentProcess().MainModule.FileName;
        var pathToContentRoot = Path.GetDirectoryName(pathToExe);
        Directory.SetCurrentDirectory(pathToContentRoot);

        var isService = !(Debugger.IsAttached || args.Contains("--console"));

        if (HaveVisibleConsole()) isService = false;
        var builder = new HostBuilder()
            .ConfigureServices((hostContext, services) =>
            {
                services.AddHostedService();
            });

        if (isService)
        {
            await builder.RunAsServiceAsync();
        }
        else
        {
            await builder.RunConsoleAsync();
        }
    }
}

AntDeploy是我開發的一款開源一鍵部署vs外掛(也是支援脫離vs單獨使用的一個開源工具)

開源地址:https://github.com/yuzd/AntDeployAgent

新增一個環境 名字叫 測試 然後 在 測試環境裡面新增 windows伺服器 這裡我做測試就新增就是我本機,註意Host裡面是填寫格式為:ip:埠號

 註意:Token不是windows伺服器的密碼!!!是安裝agent後,agent的配置檔案裡面配置的Token(你自己自定義配置的)
註意:Port不是你要釋出的專案的埠號!!!是安裝agent後,agent的配置檔案裡面配置的埠號(你自己自定義配置的)
點選【Connect Test】按鈕進行確認agent可以成功連結,否則會釋出失敗
如果【Connect Fail】失敗 請檢視 #10

進入 WindowsService Tab介面

Sdk型別選擇 netcore
ServiceName 填寫上面我們設定的名稱:[TestService]

點選 【Deploy】按鈕進行釋出

確認伺服器無誤 點選 【是】開始執行一鍵部署
如果釋出出現錯誤會出現下圖所示:

可以在Log裡面檢視失敗原因是因為我部署agent沒有用管路員許可權 報許可權不足失敗 需要用管理員許可權執行agent才行

 部署成功 如下圖:

 檢視D盤下是否log.txt是否正常每隔1秒寫入了當前時間

這裡演示的是windows服務上沒有這個service
所以自動建立了。
如果service已存在的情況 Deploy 就會全量改寫 不會重新建立site的。
如果想要改寫時排除指定檔案 可以在 Setting Tab介面的IgnoreList裡面增加(支援正則)

原文地址:https://www.cnblogs.com/yudongdong/p/10630835.html

贊(0)

分享創造快樂