Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. Gracefully exit a .net 8 based windows service [SOLVED]

Gracefully exit a .net 8 based windows service [SOLVED]

Scheduled Pinned Locked Moved C#
csharptutorialquestionvisual-studiosysadmin
6 Posts 5 Posters 18 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Richard Andrew x64R Offline
    Richard Andrew x64R Offline
    Richard Andrew x64
    wrote on last edited by
    #1

    It seems that the .NET 8 infrastructure code that interacts with the service control manager provides a layer of abstraction over the Start and Stop commands. Therefore I don't see how to directly issue a service stop command. The service is passed a CancellationToken object, but I've been informed that you can't cancel such a token without access to the CancellationTokenSource. When the service runs, all I have is the token, not the source. So how do I shutdown and exit the service from code running inside the service? SOLUTION: Below is the template code produced by Visual Studio when you create a .NET 8 Windows service: I simply created a property on the service class itself that can be set from inside the service and indicates to the outside world whether the service wants to shut down. I called it StopFlag.

    public sealed class WindowsBackgroundService(
        MyWindowsService myWindowsService,
        ILogger logger) : BackgroundService
    {
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            try
            {
                myWindowsService.OnStart(new string\[0\]);
    
                while (!stoppingToken.IsCancellationRequested && !myWindowsService.StopFlag)
                {
                    await Task.Delay(TimeSpan.FromSeconds(1), stoppingToken);
                }
            }
            catch (OperationCanceledException)
            {
                // When the stopping token is canceled, for example, a call made from services.msc,
                // we shouldn't exit with a non-zero exit code. In other words, this is expected...
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "{Message}", ex.Message);
    
                // Terminates this process and returns an exit code to the operating system.
                // This is required to avoid the 'BackgroundServiceExceptionBehavior', which
                // performs one of two scenarios:
                // 1. When set to "Ignore": will do nothing at all, errors cause zombie services.
                // 2. When set to "StopHost": will cleanly stop the host, and log errors.
                //
                // In order for the Windows Service Management system to leverage configured
                // recovery options, we need to terminate the process with a non-zero exit code.
                Environment.Exit(1);
            }
        }
    
    OriginalGriffO L J J 4 Replies Last reply
    0
    • Richard Andrew x64R Richard Andrew x64

      It seems that the .NET 8 infrastructure code that interacts with the service control manager provides a layer of abstraction over the Start and Stop commands. Therefore I don't see how to directly issue a service stop command. The service is passed a CancellationToken object, but I've been informed that you can't cancel such a token without access to the CancellationTokenSource. When the service runs, all I have is the token, not the source. So how do I shutdown and exit the service from code running inside the service? SOLUTION: Below is the template code produced by Visual Studio when you create a .NET 8 Windows service: I simply created a property on the service class itself that can be set from inside the service and indicates to the outside world whether the service wants to shut down. I called it StopFlag.

      public sealed class WindowsBackgroundService(
          MyWindowsService myWindowsService,
          ILogger logger) : BackgroundService
      {
          protected override async Task ExecuteAsync(CancellationToken stoppingToken)
          {
              try
              {
                  myWindowsService.OnStart(new string\[0\]);
      
                  while (!stoppingToken.IsCancellationRequested && !myWindowsService.StopFlag)
                  {
                      await Task.Delay(TimeSpan.FromSeconds(1), stoppingToken);
                  }
              }
              catch (OperationCanceledException)
              {
                  // When the stopping token is canceled, for example, a call made from services.msc,
                  // we shouldn't exit with a non-zero exit code. In other words, this is expected...
              }
              catch (Exception ex)
              {
                  logger.LogError(ex, "{Message}", ex.Message);
      
                  // Terminates this process and returns an exit code to the operating system.
                  // This is required to avoid the 'BackgroundServiceExceptionBehavior', which
                  // performs one of two scenarios:
                  // 1. When set to "Ignore": will do nothing at all, errors cause zombie services.
                  // 2. When set to "StopHost": will cleanly stop the host, and log errors.
                  //
                  // In order for the Windows Service Management system to leverage configured
                  // recovery options, we need to terminate the process with a non-zero exit code.
                  Environment.Exit(1);
              }
          }
      
      OriginalGriffO Offline
      OriginalGriffO Offline
      OriginalGriff
      wrote on last edited by
      #2

      Don't you just call the ServiceBase.Stop Method (System.ServiceProcess) | Microsoft Learn[^] ?

      "I have no idea what I did, but I'm taking full credit for it." - ThisOldTony "Common sense is so rare these days, it should be classified as a super power" - Random T-shirt AntiTwitter: @DalekDave is now a follower!

      "I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
      "Common sense is so rare these days, it should be classified as a super power" - Random T-shirt

      Richard Andrew x64R 1 Reply Last reply
      0
      • OriginalGriffO OriginalGriff

        Don't you just call the ServiceBase.Stop Method (System.ServiceProcess) | Microsoft Learn[^] ?

        "I have no idea what I did, but I'm taking full credit for it." - ThisOldTony "Common sense is so rare these days, it should be classified as a super power" - Random T-shirt AntiTwitter: @DalekDave is now a follower!

        Richard Andrew x64R Offline
        Richard Andrew x64R Offline
        Richard Andrew x64
        wrote on last edited by
        #3

        Griff, thanks for the reply. The method and object you mention are only in the .NET Framework. I recently upgraded the service to .NET 8, which uses a different paradigm.

        The difficult we do right away... ...the impossible takes slightly longer.

        1 Reply Last reply
        0
        • Richard Andrew x64R Richard Andrew x64

          It seems that the .NET 8 infrastructure code that interacts with the service control manager provides a layer of abstraction over the Start and Stop commands. Therefore I don't see how to directly issue a service stop command. The service is passed a CancellationToken object, but I've been informed that you can't cancel such a token without access to the CancellationTokenSource. When the service runs, all I have is the token, not the source. So how do I shutdown and exit the service from code running inside the service? SOLUTION: Below is the template code produced by Visual Studio when you create a .NET 8 Windows service: I simply created a property on the service class itself that can be set from inside the service and indicates to the outside world whether the service wants to shut down. I called it StopFlag.

          public sealed class WindowsBackgroundService(
              MyWindowsService myWindowsService,
              ILogger logger) : BackgroundService
          {
              protected override async Task ExecuteAsync(CancellationToken stoppingToken)
              {
                  try
                  {
                      myWindowsService.OnStart(new string\[0\]);
          
                      while (!stoppingToken.IsCancellationRequested && !myWindowsService.StopFlag)
                      {
                          await Task.Delay(TimeSpan.FromSeconds(1), stoppingToken);
                      }
                  }
                  catch (OperationCanceledException)
                  {
                      // When the stopping token is canceled, for example, a call made from services.msc,
                      // we shouldn't exit with a non-zero exit code. In other words, this is expected...
                  }
                  catch (Exception ex)
                  {
                      logger.LogError(ex, "{Message}", ex.Message);
          
                      // Terminates this process and returns an exit code to the operating system.
                      // This is required to avoid the 'BackgroundServiceExceptionBehavior', which
                      // performs one of two scenarios:
                      // 1. When set to "Ignore": will do nothing at all, errors cause zombie services.
                      // 2. When set to "StopHost": will cleanly stop the host, and log errors.
                      //
                      // In order for the Windows Service Management system to leverage configured
                      // recovery options, we need to terminate the process with a non-zero exit code.
                      Environment.Exit(1);
                  }
              }
          
          L Offline
          L Offline
          Lost User
          wrote on last edited by
          #4

          Store a "semaphore" (or "command code") somewhere and have the service look at it every so often. Use pull instead of push, and let it shut itself down.

          "Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I

          1 Reply Last reply
          0
          • Richard Andrew x64R Richard Andrew x64

            It seems that the .NET 8 infrastructure code that interacts with the service control manager provides a layer of abstraction over the Start and Stop commands. Therefore I don't see how to directly issue a service stop command. The service is passed a CancellationToken object, but I've been informed that you can't cancel such a token without access to the CancellationTokenSource. When the service runs, all I have is the token, not the source. So how do I shutdown and exit the service from code running inside the service? SOLUTION: Below is the template code produced by Visual Studio when you create a .NET 8 Windows service: I simply created a property on the service class itself that can be set from inside the service and indicates to the outside world whether the service wants to shut down. I called it StopFlag.

            public sealed class WindowsBackgroundService(
                MyWindowsService myWindowsService,
                ILogger logger) : BackgroundService
            {
                protected override async Task ExecuteAsync(CancellationToken stoppingToken)
                {
                    try
                    {
                        myWindowsService.OnStart(new string\[0\]);
            
                        while (!stoppingToken.IsCancellationRequested && !myWindowsService.StopFlag)
                        {
                            await Task.Delay(TimeSpan.FromSeconds(1), stoppingToken);
                        }
                    }
                    catch (OperationCanceledException)
                    {
                        // When the stopping token is canceled, for example, a call made from services.msc,
                        // we shouldn't exit with a non-zero exit code. In other words, this is expected...
                    }
                    catch (Exception ex)
                    {
                        logger.LogError(ex, "{Message}", ex.Message);
            
                        // Terminates this process and returns an exit code to the operating system.
                        // This is required to avoid the 'BackgroundServiceExceptionBehavior', which
                        // performs one of two scenarios:
                        // 1. When set to "Ignore": will do nothing at all, errors cause zombie services.
                        // 2. When set to "StopHost": will cleanly stop the host, and log errors.
                        //
                        // In order for the Windows Service Management system to leverage configured
                        // recovery options, we need to terminate the process with a non-zero exit code.
                        Environment.Exit(1);
                    }
                }
            
            J Offline
            J Offline
            jschell
            wrote on last edited by
            #5

            Richard Andrew x64 wrote:

            logger.LogError(ex, "{Message}", ex.Message);

            Just noting that from the support position I have found it useful to log both when it started and when it stopped, regardless of why it stopped.

            1 Reply Last reply
            0
            • Richard Andrew x64R Richard Andrew x64

              It seems that the .NET 8 infrastructure code that interacts with the service control manager provides a layer of abstraction over the Start and Stop commands. Therefore I don't see how to directly issue a service stop command. The service is passed a CancellationToken object, but I've been informed that you can't cancel such a token without access to the CancellationTokenSource. When the service runs, all I have is the token, not the source. So how do I shutdown and exit the service from code running inside the service? SOLUTION: Below is the template code produced by Visual Studio when you create a .NET 8 Windows service: I simply created a property on the service class itself that can be set from inside the service and indicates to the outside world whether the service wants to shut down. I called it StopFlag.

              public sealed class WindowsBackgroundService(
                  MyWindowsService myWindowsService,
                  ILogger logger) : BackgroundService
              {
                  protected override async Task ExecuteAsync(CancellationToken stoppingToken)
                  {
                      try
                      {
                          myWindowsService.OnStart(new string\[0\]);
              
                          while (!stoppingToken.IsCancellationRequested && !myWindowsService.StopFlag)
                          {
                              await Task.Delay(TimeSpan.FromSeconds(1), stoppingToken);
                          }
                      }
                      catch (OperationCanceledException)
                      {
                          // When the stopping token is canceled, for example, a call made from services.msc,
                          // we shouldn't exit with a non-zero exit code. In other words, this is expected...
                      }
                      catch (Exception ex)
                      {
                          logger.LogError(ex, "{Message}", ex.Message);
              
                          // Terminates this process and returns an exit code to the operating system.
                          // This is required to avoid the 'BackgroundServiceExceptionBehavior', which
                          // performs one of two scenarios:
                          // 1. When set to "Ignore": will do nothing at all, errors cause zombie services.
                          // 2. When set to "StopHost": will cleanly stop the host, and log errors.
                          //
                          // In order for the Windows Service Management system to leverage configured
                          // recovery options, we need to terminate the process with a non-zero exit code.
                          Environment.Exit(1);
                      }
                  }
              
              J Offline
              J Offline
              jochance
              wrote on last edited by
              #6

              So.... Environment.Exit([exit_code]); ?? Not on this yet, but soon enough. Real soon, if I have it my way. I think it does that abstraction to help with the way it facades for running services in local debug without them actually being services? It seems like we DIY'd that into the old stuff.

              1 Reply Last reply
              0
              Reply
              • Reply as topic
              Log in to reply
              • Oldest to Newest
              • Newest to Oldest
              • Most Votes


              • Login

              • Don't have an account? Register

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • World
              • Users
              • Groups