I want to stop windows service in onStart() method when customer doesn't have a license. I use service.Stop(), but it does not work.
protected override void OnStart(string[] args)
{
try
{
_bridgeServiceEventLog.WriteEntry("new OnStart");
if (LicenseValidetor.ValidCountAndTypeDevices())
{
WsInitializeBridge();
}
else
{
service = new ServiceController("BridgeService");
service.Stop();
_bridgeServiceEventLog.WriteEntry("LicenseValidetor Error");
}
_bridgeServiceEventLog.WriteEntry("end Start");
}
catch (Exception e)
{
_bridgeServiceEventLog.WriteEntry("error In onstart method ");
}
}
You cannot stop a service from within the OnStart method of that same service.
The ServiceController.Stop method internally calls ControlService (or it's Ex counterpart). Notice that one of the reasons that this function can fail is:
ERROR_SERVICE_CANNOT_ACCEPT_CTRL
The requested control code cannot be sent to the service because the state of the service is SERVICE_STOPPED, SERVICE_START_PENDING, or SERVICE_STOP_PENDING.
Well, guess what - when you're inside your OnStart method, the state of your service is SERVICE_START_PENDING.
The correct way to cope with this situation is to signal any other threads that you may have started to have them exit, and then to exit your OnStart method. The service control manager will notice that the process has exited and revert your service status to SERVICE_STOPPED. It may also notify an interactive user that "The service started and then stopped" or words to that effect.
I want to add that "simply not starting any workers" may not work (or perhaps I am being just plain stupid ;) ).
I built a service, with a try/catch(all) around my OnStart code. Because of a missing line in my .config file it crashed with an IOException, before it started any worker thread. The exception skipped over my thread starters. No thread was started by my code. Honestly.
But the service DID NOT STOP. I don't know why. As a desperate measure, I rethrew the exception, that helped.
I am still wondering if the file system watcher threads in Enterprise Library configuration were the problem. EntLib is woven to deeply into my code to remove it as an experiment, so I did not investigate further.
The accepted answer explains why what you are doing doesn't work but doesn't offer a good solution.
There are a couple of things your code isn't doing that it should.
Set the .ExitCode to indicate that your service is in an error state.
Throw an exception. Not having a license is exceptional. Throw it.
EXAMPLE:
protected override void OnStart(string[] args)
{
_bridgeServiceEventLog.WriteEntry("new OnStart");
try
{
if (LicenseValidetor.ValidCountAndTypeDevices())
{
WsInitializeBridge();
}
else
{
throw new ApplicationException("LicenseValidetor Error");
}
}
catch (Exception e)
{
this.ExitCode = e.HResult
_bridgeServiceEventLog.WriteEntry($"error In onstart method: {e.Message}");
throw
}
_bridgeServiceEventLog.WriteEntry("end Start");
}
I have noticed that your not waiting to ensure that the Service has actually stopped or if it is even running in the first instance.
Do this :-
protected override void OnStart(string[] args)
{
try
{
_bridgeServiceEventLog.WriteEntry("new OnStart");
if (LicenseValidetor.ValidCountAndTypeDevices())
{
WsInitializeBridge();
}
else
{
int time = 10000;
TimeSpan timeout = TimeSpan.FromMilliseconds(time);
service.Stop();
service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
_bridgeServiceEventLog.WriteEntry("LicenseValidetor Error");
}
_bridgeServiceEventLog.WriteEntry("end Start");
}
catch (Exception e)
{
_bridgeServiceEventLog.WriteEntry("error In onstart method ");
}
}
Related
Can anyone explain why this finally block is not executed? I have read posts about when to expect finally block not be executed, but this seems to be another case. This code needs TopShelf and log4net. I am running .net 4.5
I guess it must be the Windows Service engine that kicks in on unhandled exceptions, but why is it running before the finally block has finished?
using log4net;
using log4net.Config;
using System;
using System.Threading;
using Topshelf;
namespace ConsoleApplication1
{
public class HostMain
{
static void Main(string[] args)
{
HostFactory.Run(x =>
{
x.Service<HostMain>(s =>
{
s.ConstructUsing(name => new HostMain());
s.WhenStarted(tc => tc.Start());
s.WhenStopped(tc => tc.Stop());
});
x.RunAsLocalSystem();
x.SetServiceName("TimerTest");
});
}
public void Stop()
{
LogManager.GetLogger("MyLog").Info("stopping");
}
public void Start()
{
XmlConfigurator.Configure();
LogManager.GetLogger("MyLog").Info("starting");
new Thread(StartServiceCode).Start();
}
public void StartServiceCode()
{
try
{
LogManager.GetLogger("MyLog").Info("throwing");
throw new ApplicationException();
}
finally
{
LogManager.GetLogger("MyLog").Info("finally");
}
}
}
}
outputs
starting
throwing
stopping
EDIT: Please comment why you are downgrading, maybe you don't understand the problem? I see a big problem here. You write some domain logic that does important stuff in the finally clause on Exception. Then if you host the logic in a Windows Service the design suddenly is broken.
From MDSN try-finally (C# Reference)
Within a handled exception, the associated finally block is guaranteed to be run. However, if the exception is unhandled, execution of the finally block is dependent on how the exception unwind operation is triggered. That, in turn, is dependent on how your computer is set up. For more information, see Unhandled Exception Processing in the CLR.
Usually, when an unhandled exception ends an application, whether or not the finally block is run is not important
This is by design, .NET has chosen to terminate your application, reason is, there is something terribly wrong, something didn't work as expected, by calling finally, we don't want to do more damage, so best is to end the application.
What if finally throws one more exception, where does that go? If application is about to close, it may have closed or started closing managed resources and accessing them for logging in finally could turn out to be fatal as well.
Sorry about this being an answer, but couldn't comment.
I couldn't find anything specific about the windows service, but I'm assuming it uses background/foreground threading to execute the code.
And in terms of threading, the finally block is sometimes voided (if the thread is aborted or interrupted unexpectedly) -
http://blog.goyello.com/2014/01/21/threading-in-c-7-things-you-should-always-remember-about/
Or for a more official post - (Look for the foreground/background threading section)
https://msdn.microsoft.com/en-us/library/orm-9780596527570-03-19.aspx
Hopefully it helps you a little
Have you made sure that the logger is getting a chance to flush to disk before the logger is destroyed when the service stops?
Edit
When a service starts it happens on a new thread. Within the Topshelf code there is an AppDomain.CurrentDomain.UnhandledException += CatchUnhandledException; handler.
void CatchUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
_log.Fatal("The service threw an unhandled exception", (Exception)e.ExceptionObject);
HostLogger.Shutdown();
if (e.IsTerminating)
{
_exitCode = TopshelfExitCode.UnhandledServiceException;
_exit.Set();
#if !NET35
// it isn't likely that a TPL thread should land here, but if it does let's no block it
if (Task.CurrentId.HasValue)
{
return;
}
#endif
// this is evil, but perhaps a good thing to let us clean up properly.
int deadThreadId = Interlocked.Increment(ref _deadThread);
Thread.CurrentThread.IsBackground = true;
Thread.CurrentThread.Name = "Unhandled Exception " + deadThreadId.ToString();
while (true)
Thread.Sleep(TimeSpan.FromHours(1));
}
}
This catches the unhandled exception, and stops the service by setting the manualresetevent (this is the only thing that is blocking the service from ending).
After sleep is called, the thread is signalled and your finally block, which is on the service thread is killed.
The code then exits.
This is wired up in the Run() method in ConsoleRunHost.
public TopshelfExitCode Run()
{
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
AppDomain.CurrentDomain.UnhandledException += CatchUnhandledException;
if (_environment.IsServiceInstalled(_settings.ServiceName))
{
if (!_environment.IsServiceStopped(_settings.ServiceName))
{
_log.ErrorFormat("The {0} service is running and must be stopped before running via the console",
_settings.ServiceName);
return TopshelfExitCode.ServiceAlreadyRunning;
}
}
bool started = false;
try
{
_log.Debug("Starting up as a console application");
_log.Debug("Thread.CurrentThread.Name");
_log.Debug(Thread.CurrentThread.Name);
_exit = new ManualResetEvent(false);
_exitCode = TopshelfExitCode.Ok;
Console.Title = _settings.DisplayName;
Console.CancelKeyPress += HandleCancelKeyPress;
if (!_serviceHandle.Start(this))
throw new TopshelfException("The service failed to start (return false).");
started = true;
_log.InfoFormat("The {0} service is now running, press Control+C to exit.", _settings.ServiceName);
_exit.WaitOne();
}
catch (Exception ex)
{
_log.Error("An exception occurred", ex);
return TopshelfExitCode.AbnormalExit;
}
finally
{
if (started)
StopService();
_exit.Close();
(_exit as IDisposable).Dispose();
HostLogger.Shutdown();
}
return _exitCode;
}
There is no guarantee that finally will be called for certain exceptions.
Since this program runs as a Windows service it is managed by Windows. Windows detects that something went wrong because of the ApplicationException call and it sends Stop to the service which abort the thread before the finally block is executed.
The "finally" block is never executed because Windows pulls the rug from under. This is pefectly logical when you remind how exception handling works :
try {
// Do stuff
} catch (Exception e) {
// Executed first
} finally {
// Executed last
}
Since you didn't provide a catch block the ApplicationException is propagated up to the other layers and ultimately to Windows service management which handle it by sending the stop request thus aborting the thread.
Side notes :
Unmanaged exception in a service is very bad : obviously you should add a catch block and log exceptions.
Normally the Stop function is used to tell the working thread it needs to stop. This will give the thread a chance to stop in clean way. Here is a good example.
Edit :
Here is a sample of what I would do. It is more like pseudo-code but you should get the idea.
public void StartServiceCode(object state)
{
bool stopTimer = false;
try
{
LogManager.GetLogger("MyLog").Info("Locking");
lock (thisLock) {
LogManager.GetLogger("MyLog").Info("Throwing");
throw new ApplicationException();
}
} catch (Exception e) {
// The lock is relased automatically
// Logging the error (best practice)
LogManager.GetLogger("MyLog").Info("Exception occurred...");
// If severe, we need to stop the timer
if (e is StackOverflowException || e is OutOfMemoryException) stopTimer = true;
} finally {
// Always clean up
LogManager.GetLogger("MyLog").Info("finally");
}
// Do we need to stop?
if (stopTimer) {
LogManager.GetLogger("MyLog").Info("Severe exception : stopping");
// You need to keep a reference to the timer. (yes, a timer can stop itself)
timer.Stop();
}
}
The linked article explains why the finally block of a method run into a windows service provided by TopShelf library that raises an unhandled exception, it isn't executed: https://lowleveldesign.wordpress.com/2012/12/03/try-finally-topshelf-winsvc/
The problem seems related to a portion of code in the topshelf library that sleeps the thread that has raised the exception.
Follows an excerpt of the code responsible for the sleep call on the thread, this method belongs to TopShelf library
...
void CatchUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
_log.Error("The service threw an unhandled exception", (Exception)e.ExceptionObject);
...
int deadThreadId = Interlocked.Increment(ref _deadThread);
Thread.CurrentThread.IsBackground = true;
Thread.CurrentThread.Name = "Unhandled Exception " + deadThreadId.ToString();
while (true)
Thread.Sleep(TimeSpan.FromHours(1));
}
...
I'm creating a simple window service and when I go to debug I get the error, "Cannot evaluate expression because a native frame is on top of the call stack.". Also, when I build the service in Release and run it just hangs.
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new MyService1() };
ServiceBase.Run(ServicesToRun);
}
Thats all that is in the Program.cs file, where it normally gets hung on the ServiceBase.Run(ServicesToRun) line.
Everything I've been able to find only relates to the expression not being evaluated because the code is optimized or having to deal with asp.net and response.redirect.
Code for the Service.
public TruckRateClearService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
tmrProcess.Enabled = true;
}
protected override void OnCustomCommand(int command)
{
base.OnCustomCommand(command);
if (command == 129)
{
OnStart(null);
}
}
protected override void OnStop()
{
tmrProcess.Enabled = false;
}
private void tmrProcess_Tick(object sender, EventArgs e)
{
tmrProcess.Enabled = false;
try
{
eventLog.WriteEntry("Clearing Truck Rates Start" + DateTime.Now.ToString());
TruckRateClearingAgent.Process();
eventLog.WriteEntry("Clearing Truck Rates Finished" + DateTime.Now.ToString());
}
catch (Exception ex)
{
eventLog.WriteEntry(ex.ToString(), EventLogEntryType.Error);
}
tmrProcess.Enabled = true;
}
internal void Run()
{
tmrProcess_Tick(tmrProcess, null);
}
The Internal Void Run() was added just recent on the suggestion in the comments by Eren Ersönmez. His idea has been very helpful for helping debug my logic until I can figure the rest out.
I was able to get the into the Native call stack and it sits on one location, 76F17094 ret. Now I have no idea what this is but maybe someone else will.
Also, when I start the service and look into attaching it to VS I'm noticing two instances of it. One is the normal .exe and another is a .vshost.exe. When I start other services I only see the .exe file in the Attach to process part of the debugger. Could this be because one is on the v4 Framework ( .vshost .exe service ) and another on the v2 ( single .exe service ) Framework?
I believe I got it working. It seems that the problem lied with the timer I was using. The original timer I was using was a System.Windows.Forms timer. I switched it to System.Timers.Timers and everything started working again. Still cant attach VS to it but I can debug it still by using the Internal Run() method. Thanks for all the help n.n
Your main problem is that you're trying to directly run a windows service exe. Windows services can only be started via Service Control Manager (SCM). In order to be able to debug in VS, I'd recommend something like this:
static void Main()
{
if (Environment.UserInteractive)
{
new MyService1().Run();
Thread.Sleep(Timeout.Infinite);
}
else
{
ServiceBase.Run(new ServiceBase[] { new MyService1() });
}
}
You'd create a MyService1.Run method which spawns a new thread that runs the service loop. Also, you'd call the same Run method from within the MyService1.Onstart.
This scheme runs it as a service when being started by SCM, but treats it like a normal exe when being debugged in VS (or being run directly as an exe outside VS).
The problem
This notification means that the thread is currently executing unmanaged code, and therefore cannot be used to evaluate the expression.
In some situations, you could wait for the call to return to managed code before evaluating the expression. Unfortunately, in this situation, that won't happen until you shut down the service.
An Alternative
You might consider overriding the ServiceBase.OnCustomCommand method and putting a breakpoint there so you can evaluate your expression.
protected override void OnCustomCommand(int command)
{
//Debugger.Break() <- or just put a breakpoint in here.
}
You can invoke the custom command as follows:
c:\>sc control YourServiceName 129
The exception you're seeing means that unmanaged code is throwing an exception, so the .NET debugger can't show you the usual useful details.
What are you doing in MyService1() ? Can you post the code inside it?
Also are you trying to debug the service by just starting it from the environment. That might not work.
I usually write something like this:
static void Main(params string[] args)
{
if (args.Length > 0 && args[0] == "/console")
{
// Run whatever your service calls here
}
else
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new MyService1() };
ServiceBase.Run(ServicesToRun);
}
}
Then in the project properties under the Debug tab enter /console as the command line arguments. You should be able to step into the application and debug it. You can only debug a service by installing it first: http://msdn.microsoft.com/en-us/library/7a50syb3(v=vs.80).aspx
i am writing a windows service that checks for a particular service and check it. if it is stop it will start it...
protected override void OnStart(string[] args)
{
Thread thread = new Thread(new ThreadStart(ServiceThreadFunction));
thread.Start();
}
public void ServiceThreadFunction()
{
try
{
ServiceController dc = new ServiceController("WebClient");
//ServiceController[] services = ServiceController.GetServices();
while (true)
{
if ((int)dc.Status == 1)
{
dc.Start();
WriteLog(dc.Status.ToString);
if ((int)dc.Status == 0)
{
//heartbeat
}
}
else
{
//service started
}
//Thread.Sleep(1000);
}
}
catch (Exception ex)
{
// log errors
}
}
i want the service to check for the another service and start... plz help me how can i do that
First of all, why are you casting the ServiceController's Status property from the convenient ServiceControllerStatus enum to an int? Best to leave it as an enum. Especially since your Heartbeat code, which compares it to 0, will never be run because ServiceControllerStatus doesn't have 0 as a possible value.
Secondly, you shouldn't use a while(true) loop. Even with the Thread.Sleep you have commented out there, it's a needless drain on resources. You can just use the WaitForStatus method to wait for the service to start:
ServiceController sc = new ServiceController("WebClient");
if (sc.Status == ServiceControllerStatus.Stopped)
{
sc.Start();
sc.WaitForStatus (ServiceControllerStatus.Running, TimeSpan.FromSeconds(30));
}
This will wait up to 30 seconds (or whatever) for the service to reach the Running state.
UPDATE: I re-read the original question, and I think what you're trying to do here shouldn't even be done with code. If I understood correctly, you want to set a dependency for your service on the WebClient service when you're installing it. Then, when the user starts your service in the Service Manager, it will automatically try to start the dependent service.
I am creating this windows service by following the instructions at MSDN Walkthrough: Creating a Windows Service and after successful installation, I go to Services.msc to Start the Windows service and before it finishes starting up I get the following message:
The EIWindowsService service on Local Computer started and then stopped. Some services stop automatically if they are not in use by other services or programs.
I know the Windows Service starts ok because there is an entry to the log file stating that the service started. I did some research before posting on here and the answer from Some Services Stop Automatically states that the problem could either be that the OnStart method is throwing an error, or that the OnStart is not kicking off a thread. So I modified my code so that the only thing within the OnStart is the starting of two timers and the log entry therefore needing no exception handling. I also added a thread to "jump" to another method.
I tried the windows service again and I know that it "moved" to the new method that the thread pointed to because I had a log entry in there that threw aFormatException error due to some conversion I was doing. I commented out the conversion and the windows service still just began to start up and then stopped automatically.
Further research indicated to me that I might need a loop to keep the processing within the method, so I took information from C - Windows Service the service on and set up an infinite while loop. I also found that there might be Garbage Collection going on and established a KeepAlive statement for the timers as suggested in Examples section of MSDN Timer Class. Still the same issues.
At this point I feel I've exhaused all the research I can do so it would be appropriate to post my question here. All my code is below and I will note that before I performed any change I uninstalled the Windows Service, removed the Setup Project, and deleted the installers from the C# code. I then made changes and started back over with the instructions in the Walkthrough starting at the point where it instructs how to setup the installers. I did this each time because I found that if I made changes and did not uninstall the Windows Service, remove the Setup Project, and delete the installers, then my changes would not take effect on the currently installed windows service.
Any assistance you can give would be most appreciated. I will be here for another 15min and then I will check this first thing tomorrow.
SERVICE1.cs
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 EIWindowsService
{
public partial class Service1 : ServiceBase
{
Logs.ErrorLog logFile = new Logs.ErrorLog();
private System.Threading.Thread onStartThread;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
iTimer.Start();
iTimer.Elapsed += new ElapsedEventHandler(iTimer_Elapsed);
pTimer.Start();
pTimer.Elapsed += new ElapsedEventHandler(pTimer_Elapsed);
onStartThread = new System.Threading.Thread(TimerValue);
onStartThread.Start();
logFile.SendToLog("EIWindows Service started on " + GetDate());
}
catch (ArgumentOutOfRangeException ex)
{
logFile.SendToLog("ArgumentOutOfRangeException", "EIWindowsService\\Service1.cs", "OnStart()", ex);
} //end of ArgumentOutOfRangeException CATCH statement
}
protected override void OnStop()
{
iTimer.Stop();
pTimer.Stop();
logFile.SendToLog("EIWindowsService\\Service1.cs", "OnStop()", "EIWindows Service stopped on " + GetDate());
}
private void TimerValue()
{
try
{
/*commented out because it was throwing an exception error*/
//double iTimerValue = Convert.ToDouble(iTimer.ToString());
//double pTimerValue = Convert.ToDouble(pTimer.ToString());
while (1 > 0)
{
//if (iTimerValue % 1800000 == 0) //if the timer hits the 30min mark
//{
// logFile.SendToLog("Current iTimer Value = " + iTimerValue.ToString());
//}
//if (pTimerValue % 1800000 == 0) //if the timer hits the 30min mark
//{
// logFile.SendToLog("Current pTimer Value = " + pTimerValue.ToString());
//}
GC.KeepAlive(iTimer);
GC.KeepAlive(pTimer);
}
//TimerValue();
}
catch (OverflowException ex)
{
logFile.SendToLog("OverflowException", "EIWindowsService\\Service1.cs", "TimerValue()", ex);
} //end of OverflowException CATCH statement
catch (ArgumentException ex)
{
logFile.SendToLog("ArgumentException", "EIWindowsService\\Service1.cs", "TimerValue()", ex);
} //end of ArgumentException CATCH statement
catch (FormatException ex)
{
logFile.SendToLog("FormatException", "EIWindowsService\\Service1.cs", "TimerValue()", ex);
} //end of FormatException CATCH statement
}
private string GetDate()
{
string current = "No Date Recorded";
try
{
current = DateTime.Now.ToString("F");
}
catch (FormatException ex)
{
logFile.SendToLog("FormatException", "EIWindowsService\\Service1.cs", "GetDate()", ex);
} //end of FormatException CATCH statement
return current;
} //end of method GetDate
private void iTimer_Elapsed(object source, ElapsedEventArgs e)
{
try
{
iTimer.Stop();
ImportI();
iTimer.Start();
}
catch (ArgumentOutOfRangeException ex)
{
logFile.SendToLog("ArgumentOutOfRangeException", "EIWindowsService\\Service1.cs", "iTimer_Elapsed()", ex);
} //end of ArgumentOutOfRangeException CATCH statement
} //end of method iTimer_Elapsed
private void pTimer_Elapsed(object source, ElapsedEventArgs e)
{
try
{
pTimer.Stop();
ImportP();
pTimer.Start();
}
catch (ArgumentOutOfRangeException ex)
{
logFile.SendToLog("ArgumentOutOfRangeException", "EIWindowsService\\Service1.cs", "pTimer_Elapsed()", ex);
} //end of ArgumentOutOfRangeException CATCH statement
} //end of method pTimer_Elapsed
private void ImportI()
{
//does some action but commented out because it never gets here and is not relavant to this question.
} //end of method ImportI
private void ImportP()
{
//does some action but commented out because it never gets here and is not relavant to this question.
} //end of method ImportP
}
}
SERVICE1.DESIGNER.CS (the relavant stuff)
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.pTimer = new System.Timers.Timer(10800000); //3hrs
this.iTimer = new System.Timers.Timer(3600000); //1hr
//
// pTimer
//
this.pTimer.Enabled = true;
//
// iTimer
//
this.iTimer.Enabled = true;
//
// Service1
//
this.ServiceName = "EIWindowsService";
}
#endregion
private System.Timers.Timer pTimer;
private System.Timers.Timer iTimer;
You don't need to create a separate thread or worry about the garbage collector. The framework handles all that for you. Just create the timers and they will be called. Here's an example.
public partial class Service1 : ServiceBase
{
private Timer timer;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
timer = new Timer(1000);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
using (StreamWriter writer = File.AppendText(#"C:\Users\alfonso\Desktop\log.txt"))
{
writer.WriteLine(string.Format("{0} : {1}", DateTime.Now, "Logging from the service"));
}
}
protected override void OnStop()
{
}
}
Something else that may help someone coming across this post and the above solutions do not work. When I had this problem, I had added this to the config of my Windows Service:
<system.web>
<compilation debug ="true" />
</system.web>
I added this so that I could attach the debugger to the service when running it locally, however when I tried to move the service to another server it gave the specified error. By removing this from the config the service worked again.
This is difficult situation to explain. Have a service process that starts 2 threads, each thread loops forever but sleeps for 5 minutes each once the payload is finished.
Problem is that my second thread terminates well before the payload is even finished, for no apparent reason, and i also can't catch the exception as it seems to be triggered from outside the delegate process?
Any suggestions on how to find the problem?
The code....
public void StartService()
{
ThreadStart stRecieve = new ThreadStart(DownloadNewMail);
ThreadStart stSend = new ThreadStart(SendNewMail);
senderThread = new Thread(stRecieve);
recieverThread = new Thread(stSend);
sendStarted = true;
recieveStarted = true;
senderThread.Start();
recieverThread.Start();
}
private void DownloadNewMail()
{
while(recieveStarted)
{
//Payload....
if (recieveStarted)
{
Thread.Sleep(new TimeSpan(0, confSettings.PollInterval, 0));
}
}
}
private void SendNewMail()
{
while(sendStarted)
{
//Payload....
if (sendStarted)
{
Thread.Sleep(new TimeSpan(0, confSettings.PollInterval, 0));
}
}
}
Try to check callstack lenght in your code:
class Program
{
static void Main(string[] args)
{
try
{
Hop();
}
catch (Exception e)
{
Console.WriteLine("Exception - {0}", e);
}
}
static void Hop()
{
CheckStackTrace();
Hip();
}
static void Hip()
{
CheckStackTrace();
Hop();
}
static void CheckStackTrace()
{
StackTrace s = new StackTrace();
if (s.FrameCount > 50)
throw new Exception("Big stack!!!!");
}
}
If you are having trouble following the flow of your application's code execution, try logging the entrance of methods with a timestamp and threadid.
Also, You can't catch the exception because it is a StackOverflowException.
See msdn: "Starting with the .NET Framework version 2.0, a StackOverflowException object cannot be caught by a try-catch block and the corresponding process is terminated by default. Consequently, users are advised to write their code to detect and prevent a stack overflow. For example, if your application depends on recursion, use a counter or a state condition to terminate the recursive loop. "
Do you utlize any heavy-weight library for tasks like DownloadNewMail and SendNewMail? For example I encountered StackOverflows when running large jobs using Microsoft.SqlServer.Dts.Runtime.Package. Try running the same workload sequentially inside a command-line application to see if the issue persists.