Xây Dựng Windows Service Đơn Giản Hơn Với Topshelf

Topshelf là gì? Là một framework cho phép các nhà phát triển tạo ra một ứng dụng console đơn giản mà có thể được cài đặt như một windows service.

Topshelf - Phạm Tuân

Topshelf là một framework mã nguồn mở, các bạn có thể tải source-code tại GitHub. Hoặc get trực tiếp thông qua Nuget:

Install-Package Topshelf

Để thấy sự tiện lợi, các bạn hãy xem đoạn code dưới đây.

public class MyService // Service của bạn
{	
    public MyService()
    {
        // Do something
    }
    public void Start() { /* Do something */ }
    public void Stop() { /* Do something */ }
}

public class Program
{
    public static void Main()
    {
        HostFactory.Run(x => // Setup các thông tin cần thiết
        {
            x.Service<MyService>(s => // Khai báo các callBack
            {
               s.ConstructUsing(name=> new MyService()); // Cách mà service của tôi được khởi tạo
               s.WhenStarted(tc => tc.Start());  // Khi service được start
               s.WhenStopped(tc => tc.Stop());  // Khi service được stop
            });
            x.RunAsLocalSystem(); // Service sẽ được chạy với quyền gì

            // Thông tin service, bạn có thể không khai báo các thông tin này vì Topshelf cho phép bạn
            // khai báo khi install thông qua cmd
            x.SetDescription("This is MyService");
            x.SetDisplayName("MyService");
            x.SetServiceName("MyService");
        });
    }
}

Ngoài ra Topshelf còn cho phép developer config sâu hơn vào các behaviors của service như:

  • Service Recovery
  • Service Identity
  • Custom Install Actions
  • Service Dependencies
  • Advanced Settings

Topshelf cũng có một bộ command riêng để bạn có thể install, uninstall và start, stop service.

D:\MyProject\MyService.exe install -servicename "MyServiceName"
// Hoặc
D:\MyProject\MyService.exe uninstall -servicename "MyServiceName"
// Hoặc
D:\MyProject\MyService.exe start -servicename "MyServiceName"
// Hoặc
D:\MyProject\MyService.exe stop -servicename "MyServiceName"

// Bạn cũng có thể dùng command của Windows như sc để start/stop service như bình thường
C:\Windows\system32>sc start "MyServiceName"
// Hay
C:\Windows\system32>sc stop "MyServiceName"
// Hay
C:\Windows\system32>sc delete "MyServiceName"

Ngoài ra các bạn cũng có thể thêm vào Topshelf những command hay parameter của riêng mình bằng cách dùng Topshelf.StartParameters.

Ví dụ:

// MyService.exe install -config "standard" -setmyparam "customparam"
HostFactory.Run(x =>
            {
                x.EnableStartParameters();
                x.UseNLog();
                x.Service<MyService>(sc =>
                {
                    sc.ConstructUsing(hs => new MyService());
                    sc.WhenStarted(s => s.Start());
                    sc.WhenStopped(s => s.Stop());
                });

                x.WithStartParameter("config",
                    a => HostLogger.Get("StartParameters").InfoFormat("parameter: {0}, value: {1}", "config", a));

                x.WithCustomStartParameter("setmyparam", "myparam",
                    a => HostLogger.Get("StartParameters").InfoFormat("custom parameter: {0}, value: {1}", "myparam", a));

                x.SetServiceName("MyService");
                x.SetDisplayName("My Service");
                x.SetDescription("Sample Service");
                x.RunAsLocalSystem();
            });

Bên cạnh đó, Topshelf cũng hỗ trợ một số logging framework như: log4net, NLog, log4net.

Log4net:

// Install-Package Topshelf.Log4Net
HostFactory.Run(x =>
{
    x.UseLog4Net();
// .........................
});

NLog:

// Install-Package Topshelf.NLog
HostFactory.Run(x =>
{
    x.UseNLog();
// .........................
});

Ví dụ:

using log4net;
using log4net.Config;
using Topshelf;

namespace topshelftest
{
    using log4net;
    using log4net.Config;
    using Topshelf;

    public class MyService
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(MyService));

        public void Start()
        {
            log.Info("Started");
        }

        public void Stop()
        {
            log.Info("Stopped");
        }
    }
	
    class Program
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(Program));

        static void Main(string[] args)
        {
            XmlConfigurator.Configure();

            log.Error("HELLO.....");

            HostFactory.Run(
                x =>
                    {
                        x.UseLog4Net();
                        x.Service<MyService>(
                            s =>
                                {
                                    s.ConstructUsing(name => new MyService());
                                    s.WhenStarted(tc => tc.Start());
                                    s.WhenStopped(tc => tc.Stop());
                                });
                        x.RunAsLocalSystem();

                        x.SetDescription("This is MyService");
                        x.SetDisplayName("MyService");
                        x.SetServiceName("MyService");
                    });
        }
    }
}

Một số lưu ý khi sử dụng Topshelf:

  • Topshelf chỉ có một bộ exit-code hạn chế, nếu bạn cần chi tiết hơn về error thì cần cân nhắc. Ví dụ như Topshelf không có error khi file exe của service không tồn tại thay vào đó bạn chỉ nhận được một lỗi chung chung.
  • Topshelf config giá trị default cho time-out khi start hay stop service là 1 PHÚT, nếu service của bạn start lâu hơn 1 phút bạn sẽ nhận error mặc dù sau đó service vẫn RUNNING.
  • Nếu bạn dùng giá trị default time-out là 1 phút và service của bạn FAIL ngay khi start, bạn vẫn phải đợi đến 1 phút để nhận lỗi.

Topshelf Exit-Code

namespace Topshelf
{
    public enum TopshelfExitCode
    {
        Ok = 0,
        AbnormalExit = 1,
        SudoRequired = 2,
        ServiceAlreadyInstalled = 3,
        ServiceNotInstalled = 4,
        StartServiceFailed = 5,
        StopServiceFailed = 6,
        ServiceAlreadyRunning = 7,
        UnhandledServiceException = 8,
        ServiceNotRunning = 9,
        SendCommandFailed = 10,
    }
}

Phạm Tuân

Visual Studio Code - Bộ text-editor đa năng
ILMerge - Cách merge các dlls và exe thành một
Cách kiểm tra ứng dụng có quyền Admin hay không
Hãy bình luận trực tiếp ở đây để được trả lời nhanh hơn. 2 bình luận.

Trả lời