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

 如何開發並一鍵發佈WindowsService項目(netcore普通項目)

netcore下開發windows服務若是是web項目的話,因爲aspnetcore自己是支持的,把默認的host.Run改成host.RunAsService就能夠了。git

可是普通的netcore的控制檯項目我終於找到了以下方式來實現:github

1. 打開vs 選擇建立一個新的netcore 控制檯項目

 

 

Nuget添加以下引用

  1. Microsoft.Extensions.Hosting
  2. System.ServiceProcess.ServiceController

 

 

新建一個ServiceBaseLifetime.cs 並將下面的內容複製進去

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();
    }
}

 

新建一個ServiceBaseLifetimeHostExtensions.cs 並將下面的內容複製進去

public static class ServiceBaseLifetimeHostExtensions
{
    public static IHostBuilder UseServiceBaseLifetime(this IHostBuilder hostBuilder)
    {
        return hostBuilder.ConfigureServices((hostContext, services) => services.AddSingleton<IHostLifetime, ServiceBaseLifetime>());
    }

    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);
    }
}

新建一個服務類 TestService.cs 並寫入如下內容(該服務就是每1秒往d:\log.txt寫入當前時間)

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();
    }
}

編輯 Program.cs 寫入以下內容,保證既能夠做爲控制檯打開又能夠做爲windows服務運行:

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<TestService>();
            });

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

 

一鍵發佈到服務器,在工程上點擊右鍵 而後選擇 AntDeploy

AntDeploy是我開發的一款開源一鍵部署vs插件(也是支持脫離vs單獨使用的一個開源工具)web

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

 

 

配置AntDeploy

添加一個環境 名字叫 測試 而後 在 測試環境裏面添加 windows服務器 這裏我作測試就添加就是我本機,注意Host裏面是填寫格式爲:ip:端口號

 

 注意:Token不是windows服務器的密碼!!!是安裝agent後,agent的配置文件裏面配置的Token(你本身自定義配置的)
注意:Port不是你要發佈的項目的端口號!!!是安裝agent後,agent的配置文件裏面配置的端口號(你本身自定義配置的)
點擊【Connect Test】按鈕進行確認agent能夠成功連接,不然會發布失敗
若是【Connect Fail】失敗 請查看 #10服務器

 

進入 WindowsService Tab界面

Sdk類型選擇 netcore
ServiceName 填寫上面咱們設置的名稱:[TestService]app

 

點擊 【Deploy】按鈕進行發佈async

確認服務器無誤 點擊 【是】開始執行一鍵部署
若是發佈出現錯誤會出現下圖所示:ide

 

能夠在Log裏面查看失敗緣由是由於我部署agent沒有用管路員權限 報權限不足失敗 須要用管理員權限運行agent才行工具

 

 部署成功 以下圖:測試

 

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

這裏演示的是windows服務上沒有這個service因此自動建立了。若是service已存在的狀況 Deploy 就會全量覆蓋 不會從新建立site的。若是想要覆蓋時排除指定文件 能夠在 Setting Tab界面的IgnoreList裏面增長(支持正則)

相關文章
相關標籤/搜索