HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Controlling a Windows Service from a WPF app

Submitted by: @import:stackexchange-codereview··
0
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 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.