tacf
asked on
Preventing the "Stop" command on a Windows Service during a critical section of code. (C#/ASP.NET)
I have a Windows Service that I'm in the process of writing in C# using Visual Studio .NET. It is used to process credit card payments for Premium Members of our website. There is one part of the process which is really critical:
Once the user's details have been processed, resulting in the credit card being charged, it is important that the database is updated to set the user's billing date to one month in the future. If this does not happen, the card will be charged again an hour later, the next time the timer fires its "elapsed" event.
I have already got lots of try/catch blocks in my code and other flags I use to handle the situation where an exception occurs between these two lines of code. However, I realized that if someone stops the service during this critical section, the same problem could arise.
This leads to my question...
How can I ensure that my service does not stop until the important piece of code has finished executing?
This is fairly urgent so I would really appreciate any help that you could offer. It's my first Windows Service although I'm fairly familiar with C# and ASP.NET.
Once the user's details have been processed, resulting in the credit card being charged, it is important that the database is updated to set the user's billing date to one month in the future. If this does not happen, the card will be charged again an hour later, the next time the timer fires its "elapsed" event.
I have already got lots of try/catch blocks in my code and other flags I use to handle the situation where an exception occurs between these two lines of code. However, I realized that if someone stops the service during this critical section, the same problem could arise.
This leads to my question...
How can I ensure that my service does not stop until the important piece of code has finished executing?
This is fairly urgent so I would really appreciate any help that you could offer. It's my first Windows Service although I'm fairly familiar with C# and ASP.NET.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
If this weren't c#, I'd clear the SERVICE_ACCEPT_STOP flag in field dwControlsAccepted of the SERVICE_STATUS struct passed to the SetServiceStatus() API. However, given that c# makes its own calls to SetServiceStatus() so you don't have to, I'd be surprised if your own clearing of the bit lasted very long.
But it may be worth a try to avoid the nasty messages in the event log.
But it may be worth a try to avoid the nasty messages in the event log.
try
this.CanStop = false;
while you are in the CS
this.CanStop = false;
while you are in the CS
ASKER
I had already tried altering the value of CanStop and it results in an exception. The value of CanStop cannot be changed once the service has started.
As for logging the transactions, I am logging them in a log file in C:\Windows\System32\Logfil es rather than using the db for this.
How do I actually create a critical section in C#? I remember back in my University days studying mutual exclusion semaphores and all the rest but I don't know how to implement such a thing.
As for logging the transactions, I am logging them in a log file in C:\Windows\System32\Logfil
How do I actually create a critical section in C#? I remember back in my University days studying mutual exclusion semaphores and all the rest but I don't know how to implement such a thing.
ASKER
OK, I think I've got it.
In my OnStart() method I create a Mutex object called this.mutex.
At the start of my critical section of code, I have:
Mutex.WaitAny(new WaitHandle[] {this.mutex});
At the end of the critical section of code, I have:
this.mutex.ReleaseMutex();
In the OnStop() method, I have:
Mutex.WaitAny(new WaitHandle[] {this.mutex});
From testing with writing entries to the log file, I've discovered that this works properly. (I put in a 15 second delay in the middle of the critical section of code and when I stop the service, it waits until that part is finished.
In my OnStart() method I create a Mutex object called this.mutex.
At the start of my critical section of code, I have:
Mutex.WaitAny(new WaitHandle[] {this.mutex});
At the end of the critical section of code, I have:
this.mutex.ReleaseMutex();
In the OnStop() method, I have:
Mutex.WaitAny(new WaitHandle[] {this.mutex});
From testing with writing entries to the log file, I've discovered that this works properly. (I put in a 15 second delay in the middle of the critical section of code and when I stop the service, it waits until that part is finished.
ASKER
I just realized I could use:
this.mutex.WaitOne();
instead of:
Mutex.WaitAny(new WaitHandle[] {this.mutex});
this.mutex.WaitOne();
instead of:
Mutex.WaitAny(new WaitHandle[] {this.mutex});
@tacf
Any feedback/resolution/points distrobution?
Any feedback/resolution/points
However, one caveat, windows will display an error message saying your service didn't shut down in a timely fashion. It displays this message after waiting ~ 2 minutes for OnStop to return.