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.
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
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.
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.
There is no guarantee that finally will be called for certain exceptions.
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
From MDSN try-finally (C# Reference)
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.
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 sendsStop
to the service which abort the thread before thefinally
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 :
Since you didn't provide a
catch
block theApplicationException
is propagated up to the other layers and ultimately to Windows service management which handle it by sending thestop
request thus aborting the thread.Side notes :
catch
block and log exceptions.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.