Search code examples
c#windowsservicetimer

Keep a Windows Service running without a timer


Currently the only examples of a Windows service in C# I have seen are where a timer runs through a method every x seconds - e.g. checking for file changes.

I'm wondering if it is possible (with example code if possible) to keep a Windows service running without a timer and instead just have a service listening for events - in the same way a console application can still listen for events and avoid closing with Console.ReadLine() without requiring a timer.

I am essentially looking for a way to avoid the x second delay between an event happening and an action being performed.


Solution

  • A windows service does not need to create a timer to keep running. It can either establish a file watcher Using FileSystemWatcher to monitor a directory or start an asynchronous socket listener.

    Here is a simple TPL based listener/responder without needing to dedicate a thread to the process.

    private TcpListener _listener;
    
    public void OnStart(CommandLineParser commandLine)
    {
        _listener = new TcpListener(IPAddress.Any, commandLine.Port);
        _listener.Start();
        Task.Run((Func<Task>) Listen);
    }
    
    private async Task Listen()
    {
        IMessageHandler handler = MessageHandler.Instance;
    
        while (true)
        {
            var client = await _listener.AcceptTcpClientAsync().ConfigureAwait(false);
    
            // Without the await here, the thread will run free
            var task = ProcessMessage(client);
        }
    }
    
    public void OnStop()
    {
        _listener.Stop();
    }
    
    public async Task ProcessMessage(TcpClient client)
    {
        try
        {
            using (var stream = client.GetStream())
            {
                var message = await SimpleMessage.DecodeAsync(stream);
                _handler.MessageReceived(message);
            }
        }
        catch (Exception e)
        {
            _handler.MessageError(e);
        }
        finally
        {
            (client as IDisposable).Dispose();
        }
    }
    

    Neither of these need a timer