I am building an application monitoring service to write to the event log so I can get an general Idea how often the computer is being used. I can install the service and when I try to run it I get this error:
"The Application Monitor service on local computer started and then stopped. Some services stop automatically if they have no work to do, for example, the performance logs and alerts service."
I've tried a while loop, mouse activity, and etc... but it keeps ending. any ideas on what I can do?
public ApplicationMonitor()
{
InitializeComponent();
if (!System.Diagnostics.EventLog.SourceExists("Activity Usage"))
{
System.Diagnostics.EventLog.CreateEventSource("Activity Usage", "Computer Log");
}
eventLog1.Source = "Activity Usage";
eventLog1.Log = "Computer Log";
}
protected override void OnStart(string[] args)
{
eventLog1.WriteEntry("In OnStart");
}
protected override void OnStop()
{
eventLog1.WriteEntry("In onStop.");
}
protected override void OnContinue()
{
eventLog1.WriteEntry("In OnContinue.");
}
Because there is no active thread.
You need to start your thread that does the polling in the "OnStart" method of your service. Otherwise when the OnStart method completes, there is no active thread in the application and the .Net CLR will close the app.
Even if the thread is simply doing a thread sleep every 30 seconds, it must be alive in order for the app to stay open.
Related
I'm trying to run some console app as windows service, I followed this question, and I made a few changes to make it fit to my app.
My main code looks like that:
public static class Program
{
public class Service : ServiceBase
{
public Service(string serviceName)
{
this.ServiceName = serviceName;
}
protected override void OnStart(string[] args)
{
Program.Start(args);
}
protected override void OnStop()
{
Program.Stop(this.ServiceName);
}
}
#endregion
static void Main(string[] args)
{
if (!Environment.UserInteractive)
// running as service
using (var service = new Service("TestService"))
ServiceBase.Run(service);
else
{
// running as console app
Start(args);
}
}
private static void Start(string[] args)
{
while(true)
{
//DO SOMTHING
}
}
private static void Stop(string serviceName)
{
//Writing to log that 'serviceName' stopped
}
}
I tried to run the following console app as a service, by using the following steps:
1) Use the command: sc create ServiceTestName123 binPath= "PATH TO THE EXE FILE IN THE PROJECT DEBUG FOLDER".
2) Use the command: sc start ServiceTestName123 "parameter1".
And I got an error:
"StartService FAILED 1053:
The service did not respond to the start or control request in a timely fashion"
I read about the error in the internet and found out that I can try to solve this problem by running the start function with another thread, so I updated the OnStart function to the following function:
protected override void OnStart(string[] args)
{
Thread t = new Thread(() => Program.Start(args));
t.Start();
}
After trying to re-create the service (delete the old one and create the service again with the new OnStart function) and re-run it I got the same error.
By the way, when I ran this code as console app it worked properly.
Could someone please explaing me what am I doing wrong?
Thanks a lot.
I tried your exact steps and it worked for me. I will highlight a few key points that I came across
OnStart should definitely return in a timely fashion. i.e. the work should happen in a separate process/thread. I used your code for thread and it worked fine for me.
Make sure the executable is on a local drive which can be accessed from your "Local System" account without any permission issues.
Make sure when you create the service, you provide the absolute path and not relative path.
Make sure the sc create ... command responds back with [SC] CreateService SUCCESS
Check the service was created in the service control panel
Make sure you can start it from the service control panel before attempting it from command line
Also, open task manager or process explorer to make sure the service executable is running or not (irrespective of what status is returned by service control panel or scm start)
For debugging, I logged the information into a local temp file - again watch out for permissions issues with Local System account.
If for whatever reasons you have to delete the service, make sure that it indeed disappeared from the service control panel
To debug what's going on, you can attach the debugger at the very beggining of your program start up.
This way, you can check what your program is doing.
You can also check in the Windows ever viewer, the error that windows is throwing.
Put this line at the start trace of your program:
System.Diagnostics.Debugger.Launch()
I have simplest possible windows service.
I need service to run under Local System account.
If I start/stop service from SCM, everything works fine, my log text file has both Start and Stop events, and also both Start and Stop events are shown automatically in the event viewer.
But when I restart or shutdown my PC (tried with Win 7 and Win 10), OnStop() method is never called, if service runs as Local System account. If I change account to Network Service or any other Local/Domain account, OnStop() method is called before restart/shutdown of the PC.
Windows service code:
using System.IO;
using System.ServiceProcess;
namespace SimplestService
{
class MyService : ServiceBase
{
private string path = "<pathtologfile>\\MyServiceLog.txt";
public MyService()
{
this.ServiceName = "MyService";
this.CanShutdown = true;
}
protected override void OnStart(string[] args)
{
using (StreamWriter sw = File.AppendText(path))
{
sw.WriteLine("MyService Started.");
}
}
protected override void OnStop()
{
using (StreamWriter sw = File.AppendText(path))
{
sw.WriteLine("MyService Stopped.");
}
}
protected override void OnShutdown()
{
OnStop();
}
}
}
and Main Entry:
using System.ServiceProcess;
namespace SimplestService
{
class Program
{
static void Main(string[] args)
{
ServiceBase.Run(new MyService());
}
}
}
For simplicity I've used SC utility to create service, even though I tried with Installer, even setup project (msi), but with same results.
sc create MyService binPath= "<pathtoexe>\SimplestService.exe"
type= own start= auto DisplayName= Myservice
Microsoft Windows has added an option called Fast Startup which does not actually shutdown the computer.
As noted in the Fast Startup setting description, Restart isn't affected. This is why the Restart triggers OnShutdown and Shutdown does not.
Turning off Fast Startup will trigger OnShutdown for both Restart and Shutdown.
From what I researched, the OnShutdown method is called when the OS is shutdown, but there is there is a strict time limit, but i believe the local system services are terminated even before this time limit so that OS shutdown time is fast. This might explain why domain account are shutdown slower. Windows has introduced a PreShutdown event to handle this.
Try the link below, it has more information on this
https://www.atomia.com/2011/11/16/how-to-process-the-preshutdown-event-in-a-managed-windows-service/
I have a Windows Service. On startup it checks whether any work has been assigned to it - and if none has, it just quits. The problem is that the recovery mechanism is set to Restart the Service.
This is what I want if the service legitimately crashes, but not if I quit the service programmatically on my own.
So far everything I've tried below has resulted in Windows automatically restarting the service:
Thread th;
protected override void OnStart(string[] args)
{
th = new Thread(new ThreadStart(StartMyService));
th.Start();
}
private void StartMyService()
{
if (WorkAvailable()) {
InitWork();
} else {
this.ExitCode = 0; // no errors
Stop();
}
}
protected override void OnStop()
{
// dispose of things
try
{
if (th != null && th.ThreadState == ThreadState.Running)
th.Abort();
}
catch { }
Environment.Exit(this.ExitCode);
}
I've tried different ExitCode values, but Windows always restarts the Service. I've also tried Environment.FailFast with same results. What am I missing?
Ignoring the issue of whether or not this is good design, the reason the OS is using the failure recovery action is because the service is failing.
When you call Stop the runtime marks the service as being in the process of stopping. It then calls the OnStop method. When the OnStop method returns it finishes cleanup and then exits the service. If this is the only service in the executable then the executable also exits. There is never a need to exit the process yourself.
When you call Environment.Exit (or Environment.FailFast) you cause the service executable to suddenly exit while the ServiceControlManager still has it listed as running, so the OS quite rightly considers the service to have failed.
I want to create a windows service that performs some really long and heavy work. The code is inside OnStart method like this:
protected override void OnStart(string[] args)
{
System.IO.File.WriteAllText(
#"C:\MMS\Logs\WinServiceLogs.txt",
DateTime.Now + "\t MMS Service started."
);
this.RequestAdditionalTime(5*60*1000);
this.RunService();
}
this.RunService() sends a request to WCF service library hosted on IIS. It does some really long processes, ranging from 1-20 min, depending on the data it has to process. This service that I'm writing is supposed to be scheduled to run every day in the morning. So far, it runs and works fine, but when the time goes over a few seconds or min, it generates timeout exception. This causes the windows service to be in unstable state, and I can't stop or uninstall it without restarting the computer. Since, I'm trying to create an automated system, this is an issue.
I did do this.RequestAdditionalTime(), but I'm not sure whether it's doing what it's supposed to or not. I don't get the timeout error message, but now I don't know how to schedule it so it runs every day. If the exception occurs, then it won't run the next time. There were several articles and SO's I found, but there's something I'm missing and I can't understand it.
Should I create a thread? Some articles say I shouldn't put heavy programs in OnStart, where should I put the heavy codes then? Right now, when the service starts, it does this huge data processing which makes the Windows Service status to "Starting", and it stays there for long time until either the program crashes due to timeout, or completes successfully. How can I start the service, then set the status to Running while the code is running to do some data processing?
Your situation might be better suited for a scheduled task as Lloyd said in the comments above. But if you really want to use a Windows service, this is what you would need to add/update in your service code. This will allow your service to list as started and not timeout on you. You can adjust the timer length to suit your needs.
private Timer processingTimer;
public YourService()
{
InitializeComponent();
//Initialize timer
processingTimer = new Timer(60000); //Set to run every 60 seconds
processingTimer.Elapsed += processingTimer_Elapsed;
processingTimer.AutoReset = true;
processingTimer.Enabled = true;
}
private void processingTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//Check the time
if (timeCheck && haventRunToday)
//Run your code
//You should probably still run this as a separate thread
this.RunService();
}
protected override void OnStart(string[] args)
{
//Start the timer
processingTimer.Start();
}
protected override void OnStop()
{
//Check to make sure that your code isn't still running... (if separate thread)
//Stop the timer
processingTimer.Stop();
}
protected override void OnPause()
{
//Stop the timer
processingTimer.Stop();
}
protected override void OnContinue()
{
//Start the timer
processingTimer.Start();
}
I know that I can deny onStop feauture by setting CanStop option to false in Service's properties. This is not what I want cause this will permanently deny onStop capabilities.
What I want is to grant/deny stop capabilities programmatically. My service lifecycle is pretty simple:
starts => { run some action => sleeps for 2 minutes } x nTimes => stop
What I would is to deny stop capabilities when service is in action and grant that feature when service is idle (i.e. If user try to stop it when not permitted nothing happen, else the service really stop itself).
This is how my service is written, I have various way to understand if is idle.
partial class Service : ServiceBase
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private DateTime _lastRun = DateTime.Now;
private System.Timers.Timer _timer = new System.Timers.Timer(Convert.ToInt32(ConfigurationManager.AppSettings["pollingInterval"]) * 60 * 1000);
public Service()
{
InitializeComponent();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
_timer.Enabled = false;
DateTime now = DateTime.Now;
if (now.Minute > _lastRun.Minute)
{
ClientVS cvs = new ClientVS();
cvs.run();
}
_lastRun = now;
_timer.Enabled = true;
}
protected override void OnStart(string[] args)
{
log.Info("Started");
_timer.Elapsed += timer_Elapsed;
_timer.Start();
}
protected override void OnStop()
{
log.Info("Stopped");
}
}
Don't do this. Service must stop promptly (5 seconds or less) when requested to stop. If you delay or deny stop requests from SCM, you are guaranteed to annoy your users when they reboot computer. You can potentially change service configuration dynamically, but it is probably bad idea, because changing serice config frequently does not sound right.
Semantics of the service STOP command is just this -- service has to stop at the earliest safe place. Your action is different than that. What I would recommend is to implement a custom mechanism that would represent your semantics exactly (that is, do NOT reuse STOP command). There are couple of way to do this:
Any sort of IPC mechanism. A named event would probably be easiest to implement. A service will create a named event and wait for it in one of the background threads. When event is set (by your user mode application), it would do necessary checks and would call ServiceBase.Stop conditionally.
Invent a custom service control command. This is easy to do, just override ServiceBase.OnCustomCommand, make up an integer between 128 and 255, that would represent your command, and implement OnCustomCommand to call ServiceBase.Stop conditionally. To send custom command to service you can use API or sc control command. Assuming you made up 234 as you new command:
sc control MyService 234