patterncsharpMinor
Controlling a Windows Service from a WPF app
Viewed 0 times
appwpfservicecontrollingwindowsfrom
Problem
I have a WPF Control Panel app, where I'm trying to stay close to an MVVM architecture. The control panel (the "the CP") is for a WCF service ("the Scheduler"), hosted in a Windows Service ("the Host"). My main concern, and topic for review here, is how I am avoiding blocking the CP responsiveness for too long. The Host control operations sometimes take longer than 3 seconds, which is long for a UI.
Because the start and stop methods are typed
This is called from the viewmodel, when a
```
void ExecuteStartHostCommand()
{
Exception exception = null;
ExecuteWithTimeout(() =>
{
try
{
_host.Start();
}
catch (Exception ex)
{
exception = ex;
}
});
if (exception != null)
{
_lo
Because the start and stop methods are typed
void, and I have been advised to steer well clear of using async void methods, instead I use a method I derived from an example somewhere:private void ExecuteWithTimeout(Action task, int? timeout = null)
{
timeout = timeout ?? HostServiceConstants.ServiceControlTimeout;
var source = new CancellationTokenSource();
var timedTask = Task.Factory.StartNew(task, source.Token).ContinueWith((t) =>
{
if (t.Exception != null)
{
t.Exception.Handle(ex =>
{
var frame = new StackFrame(1);
var methodName = frame.GetMethod().Name;
_logger.Warn("'ExecuteWithTimeout' exception from: '{0}': {1}", methodName, ex.Message);
return true;
});
}
});
bool done = timedTask.Wait(timeout.Value);
if (!done)
{
source.Cancel();
var frame = new StackFrame(1);
var methodName = frame.GetMethod().Name;
_logger.Warn("'{0}' timed out after {1} milliseconds.", methodName, timeout);
}
}This is called from the viewmodel, when a
Command is invoked from the view:```
void ExecuteStartHostCommand()
{
Exception exception = null;
ExecuteWithTimeout(() =>
{
try
{
_host.Start();
}
catch (Exception ex)
{
exception = ex;
}
});
if (exception != null)
{
_lo
Solution
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.Code Snippets
var frame = new StackFrame(1);
var methodName = frame.GetMethod().Name;
_logger.Warn("'ExecuteWithTimeout' exception from: '{0}': {1}", methodName, ex.Message);var frame = new StackFrame(1);
var methodName = frame.GetMethod().Name;
_logger.Warn("'{0}' timed out after {1} milliseconds.", methodName, timeout);throw exception;Context
StackExchange Code Review Q#84069, answer score: 4
Revisions (0)
No revisions yet.