I have a C# Windows Service. The OnStart() method contains 3 lines that all they do is start a thread. The class itself has no static objects that would cause a delay. It is as simple as a service can be. My code is signed by a self made key.
Edit: I just figured out that assembly isn't signed, the rest are. It uses a few assemblies which are signed but the service itself isn't.
This code is running inside a virtual machine, whenever the host is running slow and this VM is booting up, the service will fail to start with this error:
A timeout was reached (30000 milliseconds) while waiting for the ServiceName service to connect.
Setting the service to delay start fixes it but it's a long delay and it's very annoying. Has anyone else had this problem with .NET services (2.0)?
The OnStart method:
protected override void OnStart(string[] args)
{
Thread startThread = new Thread(new ThreadStart(StartThread));
startThread.IsBackground = true;
startThread.Start();
}
The StartThread method, in which all I do is call another class so that the OnStart won't have to wait for static variable initialization or for the constructor method to end.
private void StartThread()
{
Worker mainThread = new Worker(this);
mainThread.RunWorker();
}
Thank you.
I think this is most likely due to the strong name signing that you have on your executable. In general, it's not good practice to do that on executables (see here). I have also experienced the same problem in one of my projects, where an executable took an incredible amount of time to start, and turned out it was due to strong name signing the executable (.NET 2.0 as well).
Consider turning AutoLog = false. I've seen where this flag can cause the timeout you're describing.
Related
I have created a windows service app which has OnStart method. The method will read a path from the app.config file, create an object, then the service write the object's overridden ToString() method to a file with a StreamWriter.
This is working when I manually start this service with "net start". So the OnStart method called, object created and written its ToString method to a file.
I set it as an automatic running service, when the Windows starts up.
My problem is, that this OnStart method is not called after the service is being started by Windows. So I think when the windows starts running the services at start up, it launches my service just don't calling the OnStart method.
Does anybody have the same issue or somebody have a solution for it?
OnStart method:
protected override void OnStart(string[] args)
{
filePath = configReader.ReadConfig("FilePath");
DateEvent dateEvent = new DateEvent(DateTime.Now, TimeLoggerCore.Events.STARTUP.ToString());
writer.WriteToFile(dateEvent, filePath, true, false);
}
Constructor:
public TimeLoggerService()
{
InitializeComponent();
configReader = new AppConfigReader();
writer = new CSVWriter();
}
Program.cs:
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new TimeLoggerService()
};
ServiceBase.Run(ServicesToRun);
}
Since your service starts when you attempt to start it from a command-line using net.exe start [ServiceName] but fails to start when windows is started, perhaps it is encountering an exception during startup.
One important thing to note when building and working with a custom Windows service is that the Windows Event Log can be very helpful in tracking down problems. When errors occur in a service, it's worthwhile to log that error in the event log.
Another helpful to debug your running service in Visual Studio is to start your service then attach the VS debugger to it.
To get some Windows event log logging into your service, I suggest modifying your service's code to log its startup. Note that what I've posted here is simplified for this forum - I typically put all logging code into a separate class. This way I can use it throughout the life of my service. One important note - be sure to set the ServiceName property of your main service class with an appropriate name - this should be done in Visual Studio at design time in the Properties window of the service designer.
private EventLog _eventLog;
/*
* Use the EventId enumeration to store event IDs that will be written with events
* to the Windows event log.
*/
enum EventId
{
ServiceStarting = 10,
ServiceStartNormal = 100,
ServiceStartFailure = 999;
}
protected override void OnStart(string[] args)
{
try
{
// remember the event log
_eventLog = EventLog;
// log start
LogMessage(_eventLog, "Service starting", EventLogEntryType.Information, EventId.ServiceStarting);
filePath = configReader.ReadConfig("FilePath");
DateEvent dateEvent = new DateEvent(DateTime.Now, TimeLoggerCore.Events.STARTUP.ToString());
writer.WriteToFile(dateEvent, filePath, true, false);
LogMessage(_eventLog, "Service started", EventLogEntryType.Information, EventId.ServiceStartNormal);
}
catch(Exception e)
{
LogMessage(_eventLog, e.ToString(), EventLogEntryType.Error, EventId.ServiceStartFailure);
}
}
private static void LogMessage(EventLog eventLog, string message, EventLogEntryType entryType, EventId eventId)
{
/*
* If the event source we want to log doesn't exist, create it.
* Note that this take admin privs, and creating the log source should be
* done during service installation. This is here as a secondary means
* to create the log in the event that it doesn't already exist.
*/
if (!EventLog.SourceExists(eventLog.Source)
{
EventLog.CreateEventSource(eventLog.Source, eventLog.Log);
}
eventLog.WriteEntry(message, entryType, (int) eventId);
}
After adding this code to your service, re-deploy it, restart your system, and then check the event log. At a minimum you should see a message logged at service start.
I had the same issue with my service, and after a lot of digging I found out that the reason why OnStop and OnStart were not called is because of the windows fast startup option.
I put logging in all the functions of the ServiceBase that can be overriden and the one that was called when I shut down my laptop was OnPowerEvent, not OnStop.
My event log
Everything was working as expected when I was restarting windows instead of shutting them down.
Hope that this will help someone.
If the event viewer shows that the service was started successfully, your OnStart has been called and has been returned from. How did you determine that is was not called? I guess by the fact that your file has not been written to. The problem is likely not that your OnStart is not called but that the WriteToFile failed and/or it was written to a different location (e.g. you use a relative path which is different or unavailable during startup). I suggest the following procedure to check this:
Use System.Diagnostics.Trace.WriteLine to output debug messages in your OnStart
Download and install/copy the DebugView application from Microsoft.
Configure DebugView to 1) Capture Global Win32, 2) Set a filter on Process Name with your application name and 3) Enable Logging at Boot Time (see the DebugView help).
Experiment a bit with all setting to make sure they work as intended.
Finally, also note this remark in the OnStart documentation:
Do not use the constructor to perform processing that should be in OnStart. Use OnStart to handle all initialization of your service. The constructor is called when the application's executable runs, not when the service runs. The executable runs before OnStart. When you continue, for example, the constructor is not called again because the SCM already holds the object in memory. If OnStop releases resources allocated in the constructor rather than in OnStart, the needed resources would not be created again the second time the service is called.
As you mentioned Windows start up, did you place your executable in the startup folder? If yes, that will not work that way. You need to install the service in the windows service manager. Microsoft Description for installing services
I'm quite new to development of Windows Services (my background is in Web Development) and I'm a bit confused by the development process for Windows Services.
As I understand it, the service has to be installed every time you compile the code, and then run from the Services MMC snapin.
This seems like an awfully painful process to go through every time you make a change to your code.
Can someone shed some light on the 'recommended' approach for building services?
Thanks
To debug services, I generally use the following boilerplate for Main:
static void Main()
{
ServiceBase[] servicesToRun = new ServiceBase[] { new MyService(); };
#if !DEBUG
//run the service normally using ServiceBase.Run
ServiceBase.Run(servicesToRun);
#else
//debug the process as a non-service by invoking OnStart and then sleeping
foreach (ServiceBase s in servicesToRun)
{
var serviceType = s.GetType();
var onStartMethod = serviceType.GetMethod("OnStart", System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic);
onStartMethod.Invoke(s, new object[] { new string[0] });
}
Debug.WriteLine("done starting services");
while (true)
Thread.Sleep(200);
#endif
}
What this does is use reflection to get the OnStart protected method for each service, invoke it, then sit in a sleep loop to keep the process running.
This example is assuming MyService is the service class that inherits from ServiceBase, which overrides OnStart to spawn off thread(s) and do its thing.
Here I'm using the DEBUG compile-time constant as the controlling factor of whether to start normally or debug as a non-service. If DEBUG is defined it will run in-process as a non-service. Otherwise it does its normal thing calling ServiceBase.Run. Feel free to use a command-line argument or whatever works best for you.
You may need some tweaks or re-factoring most of the logic to console app for easier testing, debugging, as what comes out of the box is really painful.
Here are some resources :
http://candordeveloper.com/2012/12/27/debugging-a-windows-service-application-without-install/
Running Windows Service Application without installing it
the easiest of them might be putting
#if DEBUG
//your logic
#endif
in your logic, putting a breakpoint and hitting F5, this is what i do most of the time.
Would be interesting to know if there is even better ways :)
Answers from Bravo 11 and Ic. give some good tips and tricks. I will add some:
Be aware that running as as service has also some implications regarding login / security context:
running under SYSTEM, you cannot access network file shares normally (there is a way adding the machine account to the ACL however)
running under a (domain) user account needs "logon as service" privileges, which is IMHO the most common cause of service starting problems in enterprise environments (the GPO settings may be adjusted). In addition, you do not have access to the desktop, so if a popup will be displayed waiting for the user, the service hangs.
in the development phase, you can swap DLLs or even the EXE if the service is not currently running without uninstall / install
use Windows event log extensively.
These differences between services and "normal application" are important enough for me to let this run directly on a server as often as possible.
In my services, I use:
protected override void OnStart(string[] args)
{
// this is not just a simple message, this has to be called very early before any worker thread
// to prevent a race condition in the .NET code of registering the event source
EventLog.WriteEntry("XXXXService is starting", EventLogEntryType.Information, 1000);
....
And do not forget that OnStart() and OnStop()should not contain long running code. You normally start a worker thread in OnStart() which runs until some notification (set in OnStop) was triggered.
Basically I need my application to run from system start until system shutdown. I figured out the following approach:
create MyApp.exe and MyService.exe
MyApp should install MyService as a service
MyService is supposed to run at startup and periodically check if MyApp is running. If it's not than start it.
That's the code I wrote for my service:
protected override void OnStart(string[] args)
{
while(true)
{
int processesCount =
Process.GetProcessesByName(Settings.Default.MyAppName).Count() +
Process.GetProcessesByName(Settings.Default.MyAppName + ".vshost").Count() +
Process.GetProcessesByName(Settings.Default.MyAppUpdaterName).Count();
if(processesCount==0)
{
//restore
var p = new Process { StartInfo = { FileName = Settings.Default.MyAppName, Arguments = "" } };
p.Start();
}
else
{
}
System.Threading.Thread.Sleep(3000);
}
}
How can I install this process so that it starts on windows start?
I'm not sure if this infinite loop in OnStart method is a good idea. Is it?
Is the general idea ok?
What I've done is have a windows service that runs the logic and main application code. Then if you need a GUI for it, have the windows service expose a web service via WCF and create a windows app that calls to the web service. On install, put you windows app in the windows startup.
This model will have the main application code running all the time, but the GUI is only up when a user is logged in.
Is the general idea ok?
As Hans points out in comments this is hostile to the user and fortunately won't work on Vista or later because services run in their own windows station. Put whatever logic you need to run all the time in the service and use an IPC mechanism such as WCF to communicate with an (optionally) running UI. If the user disables the service or exits the GUI respect their wishes...
How can I install this process so that it starts on windows start?
Add an entry to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run or HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Runthat points to your GUI application.
I'm not sure if this infinite loop in OnStart method is a good idea.
Is it?
No. You need to return from OnStart if you need to do work after OnStart returns create a Thread to do that work.
I have a console application that starts up, hosts a bunch of services (long-running startup), and then waits for clients to call into it. I have integration tests that start this console application and make "client" calls. How do I wait for the console application to complete its startup before making the client calls?
I want to avoid doing Thread.Sleep(int) because that's dependent on the startup time (which may change) and I waste time if the startup is faster.
Process.WaitForInputIdle works only on applications with a UI (and I confirmed that it does throw an exception in this case).
I'm open to awkward solutions like, have the console application write a temp file when it's ready.
One option would be to create a named EventWaitHandle. This creates a synchronization object that you can use across processes. Then you have your 'client' applications wait until the event is signalled before proceeding. Once the main console application has completed the startup it can signal the event.
http://msdn.microsoft.com/en-us/library/41acw8ct(VS.80).aspx
As an example, your "Server" console application might have the following. This is not compiled so it is just a starting point :)
using System.Threading;
static EventWaitHandle _startedEvent;
static void main()
{
_startedEvent = new EventWaitHandle(false, EventResetMode.ManualReset, #"Global\ConServerStarted");
DoLongRunnningInitialization();
// Signal the event so that all the waiting clients can proceed
_startedEvent.Set();
}
The clients would then be doing something like this
using System.Threading;
static void main()
{
EventWaitHandle startedEvent = new EventWaitHandle(false, EventResetMode.ManualReset, #"Global\ConServerStarted");
// Wait for the event to be signaled, if it is already signalled then this will fall throught immediately.
startedEvent.WaitOne();
// ... continue communicating with the server console app now ...
}
What about setting a mutex, and removing it once start up is done. Have the client app wait until it can grab the mutex before it starts doing things.
Include an is ready check in the app's client interface, or have it return a not ready error if called before it's ready.
Create a WCF service that you can use for querying the status of the server process. Only start this service if a particular command is passed on the command line. The following traits will ensure a very fast startup of this service:
Host this service as the first operation of the client application
Use the net.tcp or net.pipe binding because they start very quickly
Keep this service as simple as possible to ensure that as long as the console application doesn't terminate, it will remain available
The test runner can attempt to connect to this service. Retry the attempt if it fails until the console application terminates or a reasonably short timeout period expires. As long as the console application doesn't terminate unexpectedly you can rely on this service to provide any additional information before starting your tests in a reasonably short period of time.
Since the two(the console application, and integration test app that makes client calls - as I understand) are separate application, so there should be a mechanism - a bridge - that would tell play as a mediator(socket, external file, registry, etc).
Another possibility could be that you come up with an average time the console takes to load the services and use that time in your test app; well, just thinking out loud!
My windows service is a data server with substantial cache. During service OnStop I save the cache so that no data is lost. Saving cache may take several minutes so to prevent windows service manager from timeout I use SetServiceStatus Win32 callback:
this.serviceStatus.currentState = (int)State.SERVICE_STOP_PENDING;
this.serviceStatus.checkPoint = 1;
this.serviceStatus.waitHint = 60000;
SetServiceStatus(Process.GetCurrentProcess().Handle, ref this.serviceStatus);
That works fine.
I have also set CanShutdown to true and added OnShutdown so that service would be system shutdown proof. Here I effectively do the same thing as in OnStop:
protected override void OnShutdown()
{
this.OnStop();
base.OnShutdown();
}
That does not work too good. When system shuts down, when cache is being saved I get "The device is not ready". This suggests that Windows aborts service before it is done stopping / shutting down. Preventing that with SetServiceStatus apparently does not work.
How do I get more time (delay reboot) to get saving done?
Any suggestions welcome.
The preferred way to handle this can be found in this article on the BCL Team's blog. The article includes a bit of background on how managed services interact with the SCM, which is important for understanding why the approach shown in the question is no longer recommended.
Simply put, ServiceBase now handles service state management for you and your code just needs to request additional time if required. Read the article for a few other good guidelines for writing SCM-friendly services in .NET.
Using ManualResetEvent might be the trick.
After some testing it looks that it was a problem with the system rather than with my service.
Another easy way, after hours of searching on how to include the setservicestatus method:
protected override void OnStop()
{
stopTimer();
m_run = false;
while (m_queue.Count > 0)
Thread.Sleep(500);
}