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
Related
I'm developing a new windows service and I follow the steps provided in this instruction.
In the service class, I do pretty much the same things as the article
static EventLog _eventLog;
public CMSMetadata()
{
InitializeComponent();
_eventLog = new EventLog();
if (!EventLog.SourceExists("CMSMetadata_Processing"))
{
EventLog.CreateEventSource(new EventSourceCreationData("CMSMetadata_Processing", "CMSMetadata"));
}
_eventLog.Source = "CMSMetadata_Processing";
_eventLog.Log = "CMSMetadata";
}
protected override void OnStart(string[] args)
{
_eventLog.WriteEntry("In OnStart.", EventLogEntryType.Information);
}
After I installed and try to start the service, it shows me the following error
Error 1053: the service did not respond to the start or control
request in a timely fashion
And I also notice CreateEventSource() does not create the event log entry when I look for it in the event viewer.
I found this SO post is discussing the 1053 error I'm facing but none of the solutions works for me.
I have confirmed/tried
The service is built by release mode.
Install by both InstallUtil and ManagedInstallerClass.InstallHelper()
The framework version matches what I have installed, actually, I
tried 4.5.2 and 4.7.2 in case somehow it really has something to do with
the framework.
The service is running as local system.
The config is alright.
If I remove every code related to event log the service can be launched successfully.
Then I think fine if the service somehow can't create event log entry properly maybe I can create the entry in advance as a workaround.
However, in this way, I won't even able to install the service.
The install log (CMSMetadata.InstallLog) as below indicates somehow the installation will create the event source no matter I'm using CreateEventSource() or not.
Installing assembly 'C:\temp\GisSoftware\CMSMetadata\CMSMetadata.exe'.
Affected parameters are:
logtoconsole =
logfile = C:\temp\GisSoftware\CMSMetadata\CMSMetadata.InstallLog
assemblypath = C:\temp\GisSoftware\CMSMetadata\CMSMetadata.exe
Installing service CMSMetadata...
Service CMSMetadata has been successfully installed.
Creating EventLog source CMSMetadata in log Application...
Rolling back assembly 'C:\temp\GisSoftware\CMSMetadata\CMSMetadata.exe'.
Affected parameters are:
logtoconsole =
logfile = C:\temp\GisSoftware\CMSMetadata\CMSMetadata.InstallLog
assemblypath = C:\temp\GisSoftware\CMSMetadata\CMSMetadata.exe
Restoring event log to previous state for source CMSMetadata.
Service CMSMetadata is being removed from the system...
Service CMSMetadata was successfully removed from the system.
To conclude my question, What did I miss to use the event log in windows service?
It seems the service does create an event log by default. I should probably set AutoLog property of Service to false before generate the Installer.
Find the EventLogInstaller insides the ServiceInstaller and modify the log and source fixed my problem(also remember to remove the eventlog entry creation in service ctor).
public ProjectInstaller()
{
InitializeComponent();
EventLogInstaller installer = this.Installers.OfType<ServiceInstaller>().First()
.Installers.OfType<EventLogInstaller>().First();
installer.Source = _source;
installer.Log = _logName;
}
Moreover, it seems better to create eventlog during the installation instead of service ctor since it appears the permission of LocalSystem to access registry is limited.
ref: Easiest language for creating a Windows service
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 did set start my windows service or NT service like everybody says a then
came up this message:
The service myService on local computer started an then stopped.Some services stop automatically if they are not in use by another services or programs
i've started other services and it never hapened...
before i change the value of a parameter that have to find it's value on a web service method
that look on a sql database...
and other change is that got formatted the hard disk...maybe i have to enable somethig
please i need help
It happens most likely because
you have an exception at startup... try to debug your things either by
using a log or by trying to reproduce your behavior in a windows app....
You can even debug your windows service using the following method...
Write the following code in your Service file...
public void OnDebug()
{
OnStart(null);
}
In the program file,
YourService myService = new YourService();
myService.OnDebug();
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
This can happen when the logic performed using a windows service exceeds the default timeout.
We cannot overcome the default timeout of a windows service. Usually windows services are used to instantiate a method. So start a child thread within the OnStart event of the windows service and call your method within it.
If this is not solving your issue, put the code in try catch and log the exceptions. This error can happen if there is any exception within OnStart event too.
I've created a run of the mill C# Windows Service using the windows service project template. I've been able to install it correctly, and start and stop it without any issues.
However, when I go to my event viewer to see the log of it starting and stopping, I get nothing.
Here's the sample code I'm testing:
public MyService()
{
InitializeComponent();
ServiceName = "My Data Service";
EventLog.Log = "Application";
}
protected override void OnStart(string[] args)
{
EventLog.WriteEntry("Starting My Data Service");
}
protected override void OnStop()
{
EventLog.WriteEntry("Ending MyData Service");
}
Also, my OS is Windows Vista.
If you want it to log to the default log use
EventLog.WriteEntry("Starting My Data Service", EventLogEntryType.Information);
Of course, you have to ensure that the service is running under an account with sufficient privileges to write to the log and to "run as a service".
Found this example on SO, Best Way to write to the event log
Here's an example where you specify the source too, rather than displaying as .NET Runtime... MSDN Example
EventLog requires an EventSource created to be able to write.