Debugging of and error handling for synchronous Commands

So you might have your first Acropolis application up and running and everything works just fine. Except for that little problem in one of your commands that you have missed. How could that happen? Well, if an exception is thrown during the execution of a Part's command and you have a debugger attached to the process you might be lucky and find the issue. Unfortunately, any exception during command execution will be eaten by the Acropolis runtime which means that if there is no debugger to trap first chance exceptions there is no way to find or handle those using the usual .NET error handling mechanism. We are aware that this is a severe limitation and will look into better ways of solving this problem in a later milestone but until then you will have to rely on workarounds. The good news though is that I have one for you. Let's say you have a part with a command connection point called FailingCommand and the following implementation:

[DefaultView(typeof(AcropolisPart1View))]

public partial class AcropolisPart1 : Part

{

    public AcropolisPart1()

    {

        InitializeComponent();

    }

    private void FailingCommand_CommandExecuted(object sender, ComponentCommandExecutionEventArgs<object> e)

    {

        throw new NotImplementedException();

    }

}

 

FailingCommand_CommandExecuted(object, ComponentCommandExecutionEventArgs<object>) is the event handler for the command's ComponentCommand.CommandExecuted event and therefore also the implementation of the command. Somewhere else in our solution we probably have a caller and – assuming we can use the error handling approach we're used to – try something like this:

private void TestButton_Click(object sender, RoutedEventArgs e)

{

    try

    {

        Part.FailingCommand.Execute(null);

    }

    catch (Exception exception)

    {

        MessageBox.Show(

            "Caught '" +

            exception.GetType().ToString() +

            "' exception in TestButton_Click(object, RoutedEventArgs)");

    }

}

As already explained we will never enter the catch block no matter what happens in the command implementation. Unfortunately, the return type of IComponentCommand<T>.Execute is void. However, the return type of IComponentCommand<T>.BeginExecute(T, OperationStatusCallback, object) isn't. It's IOperation and the actual type of the object being returned in the current implementation is Operation (however, please be aware that this is an internal implementation detail which may change in the future). The Operation class has an interesting property called ExecutionException which tells us exactly what we want to know – if the execution of the command succeeded or not. So, by using (or abusing – depending on your point of view) the parameter userState of the BeginExecute method we can turn an asynchronous command execution into a synchronous one and then check if it there was an exception. First, we need something for synchronization as we don't know on which thread the command will be executed. I chose an EventWaitHandle object so I added a finally block to the command implementation to check if the user state object is of that type and if so set its state to signaled.

private void FailingCommand_CommandExecuted(object sender, ComponentCommandExecutionEventArgs<object> e)

{

    try

    {

        throw new NotImplementedException();

    }

    finally

    {

        EventWaitHandle handle = e.ExecutingOperation.UserState as EventWaitHandle;

        if (handle != null)

            handle.Set();

    }

}

 

This implementation will still work correctly when invoked synchronously or if we need to use the user state object for an actual asynchronous execution of the command. All that's left to do now is to change the calling method:

private void TestButton_Click(object sender, RoutedEventArgs e)

{

    using (EventWaitHandle waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset))

    {

        Operation op = (Operation)Part.FailingCommand.BeginExecute(null, null, waitHandle);

        waitHandle.WaitOne();

        if (op.ExecutionException != null)

        {

            MessageBox.Show(

                "'" +

                op.ExecutionException.GetType().ToString() +

                "' exception occurred during the execution of the command");

        }

    }

}

 


This posting is provided "AS IS" with no warranties, and confers no rights.