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...
Related
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 ;)
For my Windows Store App, I want my application to be active all the time.
I am using code below. My Device set to be go into screen lock in 10 seconds, while I am using my application it still goes into lock screen. Am I using this code incorrectly?
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
// Prevent tablet from sleeping while app is running
Windows.System.Display.DisplayRequest KeepScreenOnRequest = new Windows.System.Display.DisplayRequest();
KeepScreenOnRequest.RequestActive();
}
I think you should try it on page navigation events instead of application level events...
using Windows.System.Display;
private DisplayRequest KeepScreenOnRequest;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if(KeepScreenOnRequest == null)
KeepScreenOnRequest = new DisplayRequest();
KeepScreenOnRequest.RequestActive();
}
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
base.OnNavigatingFrom(e);
KeepScreenOnRequest.RequestRelease();
}
Again in this scenario you have to handle the request and release part on all of your app's pages individually...
I think the problem may be elsewhere - your DisplayRequest may be garbage collected. Try like this:
Windows.System.Display.DisplayRequest KeepScreenOnRequest;
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
KeepScreenOnRequest = new Windows.System.Display.DisplayRequest();
// Prevent tablet from sleeping while app is running
KeepScreenOnRequest.RequestActive();
}
Few notes:
of course the above code should work for the whole app, when not needed - release the request
putting this in OnNavigatedFrom/OnNavigatedTo may not be a good idea, unless handeled properly - for example when app is suspended (common case) after you return OnNavigated won't be called - your DisplayRequest probably won't be activated
you don't need to worry about releasing you request while the app goes to background, as mentioned at MSDN:
Note Windows automatically deactivates your app's active display requests when it is moved off screen, and re-activates them when your app comes back to the foreground.
I'm trying to implement an HttpStreaming comet push server in ASP.net. I am implementing an IHttpAsyncHandler that holds onto an http request and periodically sends messages down to the connected client. The connection with the client can be held open for a very long time (lets say 30 minutes). The issue that I am having is that since I don't end the request for a very long time, the handler technical is still running. So when the app pool recycles or ends, my asp.net application doesn't end gracefully. Meaning, Application_End never gets called in Global.asax since it is waiting for all handlers to complete before it gets called. My handler hasn't completed yet since it is holding on to the request. Eventually, the application just gets killed by IIS.
Here a sample HttpHandler that runs infinitely until something tells it to stop.
public class StreamingSocketHandler3 : IHttpHandler
{
private static readonly AppDomainShutdown Instance = AppDomainShutdown.Instance;
public void ProcessRequest(HttpContext context)
{
long c = 1;
bool stop = false;
Instance.OnStop += delegate()
{
stop = true;
};
while (!stop)
{
LogThis.Log.LogThis("loop: " + c, LogThis.eloglevel.debug);
c++;
System.Threading.Thread.Sleep(1000);
}
}
public bool IsReusable
{
get
{
return true;
}
}
}
If a client connects to this handler and then I stop the app pool, the web app doesn't end until the app gets completely killed by IIS sometime later.
The obvious answer to this problem is to listen to some sort of application end event and then end the request. I can't hook into Global.asax Application_end as it doesn't get called until the handler ends. The following blog post (link) provides some other alternatives (see q5 at the end of the post). I have tried the AppDomain.DomainUnload event suggest with no luck. I have also tried the IRegisteredObject interface suggested. That doesn't work either. I have built the following class that implements IRegisteredObject for testing.
public sealed class AppDomainShutdown : IRegisteredObject
{
public event Action OnStop;
// Singleton reference
public static readonly AppDomainShutdown Instance = new AppDomainShutdown();
// Singleton private Constructor
private AppDomainShutdown()
{
// Register the object
HostingEnvironment.RegisterObject(this);
}
public void Stop(bool immediate)
{
// Whats it want us to do?
if (!immediate)
{
// Do some code to handle graceful
// if OK
LogThis.Log.LogThis("Not Immediate Stop called", LogThis.eloglevel.debug);
OnStop();
HostingEnvironment.UnregisterObject(this);
}
else
{
// Do some code to force down (THREAD.ABORT)
// Mandatory
LogThis.Log.LogThis("Immediate Stop called", LogThis.eloglevel.debug);
OnStop();
HostingEnvironment.UnregisterObject(this);
}
}
}
If I make a call to this class from Global.asax without the handler starting, I get the application stop notification as expected. However, placing the same call in the HttpHandler (see the handler code), the OnStop event never fires.
What's frustrating is that I have seen a couple of forums posts on the web were the posts had my exact issue and the poster supposedly was able to implement IRegisteredObject and end the HttpRequest so the app could shutdown.
Please note that the HttpHandler code I'm presenting is simply for testing that I can end the ProcessRequest method in response to the application ending.
I want to send some kind of hearbeat at every configured time interval. I want to use dispatcher timer to send it.
Main()
{
create dispatcher timer;
}
void dispacthertimertick()
{
// send heartbeat
}
How do i keep the main thread alive?
Regards
Raju
The best place to put it is in your App.xaml.cs.
Application in WPF is responsible for setting the message loop so you should not really worry about it. If your App.xaml has a build action property of ApplicationDefinition (which is the default), it will emit this start up code (which you can see using Reflector):
[STAThread, DebuggerNonUserCode]
public static void Main()
{
App app = new App();
app.InitializeComponent();
app.Run();
}
You need to use OnStartup:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
// setup your timer here
}
Console.Read() is really a hack and unnecessary since there could be no console, as is the case in Windows forms.
Scenario
I've created a windows service, but whenever I start it, it stops immediately. The service was concieved from a console application that used to subscribe to an event and watch processes on a server. If anything happened to process (i.e. It was killed), then the event would trigger the process to be restarted. The reason I'm telling you this is because the original code used to look like this:
Original Console App Code:
static void Main(string[] args)
{
StartProcess sp = new StartProcess();
//Note the readline that means the application sits here waiting for an event!
Console.ReadLine();
}
Now that this code has been turned into a Windows Service, it is essentially EXACTLY THE SAME. However, the service does not sit there waiting, even with the readline, it just ends.....
New Windows Service Code:
protected override void OnStart(string[] args)
{
ProcessMonitor pm = new ProcessMonitor();
Console.ReadLine();
}
Thoughts
Since the functionality is entirely encapsulated within this single class (It quite literally starts, sets up some events and waits) - How can I get the service to actually sit there and just wait? It seems to be ignoring the readline. However this works perfectly as a console application, it is just far more convenient to have it as a service.
Typically you would want something like this. As Joe mentioned in the comments you want Start to initialize and release control to another thread to make sure that you return within 30 seconds.
private readonly ProcessMonitor processMonitor = new ProcessMonitor();
protected override void OnStart(string[] args)
{
processMonitor.Start();
}
protected override void OnStop()
{
processMonitor.Stop();
}
In a Service there is no concept of a readline - there's no keyboard. I wouldn't be surprised if this is throwing an exception at that call. Have you checked your Application Log?
Well... A service doesn't have a console input/output. So the ReadLine won't stop it from executing.
What does ProcessMonitor do?
Typically, for services your code lives in a thread that monitors whether the service has been stopped or paused.
OnStart() must complete and end successfully for the service to be considered "Started"
Move your Console.ReadLine(); into your ProcessMonitor() constructor, and create your ProcessMonitor inside the constructor for the service. Your OnStart method can be empty. Despite what people are saying the Console methods will NOT crash your service, however it is probably not best practice. I guess the proper way to keep a service running (after your timers are started) is to use a while loop with a Thread.Sleep(60000) inside it.
When I am writing a service I put all the functionality in a Class Library project, then I create a Console Application project to test the service functionality, and then a Windows Service project. Both the Console Application and Windows Service project call one method in the Class Library to start the service functionality. If you use this technique you can call Console.WriteLine in the Class Library which can be viewed when running the Console Application. PS Topshelf is overrated, writing a windows service is not that difficult.
public partial class ProcessMonitor_Service : ServiceBase
{
public ProcessMonitor_Service()
{
InitializeComponent();
ProcessMonitor pm = new ProcessMonitor();
}
protected override void OnStart(string[] args)
{
}
protected override void OnStop()
{
}
}
public class ProcessMonitor
{
public ProcessMonitor()
{
// start timers
Console.ReadLine();
}
}