Run .Net 6 Windows Forms app as a windows service

44 views Asked by At

I have a windows forms application that does some timely call to webservices. I did it as a windows forms because it was simpler to track comunications and tests. But now i need it to run as a windows service so it can be installed in a windows server an run unattended. The samples i have seen all start with a worker service project. But i want to make my windows forms app run as a service.

With .NET 4.5 i managed to build a service start project like this:

static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main()
        {
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[] 
            { 
                new CRDService() 
            };
            ServiceBase.Run(ServicesToRun);
        }
    }

And a service loader like this:

public partial class CRDService : ServiceBase
    {
        private int processId;
        private string filePath;

        public CRDService()
        {
            InitializeComponent();
        }

        public void Verify(string[] args)
        {
            this.OnStart(args);

            // do something here...  

            this.OnStop();
        }  

        protected override void OnStart(string[] args)
        {
            var location = new Uri(Assembly.GetEntryAssembly().CodeBase).LocalPath;
            var path = Path.GetDirectoryName(location);
            string appName = ConfigurationManager.AppSettings["AppName"];
            var serverPath = Path.Combine(path, appName);
            Process cmd = new Process();
            cmd.StartInfo.FileName = serverPath;
            cmd.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            using (var f = File.Create(Path.Combine(path, "TestFile.txt")))
            {
                filePath = f.Name;
                string msg = "Process started at " + DateTime.Now.ToString();
                f.Write(Encoding.ASCII.GetBytes(msg),0,msg.Length);
            }

            cmd.StartInfo.Arguments = filePath;
            cmd.Start();
            processId = cmd.Id;  
        }

        protected override void OnStop()
        {
            Process process = null;
            try
            {
                process = Process.GetProcessById((int)processId);
            }
            finally
            {
                if (process != null)
                {
                    process.Kill();
                    process.WaitForExit();
                    process.Dispose();
                }

                File.Delete(filePath);
            }  
        }
    }

But this doesn't work with .NET 6 and BackgroundService.

Can someone tell me if there is a way to do this in .NET 6/7?

1

There are 1 answers

0
Carlos Garcia On

Managed to resolve the problem. Here is the same solution for .NET 6/7.

using GatewayATService;

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

await host.RunAsync();
public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;
        private readonly Task _completedTask = Task.CompletedTask;

        private int processId;
        private string filePath;

        public Worker(ILogger<Worker> logger)
        {
            _logger = logger;
        }

        public override Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("GatewayAT Service is starting.");

            var location = new Uri(System.AppDomain.CurrentDomain.BaseDirectory).LocalPath;
            var path = Path.GetDirectoryName(location);
            //string appName = ConfigurationManager.AppSettings["AppName"];
            var builder = new ConfigurationBuilder()
                        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
            IConfiguration config = builder.Build();
            string appName = config.GetValue<string>("AppName");

            var serverPath = Path.Combine(path, appName);
            Process cmd = new Process();
            cmd.StartInfo.FileName = serverPath;
            cmd.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            using (var f = File.Create(Path.Combine(path, "log.txt")))
            {
                filePath = f.Name;
                string msg = "Process started at " + DateTime.Now.ToString();
                f.Write(Encoding.ASCII.GetBytes(msg), 0, msg.Length);
            }

            cmd.StartInfo.Arguments = filePath;
            cmd.Start();
            processId = cmd.Id;

            return _completedTask;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(1000, stoppingToken);
            }
        }

        public override Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("GatewayAT Service is stopping.");
            Process process = null;
            try
            {
                process = Process.GetProcessById((int)processId);
            }
            finally
            {
                if (process != null)
                {
                    process.Kill();
                    process.WaitForExit();
                    process.Dispose();
                }

                File.Delete(filePath);
            }
            return _completedTask;
        }
    }
``
`