As the title says, I'm trying to start a service created at run-time, but I always end-up getting the 'timeout' exception, as the service status does not change to Running and hangs on Starting forever.
Here's my StartService() function:
private void StartService()
{
ServiceController service = new ServiceController(serviceName);
try
{
SaveProject();
if (!CheckServiceExist(serviceName))
CreateService();
TimeSpan timeout = TimeSpan.FromMilliseconds(30000);
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running, timeout);
}
catch (Exception ex)
{
Trace.Writeline(ex.ToString());
}
}
I can confirm that CreateService() is doing what is supposed to do flawlessy.
When I call from Visual Studio (2013) the first time, it occurs as described. BUT, when I run again, it works like a charm! When I run outside Visual Studio, it hangs on Starting and I can't either Start or Stop it through Windows Task Manager nor Windows Services.
I'm using WCF and Windows Service, and the StartService() is called from a button Command, if that helps at all. Thanks in advance.
Please take a look at this MSDN page.
Under Setting Service Status you will find "If a service takes a little while to start up, it might be helpful to report a Start Pending status". There is a detailed explanation how to tell the windows service manager that your service is still in startup process and avoid a timeout.
// Update the service state to Start Pending.
ServiceStatus serviceStatus = new ServiceStatus();
serviceStatus.dwCurrentState = ServiceState.SERVICE_START_PENDING;
serviceStatus.dwWaitHint = 100000;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
But this will only help if the timeout is really the problem on your service implementation.
Related
I am dabbling with Windows services.
From what I've read and the tutorials I've covered (one example) I see that all the work must be done in the OnStart method of the service.
As far as I understand it (from the only tutorials I was able to find, which were completely basic) after the OnStart method returns the service can't do anything if you haven't, somehow, configured it in the method.
I saw the use of timers in said method to trigger events every X seconds but what I am looking for is to detect window focus changes (when a program tries to bring its window to the front). The solution in this answer works perfectly when I try it in a console application but I want to use it in my service.
However, simply registering the eventhandler in the OnStart method does not work - it doesn't get triggered and has no effect. I tried putting a timer just to keep the OnStart method going but that didn't help, either - the timer was running and it was doing work each tick but the eventhandler never fired (I put a File.AppendText for each timer tick and each time the handler fires but in the text file I used as a control only the timer ticks were appended).
Lastly, I tried running a Task (by using Task.Run to create a new thread) which ran an endless loop in a separate method from OnStart but that just made the service start hang as it went on and on.
Code:
protected override void OnStart(string[] args)
{
File.WriteAllText("file.txt", "START");
eventLog.WriteEntry("Entered OnStart method.");
// Update the service state to "Start Pending".
ServiceStatus serviceStatus = new ServiceStatus
{
dwCurrentState = ServiceState.SERVICE_START_PENDING,
dwWaitHint = 100000
};
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
eventLog.WriteEntry("Start Pending.", EventLogEntryType.Information);
// Update the service state to "Running".
serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
eventLog.WriteEntry("Running.", EventLogEntryType.Information);
Task.Run(KeepBusy());
}
private static Action KeepBusy()
{
Automation.AddAutomationFocusChangedEventHandler(OnFocusChangedHandler);
while (true)
{
Thread.Sleep(1000);
}
}
In short - if I correctly understand services can only perform work in the OnStart method I am disgusted at how stupid this seems and can't figure out how to make a "listener" service
As a First step I created Windows Service project configured it properly and
On second Step I have added TopShelf Version 3.1.135.0 in my project If I run my service through (F5 Run) then it is loading Top-shelf Console and service is completed successfully.
However When I am running it to install and Start it from command prompt I am having below TimeOut Error.
Topshelf.Hosts.StartHost Error: 0 : The service failed to start., System.Service
Process.TimeoutException: Time out has expired and the operation has not been co
mpleted.
public class AppService
{
LoggingService loggingService = new LoggingService(typeof(AppService).Name);
public void Start()
{
loggingService.Info("SampleService is Started");
ExtractProcess.Start();
TransformProcess.Start();
}
public void Stop()
{
loggingService.Info("SampleService is Stopped");
}
}
-- Updated Code to fix this issue
public void Start()
{
loggingService.Info("MPS.GOA.ETLService is Started");
ThreadStart myThreadDelegate = new ThreadStart(StartService);
Thread myThread = new Thread(myThreadDelegate);
myThread.Start();
}
private void StartService()
{
timer.Elapsed += new System.Timers.ElapsedEventHandler(OnElapsedTime);
timer.Interval = 60000 * ServiceIntervalInMinutes; //1 minute 60000 milliseconds
timer.Enabled = true;
Process();
}
private void Process()
{
ExtractProcess.Start();
TransformProcess.Start();
}
Any Suggestions?
This error is happening because you are running the extract and process methods in the Start method of the service. This is OK in Visual Studio, but when you install the service and start it, the Service Control Manager waits for the Start method to return, and if it does not do so within a certain time (30 seconds by default) then it will return this error.
You have several options, all of which will allow the Start method to return immediately:
Invoke the extract and transform methods on a separate thread
Invoke the extract and transform methods asynchronously
Use a timer to start the extract and transform process
In case you (like me) is struggling to get the service to start - and all you've found so far is references to starting work in a separate thread (and you already did) this might be the solution right here..
My problem was that I had an external JSON config file being read from the project's directory path. What I needed was to get the assembly path, so that when the .NET application is published and installed with Topshelf - it looks for the config file at the right place.
string assemblyPath = Path.GetDirectoryName(typeof(MyConfigManagerClass).Assembly.Location);
var builder = new ConfigurationBuilder()
.SetBasePath(assemblyPath)
.AddJsonFile("config.json", optional: false);
myConfigurationObject = builder.Build();
Topshelf gave an error saying the service couldn't be started, but now I finally know why.
In my case it was neither of the above solutions that solved it, but actual permissions within the topshelf service, that required access to a file that resided in an external server.
TopShelf program running on test server
Log file located on Production server
Test server does not have access to external servers, for security
reasons.
So I changed the program to refer everything internally inside it's own server, and it worked fine.
I'm fairly new to c# and am in the process of writing a system service. One of the first things that the service needs to do is connect to the internet and download a new settings file. However, as there is no guarantee that the machine it is running on will have an internet connection at startup, the service needs to intermittently attempt to download the file.
The problem I'm having is that by sitting in a loop attempting to download the file the service times out (fails to start).
How can I create a loop that will poll my server intermittently while still allowing the service startup to complete?
UPDATE
I have put together the following code. It appears to work in a non-blocking way, but I cannot work out how to stop the timer from within the netCheck function?
public static void Start()
{
// Start the system timer update
System.Timers.Timer time = new System.Timers.Timer();
time.Interval = 5*1000; // 3hrs
time.Elapsed +=new System.Timers.ElapsedEventHandler(netCheck);
time.Start();
}
public static void netCheck(object sender, EventArgs e)
{
try
{
WebClient webClient = new WebClient();
string download = webClient.DownloadString("http://www.domain.com/ping.php");
if (!string.IsNullOrEmpty(download))
{
//stop the clock
}
else
{
Console.WriteLine("No Net...");
}
}
catch (Exception)
{
Console.WriteLine("No Net...");
}
}
You can just set your service's startup type to Automatic (Delayed Start), as shown below. This will allow your network connection to be running and in place before your service starts.
Or, if it's still possible that you won't have an internet connection, even after a delayed start, have your service start a timer and check for an internet connection in your timer callback.
From https://superuser.com/a/285655:
A service marked as Automatic (Delayed Start) will start shortly after
all other services designated as Automatic have been started.
It's easy. Just set Enable to false
time.Enable=false;
I have the following scenario:
My main Application (APP1) starts a Process (SERVER1). SERVER1 hosts a WCF service via named pipe. I want to connect to this service (from APP1), but sometimes it is not yet ready.
I create the ChannelFactory, open it and let it generate a client. If I now call a method on the generated Client I receive an excpetion whitch tells me that the Enpoint was not found:
var factory = new ChannelFactory<T>(new NetNamedPipeBinding(), new EndpointAddress("net.pipe//localhost/myservice");
factory.Open()
var Client = factory.CreateChannel();
Client.Foo();
If I wait a little bit before calling the service, everything is fine;
var Client = factory.CreateChannel();
Thread.Sleep(2000);
Client.Foo();
How can I ensure, that the Service is ready without having to wait a random amount of time?
If the general case is that you are just waiting for this other service to start up, then you may as well use the approach of having a "Ping" method on your interface that does nothing, and retrying until this starts responding.
We do a similar thing: we try and call a ping method in a loop at startup (1 second between retries), recording in our logs (but ultimately ignoring) any TargetInvocationException that occur trying to reach our service. Once we get the first proper response, we proceed onwards.
Naturally this only covers the startup warmup case - the service could go down after a successfull ping, or it we could get a TargetInvocationException for a reason other than "the service is not ready".
You could have the service signal an event [Edited-see note] once the service host is fully open and the Opened event of the channel listener has fired. The Application would wait on the event before using its proxy.
Note: Using a named event is easy because the .NET type EventWaitHandle gives you everything you need. Using an anonymous event is preferable but a bit more work, since the .NET event wrapper types don't give you an inheritable event handle. But it's still possible if you P/Invoke the Windows DuplicateHandle API yourself to get an inheritable handle, then pass the duplicated handle's value to the child process in its command line arguments.
If you're using .Net 4.0 you could use WS-Discovery to make the service announce its presence via Broadcast IP.
The service could also send a message to a queue (MSMQ binding) with a short lifespan, say a few seconds, which your client can monitor.
Have the service create a signal file, then use a FileSystemWatcher in the client to detect when it gets created.
Just while (!alive) try { alive = client.IsAlive(); } catch { ...reconnect here... } (in your service contract, you just have IsAlive() return true)
I have had the same issue and when using net.pipe*://localhost/serviceName*, I solved it by looking at the process of the self-hosted application.
the way i did that was with a utility class, here is the code.
public static class ServiceLocator
{
public static bool IsWcfStarted()
{
Process[] ProcessList = Process.GetProcesses();
return ProcessList.Any(a => a.ProcessName.StartsWith("MyApplication.Service.Host", StringComparison.Ordinal));
}
public static void StartWcfHost()
{
string path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var Process2 = new Process();
var Start2 = new ProcessStartInfo();
Start2.FileName = Path.Combine(path, "Service", "MyApplication.Service.Host.exe");
Process2.StartInfo = Start2;
Process2.Start();
}
}
now, my application isn't called MyApplication but you get my point...
now in my client Apps that use the host i have this call:
if (!ServiceLocator.IsWcfStarted())
{
WriteEventlog("First instance of WCF Client... starting WCF host.")
ServiceLocator.StartWcfHost();
int timeout=0;
while (!ServiceLocator.IsWcfStarted())
{
timeout++;
if(timeout> MAX_RETRY)
{
//show message that probably wcf host is not available, end the client
....
}
}
}
This solved 2 issues,
1. The code errors I had wend away because of the race condition, and 2
2. I know in a controlled manner if the Host crashed due to some issue or misconfiguration.
Hope it helps.
Walter
I attached an event handler to client.InnerChannel.faulted, then reduced the reliableSession to 20 seconds. Within the event handler I removed the existing handler then ran an async method to attempt to connect again and attached the event handler again. Seems to work.
I'm developing a service using .NET on Windows platforms.
It had worked until yesterday... but today it doesn't want to start!!! It seems strange, and I feel I'm missing something...
I've also tried to revert sources to the last working version, but nothing else happens: net start outputs:
The service is not responding to the control function.
What could cause this malfunction?
Probably most of you wants to know more about it. So, let me show you some code:
The service code:
#if DEBUG
class iGeckoService : DebuggableService
#else
class iGeckoService : ServiceBase
#endif
{
static void Main()
{
#if DEBUG
if (Debugger.IsAttached == true) {
DebuggableService[] services = Services;
// Create console
AllocConsole();
// Emulate ServiceBase.Run
foreach (DebuggableService service in services)
service.Start(null);
// Wait for new line
Console.WriteLine("Press ENTER to exit..."); Console.ReadLine();
// Emulate ServiceBase.Run
foreach (DebuggableService service in services)
service.Stop();
} else
ServiceBase.Run(Services);
#else
ServiceBase.Run(Services);
#endif
}
#if DEBUG
static DebuggableService[] Services
{
get {
return (new DebuggableService[] { new iGeckoService() });
}
}
[DllImport("kernel32")]
static extern bool AllocConsole();
#else
static DebuggableService[] Services
{
get {
return (new ServiceBase[] { new iGeckoService() });
}
}
#endif
#endregion
#region Constructors
/// <summary>
/// Default constructor.
/// </summary>
public iGeckoService()
{
// Base properties
ServiceName = DefaultServiceName;
// Service feature - Power events
}
#endregion
protected override void OnStart(string[] args)
{
try {
...
} catch (Exception e) {
sLog.Error("Unable to initialize the service. Request to stop.", e);
}
}
/// <summary>
/// Stop this service.
/// </summary>
protected override void OnStop()
{
...
}
}
[RunInstaller(true)]
public class iGeckoDaemonInstaller : Installer
{
/// <summary>
/// Default constructor.
/// </summary>
public iGeckoDaemonInstaller()
{
ServiceProcessInstaller spi = new ServiceProcessInstaller();
spi.Account = ServiceAccount.LocalSystem;
ServiceInstaller si = new ServiceInstaller();
si.ServiceName = iGeckoService.DefaultServiceName;
si.StartType = ServiceStartMode.Automatic;
Installers.AddRange(new Installer[] {spi, si});
}
}
class DebuggableService : ServiceBase
{
public void Start(string[] args) { OnStart(args); }
}
The start script is:
installutil ..\bin\Debug\iGeckoService.exe
net start "Gecko Videowall"
while the stop script is:
net stop "Gecko Videowall"
installutil /u ..\bin\Debug\iGeckoService.exe
However, I think it is a system setting, since the application has worked well until the last day. (Sigh).
Update
When the service was working, I used log4net for logging service activity (I'm unable to attach the debugger to the running service...), and it has always logged.
From now, the log4net log it is never created (even if I enable internal debug option), even if I log at the Main routine!
Another update
It seems that the application is never executed. I've reduced every routine (Main, OnStart, OnStop), and I run an empty service. OnStart routine creates a file on a directory (fully writeable by everyone), but when the service is started, no file is created.
Yet another update
Stimulated by the Rob's comment, I've seen this message on the event viewer:
> Faulting application name: iGeckoService.exe, version: 1.0.0.0, time stamp: 0x4c60de6a
> Faulting module name: ntdll.dll, version: 6.1.7600.16385, time stamp: 0x4a5be02b
> Exception code: 0x80000003
> Fault offset: 0x000000000004f190
> Faulting process id: 0x1258
> Faulting application start time: 0x01cb384a726c7167
> Faulting application path: C:\Users\Luca\Documents\Projects\iGeckoSvn\iGeckoService\bin\Debug\iGeckoService.exe
> Faulting module path: C:\Windows\SYSTEM32\ntdll.dll
> Report Id: b096a237-a43d-11df-afc4-001e8c414537
This is, definitively, the reason on the service shutdown... not question becomes: "How to debug it?" (Thank you Rob, I've never thought about the event viewer until now!)
Debugging it running as console application it doesn't show any error, indeed it seems related to the service environment. The only thing that comes to my mind could be some DLL loading failure, since now the service is empty... any idea?
(Thank you all for following me... I'd like to offer you pizza & beer)
Solved!
The service was unable to start since a crash before the Main routine, caused by the installation and the setup of the MS Application Verifier (x64). After having uninstalled that application, everything worked as usual!
Thank you all!
In general every service must do following two simple things
if the service manager send him a control code like SERVICE_CONTROL_START, SERVICE_CONTROL_STOP and so on if should return in a short interval. Using SetServiceStatus function service can prolong this interval for example with calling SetServiceStatus with incremented dwCheckPoint value. (In .NET use can use ServiceBase.RequestAdditionalTime instead)
every service must answer to SERVICE_CONTROL_INTERROGATE control code just with return. This control code are used from the service manager to detect whether the service still living.
If your program don't follow one of the rules you receive the error "The service is not responding to the control function."
If you write a program in .NET you don't need to do directly the two things which I described before. The ServiceBase class do there for you. Nevertheless you can easy break this rules if create a thread running with priority higher as normal or if you do some too long work inside an OnXXX handle (OnStop, OnStart, OnPowerEvent etc) without calling of ServiceBase.RequestAdditionalTime. Some other tricks with additional threads can also make problems.
Usually this happens if you're trying to do too much work in the OnStart call. For example, if you start an endless loop in the same thread, you'll get this error message.
Generally the service should create a new thread in the OnStart call, and then cleanly terminate it in the OnStop call.
Of course that doesn't help if you're using code which was previously working. Have you tried rebooting it since the failure? I seem to remember that if you've already got a service which is borked, it can sometimes be tricky to get back to a working state without rebooting it. You may want to look in your process list and see whether you've got a copy still running, and kill it if so.
For me it just meant that an exception was being thrown. (Platform conflict in Configuration Manager, resulting in "bad image format".) Try running the .exe from the command line and see if you get an error.
I see that there is a code block
// Wait for new line
Console.WriteLine("Press ENTER to exit..."); Console.ReadLine();
as stated by #Jon since this is a service. when service starts it waits for a stipulated time within which it should respond.
there is a statement "Console.ReadLine()" you service will wait until key is pressed. since this is a service will keep waiting at this point
For me it was an error in the file that is configured to the windows service. I found a syntax error due to which I was getting this error code.
Fixed the syntax error and I was able to restart the service again.