如何在 try catch 语句中包装 MVVM Light ViewModel?

Posted

技术标签:

【中文标题】如何在 try catch 语句中包装 MVVM Light ViewModel?【英文标题】:How do I wrap a MVVM Light ViewModel in a try catch statement? 【发布时间】:2013-11-04 17:36:01 【问题描述】:

我目前有一个AppDomain.CurrentDomain.UnhandledException 处理程序,当应用程序崩溃时,它会通过电子邮件向我发送堆栈跟踪。这在大多数情况下都可以正常工作,但是当我在 MVVM 轻视图模型中遇到异常时,堆栈跟踪可能相当神秘,并不能真正告诉我它们发生在哪里。有没有一种简单的方法可以将我的视图模型包装在 try catch 语句中,然后我可以将一些更有用的信息注入到异常中,然后重新抛出它?

以下是堆栈跟踪的示例:

在 System.RuntimeMethodHandle.InvokeMethod(对象目标,对象 [] 参数,签名 sig,布尔构造函数) 在 System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(对象 obj,对象 [] 参数,对象 [] 参数) 在 System.Reflection.RuntimeMethodInfo.Invoke(Object obj,BindingFlags invokeAttr,Binder binder,Object[] 参数,CultureInfo 文化) 在 System.Reflection.MethodBase.Invoke(对象 obj,对象 [] 参数) 在 d:\GalaSoft\mydotnet\MvvmLight\Source\GalaSoft.MvvmLight\GalaSoft.MvvmLight (NET35)\Helpers\WeakAction.cs:line 269 中的 GalaSoft.MvvmLight.Helpers.WeakAction.Execute() 在 d:\GalaSoft\mydotnet\MvvmLight\Source\GalaSoft.MvvmLight\GalaSoft.MvvmLight (NET35)\Command\RelayCommand.cs:line 167 中的 GalaSoft.MvvmLight.Command.RelayCommand.Execute(对象参数) 在 MS.Internal.Commands.CommandHelpers.CriticalExecuteCommandSource(ICommandSource commandSource,Boolean userInitiated) 在 System.Windows.Controls.Primitives.ButtonBase.OnClick() 在 System.Windows.Controls.Button.OnClick() 在 System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e) 在 System.Windows.UIElement.OnMouseLeftButtonUpThunk(对象发送者,MouseButtonEventArgs e) 在 System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(委托 genericHandler,对象 genericTarget) 在 System.Windows.RoutedEventArgs.InvokeHandler(委托处理程序,对象目标) 在 System.Windows.RoutedEventHandlerInfo.InvokeHandler(对象目标,RoutedEventArgs routedEventArgs) 在 System.Windows.EventRoute.InvokeHandlersImpl(对象源,RoutedEventArgs args,布尔 reRaised) 在 System.Windows.UIElement.ReRaiseEventAs(DependencyObject 发件人,RoutedEventArgs 参数,RoutedEvent newEvent) 在 System.Windows.UIElement.OnMouseUpThunk(对象发送者,MouseButtonEventArgs e) 在 System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(委托 genericHandler,对象 genericTarget) 在 System.Windows.RoutedEventArgs.InvokeHandler(委托处理程序,对象目标) 在 System.Windows.RoutedEventHandlerInfo.InvokeHandler(对象目标,RoutedEventArgs routedEventArgs) 在 System.Windows.EventRoute.InvokeHandlersImpl(对象源,RoutedEventArgs args,布尔 reRaised) 在 System.Windows.UIElement.RaiseEventImpl(DependencyObject 发件人,RoutedEventArgs 参数) 在 System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs 参数) 在 System.Windows.UIElement.RaiseEvent(RoutedEventArgs 参数,布尔值信任) 在 System.Windows.Input.InputManager.ProcessStagingArea() 在 System.Windows.Input.InputManager.ProcessInput(InputEventArgs 输入) 在 System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport) 在 System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd,InputMode 模式,Int32 时间戳,RawMouseActions 动作,Int32 x,Int32 y,Int32 轮) 在 System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd,WindowMessage msg,IntPtr wParam,IntPtr lParam,布尔&处理) 在 System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd,Int32 msg,IntPtr wParam,IntPtr lParam,Boolean& 处理) 在 MS.Win32.HwndWrapper.WndProc(IntPtr hwnd,Int32 msg,IntPtr wParam,IntPtr lParam,Boolean& 处理) 在 MS.Win32.HwndSubclass.DispatcherCallbackOperation(对象 o) 在 System.Windows.Threading.ExceptionWrapper.InternalRealCall(委托回调,对象 args,Int32 numArgs) 在 MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(对象源,委托方法,对象 args,Int32 numArgs,委托 catchHandler) 在 System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority 优先级,TimeSpan 超时,委托方法,对象 args,Int32 numArgs) 在 MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd,Int32 味精,IntPtr wParam,IntPtr lParam) 在 MS.Win32.UnsafeNativeMethods.DispatchMessage(味精和味精) 在 System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame 框架) 在 System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame 框架) 在 System.Windows.Threading.Dispatcher.Run() 在 System.Windows.Application.RunDispatcher(对象忽略) 在 System.Windows.Application.RunInternal(窗口窗口) 在 System.Windows.Application.Run(窗口窗口) 在 System.Windows.Application.Run() 在 c:|my computer\my projectname\obj\x86\Debug\App.g.cs:line 0 中的 MyApplication.App.Main() 在 System.AppDomain._nExecuteAssembly(RuntimeAssembly 程序集,字符串 [] 参数) 在 System.AppDomain.ExecuteAssembly(字符串 assemblyFile,证据 assemblySecurity,String [] args) 在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 在 System.Threading.ThreadHelper.ThreadStart_Context(对象状态) 在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext,ContextCallback 回调,对象状态,布尔值 preserveSyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback 回调,对象状态,布尔值 preserveSyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback 回调,对象状态) 在 System.Threading.ThreadHelper.ThreadStart()

这是由我的视图模型中的一个方法中的 NotImplementedException 引起的,该方法包含在 RelayCommand 中,因此我可以将按钮绑定到它。没有什么可以让我指出方法的名称或视图模型的名称。

【问题讨论】:

你能展示其中一个神秘的例外吗? 已添加堆栈跟踪。我唯一编辑的是我的应用程序的名称以及其中包含整个项目路径的行。 该异常是否有InnerException 是的,它确实......而且它有更多相关信息!感谢您指出应该是显而易见的。如果你把它写成答案,我会这样标记它 代码将使我的错误消息更易于阅读这一事实让我微笑。 【参考方案1】:

您应该在InnerException 属性中获得更多信息。

如果我没记错的话,您的主要例外是TargetInvocationException 类型。你可以写一个小方法来解开这个:

public Exception Unwrap(TargetInvocationException root)

    if(root.InnerException == null)
        return root;
    var innerException = root.InnerException as TargetInvocationException;
    if(innerException == null)
        return root.InnerException;

    return Unwrap(innerException);

此方法很有帮助,因为您通常有多个级别的TargetInvocationException,而真正的异常隐藏在其中的 3 或 4 个之下。

【讨论】:

【参考方案2】:

如果您已经在处理AppDomain.CurrentDomain.UnhandledException 事件,是否可以不在该处理程序中添加您的信息?:

public void MainWindow_UnhandledException(object sender, UnhandledExceptionEventArgs e)

    Exception exception = (Exception)e.ExceptionObject;
    if (exception.TargetSite.Module.ToString() == "nameOfViewModelAssembly.dll")
    
        if (exception.StackTrace.Contains(nameOfSomeViewModel))
        
            throw new Exception("Problem in nameOfSomeViewModel", exception);
        
        else if (exception.StackTrace.Contains(nameOfOtherViewModel))
        
            throw new Exception("Problem in nameOfOtherViewModel", exception);
        
    

当然,如果您有很多视图模型,这可能会变得很大,但我相信您可以找到更有效的方法来做到这一点。

【讨论】:

堆栈跟踪没有迹象表明它来自哪个视图模型。

以上是关于如何在 try catch 语句中包装 MVVM Light ViewModel?的主要内容,如果未能解决你的问题,请参考以下文章

在 try-catch 块中包装循环会导致性能问题吗? [复制]

javascript 中try catch 语句啥意思

如何在 Javascript 中包装函数?

java中try 与catch的使用?

try

如何使用 jest 在 javascript 中测试 try catch 代码并在 express 中包含带有中间件的 next() 调用?