TriggerAction obscuring the actual problem, replacing the stack trace

TriggerAction obscuring the actual problem, replacing the stack trace

Old forum URL: forums.lhotka.net/forums/t/11639.aspx


skagen00 posted on Wednesday, October 10, 2012

I could be misreading this, but I think there's an issue with TriggerAction where it ends up obscuring the stack trace.

Initial Exception Stack - I basically can just create a null variable and try to reference a property.

   at [ProductName].Silverlight.ViewModels.Menu.PaymentVoidMenuItemViewModel.ExecuteAction()
   at [ProductName].Silverlight.ViewModels.Menu.MenuItemViewModelBase.HandleTriggerAction(TriggerAction action, ExecuteEventArgs args)
   at [ProductName].Silverlight.ViewModels.Menu.MenuItemViewModel`1.HandleTriggerAction(TriggerAction action, ExecuteEventArgs args)

(We use an intermediary HandleTriggerAction to help suppress things like double-clicks firing off methods multiple times - which gets kind of tricky when async calls are involved).

End up getting a null reference exception:

   at Csla.Xaml.TriggerAction.CallMethod(Object sender, EventArgs e)
   at System.Windows.Controls.Primitives.ButtonBase.OnClick()
   at System.Windows.Controls.Button.OnClick()
   at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
   at System.Windows.Controls.Control.OnMouseLeftButtonUp(Control ctrl, EventArgs e)
   at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName, UInt32 flags)

It would be tremendously useful  to actually see the first trace, because it becomes clear where the error may have occurred.  We log our errors - the former is helpful, the second is worthless.

I am trying to get my debugging working for CSLA to step through it and see it in action, but is there something that can be done for this sort of scenario / has anyone encountered this?  The reality is that sometimes we'll program in bugs into the methods our trigger actions call and to have a stacktrace that means something would be very helpful.

skagen00 replied on Wednesday, October 10, 2012

I see - so I presume I have an ex.InnerException and by throwing it I'm getting my inner exception but not the stack trace to it... hmm... I imagine the goal is to just drop the targetinvocationexception but that stack trace lost sure would be nice.

       catch (System.Reflection.TargetInvocationException ex)
      {
        if (ex.InnerException != null)
          throw ex.InnerException;
        else
          throw;
      }

 

RockfordLhotka replied on Wednesday, October 10, 2012

It has been a while, but iirc the issue, it is because dynamically calling the method via reflection (or a lambda expression - whichever we're using now) causes the underlying stack trace to be lost due to a context switch.

Of course I could be misremembering too...

skagen00 replied on Wednesday, October 10, 2012

I rebuilt the CSLA dlls without the rethrow and also just writing out the exception that was caught to see what would happen.  Throwing a NotSupportedException in the trigger action's method that is called, I get the full exception.

Obviously one gets the "System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation." piece.  I'm not sure how you feel about it but the exception below would be very valuable in terms of diagnosing errors.

 System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.NotSupportedException: Specified method is not supported.
   at [ProductName].Silverlight.ViewModels.Menu.PaymentVoidMenuItemViewModel.ExecuteAction()
   at [ProductName].Silverlight.ViewModels.Menu.MenuItemViewModelBase.HandleTriggerAction(TriggerAction action, ExecuteEventArgs args)
   at [ProductName].Silverlight.ViewModels.Menu.MenuItemViewModel`1.HandleTriggerAction(TriggerAction action, ExecuteEventArgs args)
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at Csla.Xaml.TriggerAction.CallMethod(Object sender, EventArgs e)

 

 

RockfordLhotka replied on Wednesday, October 10, 2012

What did you change specifically?

skagen00 replied on Wednesday, October 10, 2012

In Csla.Xaml.TriggerAction.CallMethod() towards the bottom - commented the three lines (to just throw the caught exception with the original stack trace)

        catch (System.Reflection.TargetInvocationException ex)
      {
          System.Diagnostics.Debug.WriteLine(ex.ToString());
        //if (ex.InnerException != null)
        //  throw ex.InnerException;
        //else
          throw;
      }

RockfordLhotka replied on Friday, October 12, 2012

That's a breaking change, but might be worth it. My preference is to strip out the useless reflection exception and to just keep the real exception, but losing the stack trace isn't good either.

I'll give this some thought.

skagen00 replied on Friday, October 12, 2012

Yup, I appreciate that.  We've made the change locally (our only one to CSLA) so that we can better assess any errors our clients are encountering - it was always an exception that really gave us no clue as to what they may have encountered..

Thanks for considering it!

Copyright (c) Marimer LLC