Controlling a Windows Service from a WPF app
async void methods should generally be avoided, yes, but this looks like it's one of the cases where they make sense.



var frame = new StackFrame(1);
var methodName = frame.GetMethod().Name;
_logger.Warn("'ExecuteWithTimeout' exception from: '{0}': {1}", methodName, ex.Message);


I don't see how is methodName useful here, it's always going to be Handle.



var frame = new StackFrame(1);
var methodName = frame.GetMethod().Name;
_logger.Warn("'{0}' timed out after {1} milliseconds.", methodName, timeout);


I think [CallerMemberName] would be simpler here.



throw exception;


This means that the stack trace of the exception is going to be rewritten. If you don't want to wrap the exception in another exception, you can use ExceptionDispatchInfo to preserve the stack.