Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting a Topshelf service to run once on boot, then stop

I have written a TopShelf service / console app, which appears to be running as intended, except I would like it to run once on boot, then disable itself until the next boot/reboot.

I was hoping this would work:

class MyServiceClass
{
    public void Start()
    {
        // do the things that need doing

        this.Stop();
    }

    public void Stop()
    {
    }

But that doesn't work, presumably because the this.Stop() command is there for cleanup, not for causing the service to stop.

My Program.cs looks like this:

// Uses Topshelf: http://topshelf-project.com/
// Guided by: http://www.ordina.nl/nl-nl/blogs/2013/maart/building-windows-services-with-c-and-topshelf/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

using Topshelf;

namespace MyNamespace
{
    class Program
    {
        static void Main(string[] args)
        {
            HostFactory.Run(hostConfigurator =>
            {
                hostConfigurator.Service<MyServiceClass>(serviceConfigurator =>
                {
                    serviceConfigurator.ConstructUsing(() => new MyServiceClass());
                    serviceConfigurator.WhenStarted(myServiceClass => myServiceClass.Start());
                    serviceConfigurator.WhenStopped(myServiceClass => myServiceClass.Stop());
                });

                hostConfigurator.RunAsLocalSystem();

                hostConfigurator.SetDisplayName("MyService");
                hostConfigurator.SetDescription("Does stuff.");
                hostConfigurator.SetServiceName("MyService");
                hostConfigurator.StartAutomatically();
                hostConfigurator.EnableShutdown();
            });
        }
    };
}

How do I go about stopping the service at the end of execution?

UPDATE: Based on Damien's input, I now have:

public class MyServiceClass
{
    private readonly Task task;
    private HostControl hostControl;

    public MyServiceClass()
    {
        task = new Task(DoWork);
    }

    private void DoWork()
    {
        Console.WriteLine("Listen very carefully, I shall say this only once");
        hostControl.Stop();
    }

    public void Start(HostControl hostControl)
    {
        // so we can stop the service at the end of the check
        this.hostControl = hostControl;

        // start the DoWork thread
        task.Start();
    }

    public void Stop()
    {

    }

};

and an updated Program.cs

class Program
{
    static void Main(string[] args)
    {

        HostFactory.Run(hostConfigurator =>
        {
            hostConfigurator.Service<MyServiceClass>((serviceConfigurator =>
            {
                serviceConfigurator.ConstructUsing(() => new MyServiceClass());
                serviceConfigurator.WhenStarted((myServiceClass, hostControl) => myServiceClass.Start(hostControl));
                serviceConfigurator.WhenStopped(myServiceClass => myServiceClass.Stop());
            });    /* compiler thinks there's a ")" missing from this line */

            hostConfigurator.RunAsLocalSystem();

            hostConfigurator.SetDisplayName("MyService");
            hostConfigurator.SetDescription("Does stuff.");
            hostConfigurator.SetServiceName("MyService");
            hostConfigurator.StartAutomatically();
            hostConfigurator.EnableShutdown();
        });

    }
};

However, this will not compile. My compiler suggests that a ")" is missing on (or around) my comment (shown in the code above), but any addition of a close parenthesis just adds to the error list.

I feel like I'm close... any ideas?

like image 881
technorabble Avatar asked Mar 19 '23 17:03

technorabble


1 Answers

Got this working eventually:

public class MyServiceClass : ServiceControl
{
    private readonly Task task;
    private HostControl hostControl;

    public MyServiceClass()
    {
        task = new Task(DoWork);
    }

    private void DoWork()
    {
        Console.WriteLine("Listen very carefully, I shall say this only once");
        //hostControl.Stop();
    }

    public bool Start(HostControl hostControl)
    {
        // so we can stop the service at the end of the check
        this.hostControl = hostControl;

        // start the DoWork thread
        task.Start();

        return true;
    }

    public bool Stop(HostControl hostControl)
    {
        return true;
    }

};

and

class Program
{
    static void Main(string[] args)
    {

        HostFactory.Run(hostConfigurator =>
        {
            hostConfigurator.Service<MyServiceClass>(serviceConfigurator =>
            {
                serviceConfigurator.ConstructUsing(() => new MyServiceClass());
                serviceConfigurator.WhenStarted((myServiceClass, hostControl) => myServiceClass.Start(hostControl));
                serviceConfigurator.WhenStopped((myServiceClass, hostControl) => myServiceClass.Stop(hostControl));
            });

            hostConfigurator.RunAsLocalSystem();

            hostConfigurator.SetDisplayName("MyService");
            hostConfigurator.SetDescription("Does stuff.");
            hostConfigurator.SetServiceName("MyService");
            hostConfigurator.StartAutomatically();
            hostConfigurator.EnableShutdown();
        });

    }
};

My 2nd attempt had a spare "(" at the first mention of serviceConfigurator, then I needed to turn my void Start and Stop functions into bool functions. Hope this helps someone.

like image 160
technorabble Avatar answered Apr 01 '23 19:04

technorabble