Service not catching SessionChange events - c#

I'm writting a small service supposed to log some events. However only two of them or working and even after searching I can't figure out why.
These are the events I want to log:
Starting computer WORKING
Session locking
Session unlocking
Shutdown computer WORKING
I triple checked that my service could catch those events (I even set all CanHandle.. to true..
private void InitializeComponent()
{
//
// Service1
//
this.CanHandlePowerEvent = true;
this.CanHandleSessionChangeEvent = true;
this.CanPauseAndContinue = true;
this.CanShutdown = true;
this.ServiceName = "TimeToGoService";
}
This my overrided OnSessionChange()
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
if (changeDescription.Reason == SessionChangeReason.SessionLock)
{
startBreak();
}
else if (changeDescription.Reason == SessionChangeReason.SessionUnlock)
{
endBreak();
}
base.OnSessionChange(changeDescription);
}
startBreak() and endBreak() are only writing logs to a file with a StreamWriter..
By searching on the web, I saw some people using a hidden form for those events to be fired. Is that the problem ?

Don't know why, but the code above is now working 100%. Probably have missed something..
EDIT: Not beeing able to identify exactly what was wrong. I can give to my next one the service config that works beside the code.
Service user is LocalSystem
CanHandleSessionChangingEvents set to true
And.. That's pretty much it. Notice that service does not need to interact with desktop to catch those events.
Moreover, you can check if your services is getting events from terminal in EventObserver, you'll see if they failed or if they succeed.
Good luck, but if you use code and configuration above, you should be able to make it work ;)

Related

Abort a webtest if an error occurs

Using VS2010's load test feature with recorded webtests.
I have problems with cascading errors in my recorded webtests. That is, if one request fails, several other requests will also fail. This creates a lot of clutter in the logs, since usually only the first error is relevant.
Is there a way to make a failed validation rule terminate the web test at the point of failure, and NOT run the rest of the requests?
(to be clear, I still want to continue with the load test in general, just stop that specific iteration of that specific test case)
Here is some sample code that demonstrates what I'm trying to do:
using System.ComponentModel;
using Microsoft.VisualStudio.TestTools.WebTesting;
namespace TestPlugInLibrary
{
[DisplayName("My Validation Plugin")]
[Description("Fails if the URL contains the string 'faq'.")]
public class MyValidationPlugin : ValidationRule
{
public override void Validate(object sender, ValidationEventArgs e)
{
if (e.Response.ResponseUri.AbsoluteUri.Contains("faq"))
{
e.IsValid = false;
// Want this to terminate the running test as well.
// Tried throwing an exception here, but that didn't do it.
}
else
{
e.IsValid = true;
}
}
}
}
I found a good solution to this. There's a blog here that details it in full, but the short version is to use e.WebTest.Stop(). This aborts the current iteration of the current test, while leaving the rest of the run intact as needed.
Use the Assert.Fail(). This will stop the Test and will throw an AssertFailedException, just like in any failed assertion.
if (e.Response.ResponseUri.AbsoluteUri.Contains("faq"))
{
e.IsValid = false;
Assert.Fail("The URL contains the string 'faq'.");
}
This will stop only the specific test. At the end of the load test you can see the total number of tests failed with this exception.

Windows service doesn't hit OnStart unless using Administrator account

The service installs correctly but when attempting to start it via net start or from the services window it doesn't start at all, not even getting to the OnStart handler.
If I use an administrator account, the service starts and works correctly. This seems to suggest something in the service requires admin privileges but this is purely an on-demand style service with nothing executing until requested. With this type of service I'd assume that is should at least start and then fail later when a request is made to it that requires admin privileges?
It's impossible to debug as I can't even get it to start and nothing is appearing on the event logs apart from an Information log stating that the service stopped. There's too much code in the service to add it all here but the entry point is a fairly standard Unity style service:
partial class MyServiceHost : UnityServiceBase
{
private Bootstrapper _bootstrapper;
public MyServiceHost()
{
InitializeComponent();
}
protected override void OnStart( string[] args )
{
TextWriter tw = new StreamWriter( "ServiceTestLog.txt" );
tw.Write( "Date: " + DateTime.Now + "\n" );
try
{
base.OnStart( args );
_bootstrapper = new Bootstrapper( UnityContainer );
_bootstrapper.Run();
}
catch ( Exception ex )
{
tw.Write( ex.ToString() );
}
tw.Close();
}
protected override void OnStop()
{
_bootstrapper.Teardown();
base.OnStop();
}
}
For business reasons I can't just make the user account it uses an administrator so I'd appreciate any suggestions on how to fix this issue.
Writing to "ServiceTestLog.txt" may require local admin rights.
Make sure your user account has the "Log on as a Service" privilege. This won't work without that, and it's not on by default for users, though it would be for administrator. Instructions here.
Run the Visual Studio Debugger and attach to the service and you can step through it and see what's going on.
You can add this before initializecomponent() and add WAITFORDEBUGGER in the Service Control Panel "Start parameters" textbox for your service.
C#:
foreach (string arg in args) {
if (arg == "WAITFORDEBUGGER") {
while (!Debugger.IsAttached) {
Threading.Thread.Sleep(1000);
}
}
}
VB.Net:
For Each arg As String In args
If arg = "WAITFORDEBUGGER" Then
While Not Debugger.IsAttached
Threading.Thread.Sleep(1000)
End While
End If
Next
The service will then wait for you to fire up Visual Studio and attach the debugger, at which point you can trace through the entire initialization and run sequence and see what's broken.
If it never hits the WAITFORDEBUGGER code, it's probably having trouble loading a dependency, in which case Sysinternals Process Monitor (https://technet.microsoft.com/en-us/sysinternals/bb896645) can tell you what it's getting hosed on.

Windows service on Local Computer started and then stopped error

Usually, I get this error:
(The "service name" service on Local Computer started and then stopped. Some services stop automatically if they are not in use by other service or programs) when there's something wrong with my code, like non-existing drive paths, etc. The windows service will not start.
I have a windows service that backs up folder/files, to a location if it reached the size limit. Details are all provide by an XML Configuration that the windows service reads on start. I have a separate windows forms that has a button that does exactly what my windows service's onstart is doing. I use my windows forms for debugging the code before I put it in my windows service.
When I start my windows forms. It does what it suppose to do. When I put my code in the windows service OnStart() method the error showed up.
Here's my code:
protected override void OnStart(string[] args)
{
private static string backupConfig = #"D:\LogBackupConfig\backupconfig.xml";
private static string serviceStat = #"D:\LogBackupConfig\Status.txt";
private static string fileFolderStat = #"D:\LogBackupConfig\FileFolderStat.txt";
protected override void OnStart(string[] args)
{
if (File.Exists(backupConfig))
{
FileSystemWatcher watcher = new FileSystemWatcher();
XmlTextReader reader = new XmlTextReader(backupConfig);
XmlNodeType type;
List<string> listFile = new List<string>();
string fileWatch = "";
//this loop is for reading XML elements and assigning to variables
while (reader.Read())
{
type = reader.NodeType;
if (type == XmlNodeType.Element)
{
if (reader.Name == "File")
{
reader.Read();
fileWatch = reader.Value;
}
else if (reader.Name == "Folder")
{
reader.Read();
fileWatch = reader.Value;
}
}
}
reader.Close();
watcher.Path = fileWatch;
watcher.Filter = "*.*";
//this loop reads whether the service will watch a file/folder
XmlTextReader reader1 = new XmlTextReader(backupConfig);
while (reader1.Read())
{
type = reader1.NodeType;
if (type == XmlNodeType.Element)
{
if (reader1.Name == "File")
{
watcher.IncludeSubdirectories = false;
watcher.Changed += new FileSystemEventHandler(OnChangedFile);
}
else if (reader1.Name == "Folder")
{
watcher.IncludeSubdirectories = true;
watcher.Changed += new FileSystemEventHandler(OnChangedFolder);
}
}
}
reader1.Close();
watcher.EnableRaisingEvents = true;
}
else
{
StreamWriter sw = new StreamWriter(serviceStat, true);
sw.WriteLine("File not found. Please start the Log Backup UI first.");
sw.Close();
}
}
I don't know what keeps the windows service not starting, the windows form simulator worked fine. What seems to be the problem?
UPDATE:
After many trials I've noticed that using only a folder directory (w/out file), the windows service doesn't work. When I replaced the fileWatch variable with a specific file (including its directory), the windows service started. When I changed it back to a folder location, it didn't work. What I think is that folder locations doesn't work in a filewatcher.
When I tried creating a new windows service that watches a folder location, it worked.. However, when I tried the same location in my original windows service, it didn't work! I was mindf$#*ed! It seems that I have to create a new windows service and build the installer everytime I place a new code/function.. This way I can keep track where I get an error.
If the service starts and stops like that, it means your code is throwing an unhandled exception. This is pretty difficult to debug, but there are a few options.
Consult the Windows Event Viewer. Normally you can get to this by going to the computer/server manager, then clicking Event Viewer -> Windows Logs -> Application. You can see what threw the exception here, which may help, but you don't get the stack trace.
Extract your program logic into a library class project. Now create two different versions of the program: a console app (for debugging), and the windows service. (This is a bit of initial effort, but saves a lot of angst in the long run.)
Add more try/catch blocks and logging to the app to get a better picture of what's going on.
Not sure this will be helpful, but for debugging a service you could always use the following in the OnStart method:
protected override void OnStart(string[] args)
{
System.Diagnostics.Debugger.Launch();
...
}
than you could attach your visual studio to the process and have better debug abilities.
hope this was helpful,
good luck
I have found it very handy to convert your existing windows service to a console by simply changing your program with the following. With this change you can run the program by debugging in visual studio or running the executable normally. But it will also work as a windows service. I also made a blog post about it
program.cs
class Program
{
static void Main()
{
var program = new YOUR_PROGRAM();
if (Environment.UserInteractive)
{
program.Start();
}
else
{
ServiceBase.Run(new ServiceBase[]
{
program
});
}
}
}
YOUR_PROGRAM.cs
[RunInstallerAttribute(true)]
public class YOUR_PROGRAM : ServiceBase
{
public YOUR_PROGRAM()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
Start();
}
protected override void OnStop()
{
//Stop Logic Here
}
public void Start()
{
//Start Logic here
}
}
Please check that you have registered all HTTP endpoints in the local mahcine's Access Control List (ACL)
http://just2thepoint.blogspot.fr/2013/10/windows-service-on-local-computer.html
EventLog.Log should be set as "Application"
Meanwhile, another reason : accidentally deleted the .config file caused the same error message appears:
"Service on local computer started and then stopped. some services stop automatically..."
Use Timer and tick event to copy your files.
On start the service, start the time and specify the interval in the time.
So the service is keep running and copy the files ontick.
Hope it help.
You may want to unit test the initialization - but because it's in the OnStart method this is near to impossible. I would suggest moving the initialization code out into a separate class so that it can be tested or at least re-used in a form tester.
Secondly to add some logging (using Log4Net or similar) and add some verbose logging so that you can see details about runtime errors. Examples of runtime errors would be AccessViolation etc. especially if your service is running without enough privileges to access the config files.
The account which is running the service might not have mapped the D:-drive (they are user-specific). Try sharing the directory, and use full UNC-path in your backupConfig.
Your watcher of type FileSystemWatcher is a local variable, and is out of scope when the OnStart method is done. You probably need it as an instance or class variable.
I came across the same issue. My service is uploading/receiving XMLS and write the errors to the Event Log.
When I went to the Event Log, I tried to filter it. It prompt me that the Event Log was corrupted.
I cleared the Event Log and all OK.
In our case, nothing was added in the Windows Event Logs except logs that the problematic service has been started and then stopped.
It turns out that the service's CONFIG file was invalid. Correcting the invalid CONFIG file fixed the issue.

How do i know if my windows service is working?

I have built a windows service to populate a database with my email inbox every 5 minutes.
I used a class inside my windows service the class gets my emails and writes them to my database, the class has been tested and works.
All i need the windows service to do is use a timer and call the class every 5 minutes, but i have no idea whats going on as i cant even test my windows service.
Please someone tel me what to do to test, if there is a way to test, or just blink luck and pray it works lol.
Also do u have to uninstall and re-install every time you want to test the service or is there an update service option? Please answer this i'm really interested even tho its not my main question.
This is my windows service, if u can point out any errors that would be amazing since i cant test for them. I think my timer might be wrong if some one could look at it?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Timers;
namespace EmailWindowsService
{
public partial class MyEmailService : ServiceBase
{
private Timer scheduleTimer1 = null;
private DateTime lastRun;
private bool flag;
public MyEmailService()
{
InitializeComponent();
if (!System.Diagnostics.EventLog.SourceExists("MySource"))
{
System.Diagnostics.EventLog.CreateEventSource(
"MySource", "MyNewLog");
}
eventLogEmail.Source = "MySource";
eventLogEmail.Log = "MyNewLog";
scheduleTimer1 = new Timer();
scheduleTimer1.Interval = 5 * 60 * 1000;
scheduleTimer1.Elapsed += new ElapsedEventHandler(scheduleTimer_Elapsed);
}
protected override void OnStart(string[] args)
{
flag = true;
lastRun = DateTime.Now;
scheduleTimer.Start();
eventLogEmail.WriteEntry("Started");
}
protected override void OnStop()
{
scheduleTimer.Stop();
eventLogEmail.WriteEntry("Stopped");
}
protected override void OnPause()
{
scheduleTimer.Stop();
eventLogEmail.WriteEntry("Paused");
}
protected override void OnContinue()
{
scheduleTimer.Start(); ;
eventLogEmail.WriteEntry("Continuing");
}
protected override void OnShutdown()
{
scheduleTimer.Stop();
eventLogEmail.WriteEntry("ShutDowned");
}
protected void scheduleTimer_Elapsed(object sender, ElapsedEventArgs e)
{
RetriveEmailClass Emails = new RetriveEmailClass();
if (flag == true)
{
eventLogEmail.WriteEntry("In getting Email Method");
Emails.ServiceEmailMethod();
lastRun = DateTime.Now;
flag = false;
}
else if (flag == false)
{
if (lastRun.Date < DateTime.Now.Date)
{
Emails.ServiceEmailMethod();
eventLogEmail.WriteEntry("In getting Email Method");
}
}
}
}
}
Surely you can test it. All you need is
start up the service
observe that it triggers the expected call after 5 minutes
(observe that it triggers the expected call every 5 minutes for a couple more times)
You can test this manually, or (preferably) create/use an automated test harness which allows you to test repeatedly and reliably, as many times as you want. This is possible even using a simple batch file.
To detect that the timer works correctly, you can inspect its log file. It also helps of course if you make the called class method configurable instead of hardcoding it. So you can run your automated tests using a dummy worker class which does not flood your inbox :-)
To make it even more testable, you can extract the timing logic from your service class too, so that it becomes runnable from a regular application. Then you can test it even easier, even using a unit test framework such as NUnit. This allows you to do more thorough testing, using different timing intervals etc. And the service class itself becomes an almost empty shell whose only job is to launch and call the other classes. If you have verified that all the classes containing real program logic (i.e. all the code which can fail) is unit tested and works fine, you can have much greater confidence in that your whole app, when integrated from its smaller parts, works correctly too.
Update
Looking through your code, it seems that you don't initialize flag anywhere, so its default value will be false. You should initialize it to true in the constructor, otherwise your email retriever won't ever get called even if the timer fires properly.
To set the interval to 1 minute, my first guess would be
scheduleTimer1.Interval = 1 * 60 * 1000;
James Michael Hare has on his blog written about a really nice template/framework he has made, making it lot easier to develop (and debug) Windows Services: C# Toolbox: A Debuggable, Self-Installing Windows Service Template (1 of 2)
It provides you with all the basics you need to quickly get started. And best of all, it give you a really nice way to debug your service as if it was a regular console application. I could also mention that it provides out of the box functionality to install (and uninstall) your service. Part two of the post can be found at this link.
I've used this myself a couple of times, and can really recommend it.
Refactor you logic in another class.
Write a simple console application invoking this class
Test it like a normal application.
Once it runs standalone, it should run as a service.
Beware on permissions and service registration, there are a couple of issues there (like having a sys user, or a desktop session).
A good practice is to use system logs (e.g. the ones you can inspect with eventvwr)
1.add this line to the place you want to break, then you can debug your service.
System.Diagnostics.Debugger.Break();
or
2.try to attach to your service progress from process explorer, then you can also debug your service.
or
3.use a log file to log what your service is doing.
You can attach a debugger to you running service instance from Visual Studio. Click "Debug" in the main menu, "Attach to Process...", select your service process from the list and click "Attach".
If you need to debug the startup of your service, you need to use System.Diagnostics.Debugger.Break().

detect shutdown in window service

i have a windows service that get user details and save the result into log text file. and, my problem is when i shut down or log off my system, i also would like to save the time that i down my system into that log file. but, i don't know how to do that.
I checked the winproc method to detect shutdown operation but i was not able to use it on window service, on googling found it can be used with forms only. how can we detect user have clicked shutdown or log off and do some action.
so,please give me some idea or suggestion on that.
i have used it for logoff but on log entry is made when i logoff the system
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
this.RequestAdditionalTime(250000); //gives a 25 second delay on Logoff
if (changeDescription.Reason == SessionChangeReason.SessionLogoff)
{
// Add your save code here
StreamWriter str = new StreamWriter("D:\\Log.txt", true);
str.WriteLine("Service stoped due to " + changeDescription.Reason.ToString() + "on" + DateTime.Now.ToString());
str.Close();
}
base.OnSessionChange(changeDescription);
}
For a shutdown, override the OnShutdown method:
protected override void OnShutdown()
{
//your code here
base.OnShutdown();
}
For a logoff:
First, add an event handler to Microsoft.Win32.SystemEvents.SessionEnded in the Service Constructor:
public MyService()
{
InitializeComponent;
Microsoft.Win32.SystemEvents.SessionEnded += new Microsoft.Win32.SessionEndedEventHandler(SystemEvents_SessionEnded);
}
Then add the handler:
void SystemEvents_SessionEnded(object sender, Microsoft.Win32.SessionEndedEventArgs e)
{
//your code here
}
This should catch any ended session, including the console itself (the one running the services).
Tl;dr
In your service set
CanShutdown = true;
then override
protected override void OnShutdown()
{
//Your code here
//Don't forget to call ServiceBase OnShutdown()
base.OnShutdown();
}
Now the extended answer
I know I'm bringing this up from the dead but I found it helpful and hope to add a little to the topic. I'm implementing a WCF duplex library hosted in a Windows Service and came across this thread because I needed to detect, from within the windows service, when a user logs off or shuts down the computer. I'm using .Net Framework 4.6.1 on Windows 7 and Windows 10. Like previously suggested for shutdown what worked for me was overriding ServiceBase.OnShutdown() like so:
protected override void OnShutdown()
{
//Your code here
//Don't forget to call ServiceBase OnShutdown()
base.OnShutdown();
}
Remember to add the following to your service's constructor to allow the shutdown event to be caught:
CanShutdown = true;
Then to capture when a user logs off, locks the screen, switches user, etc. you can just override the OnSessionChange method like so:
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
if (changeDescription.Reason == SessionChangeReason.SessionLogoff)
{
//Your code here...
//I called a static method in my WCF inbound interface class to do stuff...
}
//Don't forget to call ServiceBase OnSessionChange()
base.OnSessionChange(changeDescription);
}
And of course remember to add the following to your service's constructor to allow catching of session change events:
CanHandleSessionChangeEvent = true;
You should override OnShutdown in your service
// When system shuts down
protected override void OnShutdown()
{
// Add your save code here
base.OnShutdown();
}
You might also want to override OnStop
// When the user presses stops your service from the control panel
protected override void OnStop()
{
// Add your save code here too
base.OnStop();
}
Edit:
If you really want to listen to the shutdown event Microsoft.Win32.SystemEvents.SessionEnding is the way to go.
Maybe you can use this. Poll the method in question every now and then (1 second interval) and you'll be able to do what you want.
You need RegisterServiceCtrlHandlerEx API call.
Disclaimer
Maybe this answer wont be useful when Windows changes the Shut down behavior again.
Which notifications occur when computer Shutsdown?
As far as i was able to find out, three notifications occur when the computer shuts down:
SessionLogoff
SessionLock
Suspend
The first two are delivered by OnSessionChange(), and the last by OnPowerEvent().
Of course, a natural choice is Suspend, but care should be taken that this notification is also sent when the computer is sent to Sleep.
How to get notified?
To get the notifications posted above you have to allow the notifications in the service constructor as follows:
public Service1()
{
InitializeComponent();
CanHandlePowerEvent = true;
CanHandleSessionChangeEvent = true;
}
and then override the respective
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
// Do something
base.OnSessionChange(changeDescription);
}
protected override bool OnPowerEvent(PowerBroadcastStatus powerStatus)
{
// Do something
return base.OnPowerEvent(powerStatus);
}
What about ServiceBase.OnShutdown()?
Well, this is not called when a computer is shut down by clicking on "Shut down" in the Power options.
Indeed, as written in this official post,
When you shut down your computer, your computer actually enters a hibernation state instead of a full shutdown.
and further, according to the documentation:
Use OnShutdown to specify the processing that occurs when the system shuts down.
This event occurs only when the operating system is shut down, not when the computer is turned off.
OnShutdown is expected to be overridden when the CanShutdown property is true.
So, if manually shutting down the computer does not really shuts down the computer, but it puts it in an hibernation state, what can shut down the computer?
The post quoted above has again the answer:
Full shutdown only occurs when you restart a computer or when other event causes the computer to process a full shutdown.
And indeed, i could get the OnShutdown() method called on my service by setting
CanShutdown = true;
and overriding to OnShutdown
protected override void OnShutdown()
{
// Do something
base.OnShutdown();
}
and then restarting my computer.
Well, enough with this post. I only hope the shut down behavior of Windows does not change soon...

Categories

Resources