23
votes

I developed a http server via console application in C# and decided to turn it into a Windows service to be able to initialize it without the need to login the machine.

I followed all the steps in How to create Windows Service and chose the account as "Local System", but when I install in my server machine and push the start button it takes a while and gives the following error:

Erro 1053: The service did not respond to the start or control request in timely fashion.

After that, the service status stays stuck in "starting" and the application don't work and I can't even stop the service anymore.

Trying to work around this problem, I changed it to "Network Service", so it started normally, but the application was not listening in the port I set when I checked in the prompt with the command "netstat -an". But the application listens normally if i run it as a console application.

So I am looking for an answer to one of these two questions:

  1. What should I do to make the service starts properly with a Local System account?
  2. If I decide to use Network service account, what should I care about to guarantee that my service works properly as a server?
6
OnStart should finish in 30 seconds. Refer this: stackoverflow.com/questions/2631364/c-sharp-windows-serviceOrçun Çolak

6 Answers

32
votes

When I converted my console application to windows service I simply put my code directly in the OnStart method. However, I realized the OnStart method should start the service, but needs to end some time to the service indeed start. So I created a thread that runs my service and let the OnStart method finish. I tested and the service worked just fine. Here is how it was the code:

protected override void OnStart(string[] args)
{
    Listener(); // this method never returns
}

Here is how it worked:

protected override void OnStart(string[] args)
{
    Thread t = new Thread(new ThreadStart(Listener));
    t.Start();
}

But I still don't understand why the service ran (passed the "starting" status, but didn't work) when I used network service account. If anyone knows, I'll be glad to know the reason.

14
votes

If you have a service that is not responding or showing pending in Windows services that you are unable to stop, use the following directions to force the service to stop.

  • Start -> Run or Start -> type services.msc and press Enter
  • Look for the service and check the Properties and identify its service name
  • Once found, open a command prompt. Type sc queryex [servicename]
  • Identify the PID (process ID)
  • In the same command prompt type taskkill /pid [pid number] /f
0
votes

Check the Windows Application event log, it could contain some entries from your service's auto generated event source (which should have the same name of the service).

0
votes

For me it was a while loop that looked at an external queue. The while-loop continued running until the queue was empty. Solved it by calling a timer event directly only when Environment.UserInteractive. Therefore the service could be debugged easily but when running as a service it would wait for the timers ElapsedEventHandler event.

Service:

partial class IntegrationService : ServiceBase
{
    private static Logger logger = LogManager.GetCurrentClassLogger();
    private System.Timers.Timer timer;

    public IntegrationService()
    {
        InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
        try
        {
            // Add code here to start your service.
            logger.Info($"Starting IntegrationService");

            var updateIntervalString = ConfigurationManager.AppSettings["UpdateInterval"];
            var updateInterval = 60000;
            Int32.TryParse(updateIntervalString, out updateInterval);

            var projectHost = ConfigurationManager.AppSettings["ProjectIntegrationServiceHost"];
            var projectIntegrationApiService = new ProjectIntegrationApiService(new Uri(projectHost));
            var projectDbContext = new ProjectDbContext();
            var projectIntegrationService = new ProjectIntegrationService(projectIntegrationApiService, projectDbContext);
            timer = new System.Timers.Timer();
            timer.AutoReset = true;
            var integrationProcessor = new IntegrationProcessor(updateInterval, projectIntegrationService, timer);
            timer.Start();
        }
        catch (Exception e)
        {
            logger.Fatal(e);
        }
    }

    protected override void OnStop()
    {
        try
        {
            // Add code here to perform any tear-down necessary to stop your service.
            timer.Enabled = false;
            timer.Dispose();
            timer = null;
        }
        catch (Exception e)
        {
            logger.Fatal(e);
        }
    }
}

Processor:

public class IntegrationProcessor
{
    private static Logger _logger = LogManager.GetCurrentClassLogger();
    private static volatile bool _workerIsRunning;
    private int _updateInterval;
    private ProjectIntegrationService _projectIntegrationService;

    public IntegrationProcessor(int updateInterval, ProjectIntegrationService projectIntegrationService, Timer timer)
    {
        _updateInterval = updateInterval;
        _projectIntegrationService = projectIntegrationService;

        timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
        timer.Interval = _updateInterval;

        //Don't wait for first elapsed time - Should not be used when running as a service due to that Starting will hang up until the queue is empty
        if (Environment.UserInteractive)
        {
            OnTimedEvent(null, null);
        }
        _workerIsRunning = false;
    }

    private void OnTimedEvent(object source, ElapsedEventArgs e)
    {
        try
        {
            if (_workerIsRunning == false)
            {
                _workerIsRunning = true;

                ProjectInformationToGet infoToGet = null;
                _logger.Info($"Started looking for information to get");
                //Run until queue is empty
                while ((infoToGet = _projectIntegrationService.GetInformationToGet()) != null)
                {
                    //Set debugger on logger below to control how many cycles the service should run while debugging.
                    var watch = System.Diagnostics.Stopwatch.StartNew();
                    _logger.Info($"Started Stopwatch");
                    _logger.Info($"Found new information, updating values");
                    _projectIntegrationService.AddOrUpdateNewInformation(infoToGet);
                    _logger.Info($"Completed updating values");
                    watch.Stop();
                    _logger.Info($"Stopwatch stopped. Elapsed seconds: {watch.ElapsedMilliseconds / 1000}. " +
                                 $"Name queue items: {infoToGet.NameQueueItems.Count} " +
                                 $"Case queue items: {infoToGet.CaseQueueItems.Count} " +
                                 $"Fee calculation queue items: {infoToGet.FeeCalculationQueueItems.Count} " +
                                 $"Updated foreign keys: {infoToGet.ShouldUpdateKeys}");
                }

                _logger.Info($"Nothing more to get from integration service right now");

                _workerIsRunning = false;
            }
            else
            {
                _logger.Info($"Worker is already running! Will check back again after {_updateInterval / 1000} seconds");
            }
        }
        catch (DbEntityValidationException exception)
        {
            var newException = new FormattedDbEntityValidationException(exception);
            HandelException(newException);
            throw newException;
        }
        catch (Exception exception)
        {
            HandelException(exception);
            //If an exception occurs when running as a service, the service will restart and run again
            if (Environment.UserInteractive)
            {
                throw;
            }
        }
    }

    private void HandelException(Exception exception)
    {
        _logger.Fatal(exception);
        _workerIsRunning = false;
    }
}
0
votes

You can try to increase the windows service timeout with a key in the registry

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control

"ServicesPipeTimeout"=dword:300000 (300 seconds or 5 minutes)

If it doesn't exists it has to be created.

0
votes

Find PID of Service

sc queryex <SERVICE_NAME>

Give result's below

SERVICE_NAME: Foo.Services.Bar TYPE : 10 WIN32_OWN_PROCESS STATE : 2 0 START_PENDING (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN) WIN32_EXIT_CODE : 0 (0x0) SERVICE_EXIT_CODE : 0 (0x0) CHECKPOINT : 0x0 WAIT_HINT : 0x0 PID : 3976 FLAGS :

Now Kill the Service:

taskkill /f /pid 3976

SUCESS: The process with PID 3976 has been terminated.