none
Calling remote API on Windows service OnShutdown event. RRS feed

  • Question

  • Hi, 

    I have a window service which is detecting the device and system status. I need send a signal to remote API stating system has been shutdown by user. For this we can use following approaches: 

     1. Use windows service OnShutdown event. But when i am using it, it is never called. I have already set CanShutdown= true.

     2. Register Pre-shutdown in service constructor then and then call OnCustomCommand event to send signal to API.

    My first approach never worked. Please help me call this event in windows service.

    Second approach is working after turning off the  Fast Startup in power management. But with this approach, i am able to send data to API when it connected to LAN cable. But on WLAN, i am getting exception of remote server not found.

    Please help me resolve this issue, so that this could work with both LAN , WLAN or please suggest another way of doing this.

    See my code :

    public MonSService()
            {
                FieldInfo acceptedCommandsFieldInfo = typeof(ServiceBase).GetField("acceptedCommands", BindingFlags.Instance | BindingFlags.NonPublic);
                if (acceptedCommandsFieldInfo == null)
                    throw new ApplicationException("acceptedCommands field not found");

                int value = (int)acceptedCommandsFieldInfo.GetValue(this);
                acceptedCommandsFieldInfo.SetValue(this, value | SERVICE_ACCEPT_PRESHUTDOWN);
                
                InitializeComponent();

            }

     protected override void OnCustomCommand(int command)
            {

                Logger.Instance.LogInfo("Custom pre-shutdown hit..");
                if (command == SERVICE_CONTROL_PRESHUTDOWN)
                {
                    Logger.Instance.LogInfo("Custom pre-shutdown hit..");
                    var content = new FormUrlEncodedContent(new[]
                    {
                        new KeyValuePair<string, string>("", "custom pre-shutting down...")
                   });
                    try
                    {
                        var client = new HttpClient { BaseAddress = new Uri("http://172.30.68.50:9900") };
                        client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/x-www-form-urlencoded");
                        
                        var response = client.PostAsync("/api/values", content).Result;
                    }
                    catch (Exception ex)
                    {
                        Logger.Instance.LogError("api hitting..: "+ ex.InnerException);
                    } 
                }
            }

    Wednesday, August 21, 2019 12:32 PM

All replies

  • Hello,

    Can you try this an add Debugger.Launch() as the first line of code before base.OnCustomCommand, see if the JIT hits this and ask to debug.

    protected override void OnCustomCommand(int command)
            {
                base.OnCustomCommand(command);


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Wednesday, August 21, 2019 12:43 PM
    Moderator
  • Firstly, are you running the service under an account that has network access? Most people run services as SYSTEM which doesn't have network access. You'll need to run it as at least NETWORK SERVICE if not a domain account.

    Secondly, OnShutdown is not guaranteed to be called in all cases. For example a power loss will not trigger the event as there isn't time. Also be aware that shutdown is very time sensitive. As documented here you really don't have a lot of time to make remote network calls. In fact you probably shouldn't as this will slow down everything and it isn't reliable in most cases.

    Personally I think you're going about this incorrectly. There are too many cases where your service will not be running but it won't send the necessary notification (aka the service is stopped or terminates). If you want to know whether a machine is shut down or not then either poll the machine directly and/or read the event logs. The logs will contain an event when the machine is shut down. If it was graceful then the log will be there before shutdown otherwise the system will write it when it comes back up.

    If you really need to do this via your service then a better approach might be to send a ping to the API periodically instead. The remote API knows when it got the last ping so if enough time has elapsed since the last ping either the machine is offline or the service has stopped.


    Michael Taylor http://www.michaeltaylorp3.net

    Wednesday, August 21, 2019 1:55 PM
    Moderator
  • Thanks for replying Michael,

    I am running the service in network account. this why i am able to send signal to API while connected to LAN cable.

    But it is not sending data while system is connected to WLAN.

    I really need to distinguish among shutdown, network disconnected or power off. With the ping approach, i wont be able to differentiate shutdown or power off. 

    I am really curious to know why i am able to send signal to API while connected to Ethernet cable but not able to send when connected to wireless LAN.

    Thanks..

    Thursday, August 22, 2019 9:24 AM
  • LAN and WLAN would be using 2 different network connections. Are you testing this by starting with the LAN enabled and then pulling out the cable to see what happens with the WLAN? If so then that isn't going to work properly.

    You're using HttpClient (which by the way you should create once and reuse for the life of your app otherwise you will run out of sockets eventually). Under the hood that uses the HttpWebRequest which ultimately relies on ServicePoint (as does almost everything else). ServicePoint, as discussed here, caches connection information to avoid the hit for DNS lookup and whatnot. If you rip the network out from under it (which is what happens when you switch from LAN to WLAN) then that data is no longer valid and you'll potentially get an error when you try to connect again. The connection info should be dropped and a subsequent call should then create a new connection properly. When you switch back the other way the same thing happens. If you need to support this scenario then you're going to need to introduce retry policies. Polly is a popular library for adding this into HttpClient.


    Michael Taylor http://www.michaeltaylorp3.net

    Thursday, August 22, 2019 1:53 PM
    Moderator