你可以使用Serilog来捕获.NET MAUI应用程序中App.cs中的未处理异常。

huangapple go评论81阅读模式
英文:

How can I use Serilog to catch Unhandled Exceptions in the App.cs of a .NET MAUI application?

问题

我明白你的要求,以下是你要翻译的内容:

我正在使用Azure表存储作为存储机制。我可以从ViewModel内部写入异常到Azure表,但是当我尝试在App.cs中添加处理未处理的异常时,异常会记录在调试输出窗口上,但不会存储在Azure表中。

这是我的Program.cs

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
                fonts.AddFont("SF-Pro-Text-Bold.otf", "SFProTextBold");
                fonts.AddFont("SF-Pro-Text-Regular.otf", "SFProTextRegular");
                fonts.AddFont("materialdesignicons-webfont.ttf", "MaterialDesignIcons");
            });

        builder.UseMauiApp<App>()
            .UseMauiCommunityToolkit()
            .RegisterDataServices()
            .RegisterViewModels()
            .RegisterViews();

        builder.Logging.AddSerilog();

        var storageConnectionString = "MY_CONNECTION_STRING";
        var tableName = "logs";

        Log.Logger = new LoggerConfiguration()
            .WriteTo.AzureTableStorage(connectionString: storageConnectionString, storageTableName: tableName)
            .WriteTo.Debug()
            .CreateLogger();

        return builder.Build();
    }
}

这是我的App.cs:

public partial class App : Application
{
    private readonly ILogger<App> _logger;

    public App(ILogger<App> logger)
    {
        _logger = logger;
        InitializeComponent();
        AppDomain.CurrentDomain.UnhandledException += HandleUnhandledException;
        MainPage = new AppShell();
    }

    private void HandleUnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        var exception = (Exception)e.ExceptionObject;
        _logger.LogCritical(exception, exception.Message);
    }
}

这是我其中一个实现日志记录的ViewModel:

public class OnboardingViewModel : BaseViewModel
{
    private ILogger<OnboardingViewModel> _logger;

    public OnboardingViewModel(ILogger<OnboardingViewModel> logger)
    {
        _logger = logger;
    }

    private void OnSkipOnboardingCommand()
    {
        try
        {
            throw new Exception("Oops!出了点问题。");
        }
        catch (Exception e)
        {
            _logger.LogError(e, e.Message);
        }
    }
}

希望这些帮助你理解代码的翻译。

英文:

I'm using Azure Table Storage to as a storage mechanism. I'm able to write exceptions within a ViewModel to the Azure Table from within the ViewModel, but when I try to add a handler to unhandled exceptions on App.cs the exception is logged on the Debug output window, but it isn't stored on the Azure Table.

This is my Program.cs:

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp&lt;App&gt;()
            .ConfigureFonts(fonts =&gt;
            {
                fonts.AddFont(&quot;OpenSans-Regular.ttf&quot;, &quot;OpenSansRegular&quot;);
                fonts.AddFont(&quot;OpenSans-Semibold.ttf&quot;, &quot;OpenSansSemibold&quot;);
                fonts.AddFont(&quot;SF-Pro-Text-Bold.otf&quot;, &quot;SFProTextBold&quot;);
                fonts.AddFont(&quot;SF-Pro-Text-Regular.otf&quot;, &quot;SFProTextRegular&quot;);
                fonts.AddFont(&quot;materialdesignicons-webfont.ttf&quot;, &quot;MaterialDesignIcons&quot;);
            });

        builder.UseMauiApp&lt;App&gt;()
            .UseMauiCommunityToolkit()
            .RegisterDataServices()
            .RegisterViewModels()
            .RegisterViews();

        builder.Logging.AddSerilog();

        var storageConnectionString = &quot;MY_CONNECTION_STRING&quot;;
        var tableName = &quot;logs&quot;;

        Log.Logger = new LoggerConfiguration()
            .WriteTo.AzureTableStorage(connectionString: storageConnectionString, storageTableName: tableName)
            .WriteTo.Debug()
            .CreateLogger();

        return builder.Build();
    }
}

This is my App.cs:

public partial class App : Application
	{
		private readonly ILogger&lt;App&gt;_logger;

		public App(ILogger&lt;App&gt; logger)
		{
			_logger = logger;
			InitializeComponent();
			AppDomain.CurrentDomain.UnhandledException += HandleUnhandledException;
			MainPage = new AppShell();
		}

		private void HandleUnhandledException(object sender, UnhandledExceptionEventArgs e)
		{
			var exception = (Exception)e.ExceptionObject;
			_logger.LogCritical(exception, exception.Message);
		}
	}
}

This is one of my ViewModels where I'm implementing logging:

public class OnboardingViewModel : BaseViewModel
{
    private ILogger&lt;OnboardingViewModel&gt; _logger;

    public OnboardingViewModel(ILogger&lt;OnboardingViewModel&gt; logger)
    {
        _logger = logger;
    }

    private void OnSkipOnboardingCommand()
    {
        try
        {
            throw new Exception(&quot;Oops! Something went wrong.&quot;);
        }
        catch (Exception e)
        {
            _logger.LogError(e, e.Message);
        }
    }
}

When I try this the exception is shown on the output window and saved to the Azure Table:

你可以使用Serilog来捕获.NET MAUI应用程序中App.cs中的未处理异常。

However if I change the OnSkipOnboardCommand to this:

private void OnSkipOnboardingCommand()
{
	throw new Exception(&quot;Oops! Unhandled Exception.&quot;);
}

I receive the exception on the HandleUnhandledException methond on App.cs. The exception is logged only to the Output Window:

[0:] [07:38:43 FTL] Oops! Unhandled Exception.
System.Exception: Oops! Unhandled Exception.
   at MyApp.Mobile.ViewModels.OnboardingViewModel.OnSkipOnboardingCommand() in C:\Users\Developer\Development\MyApp\src\MyApp.Mobile\ViewModels\OnboardingViewModel.cs:line 74
   at Microsoft.Maui.Controls.Command.&lt;&gt;c__DisplayClass4_0.&lt;.ctor&gt;b__0(Object o) in D:\a\_work\s\src\Controls\src\Core\Command.cs:line 80
   at Microsoft.Maui.Controls.Command.Execute(Object parameter) in D:\a\_work\s\src\Controls\src\Core\Command.cs:line 123
   at Microsoft.Maui.Controls.TapGestureRecognizer.SendTapped(View sender, Func`2 getPosition) in D:\a\_work\s\src\Controls\src\Core\TapGestureRecognizer.cs:line 59
   at Microsoft.Maui.Controls.Platform.TapGestureHandler.OnTap(Int32 count, MotionEvent e) in D:\a\_work\s\src\Controls\src\Core\Platform\Android\TapGestureHandler.cs:line 69
   at Microsoft.Maui.Controls.Platform.InnerGestureListener.Android.Views.GestureDetector.IOnGestureListener.OnSingleTapUp(MotionEvent e) in D:\a\_work\s\src\Controls\src\Core\Platform\Android\InnerGestureListener.cs:line 157
   at Android.Views.GestureDetector.IOnGestureListenerInvoker.n_OnSingleTapUp_Landroid_view_MotionEvent_(IntPtr jnienv, IntPtr native__this, IntPtr native_e) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net8.0/android-33/mcw/Android.Views.GestureDetector.cs:line 711
   at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PPL_Z(_JniMarshal_PPL_Z callback, IntPtr jnienv, IntPtr klazz, IntPtr p0) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:line 137
   at Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualBooleanMethod(JniObjectReference instance, JniObjectReference type, JniMethodInfo method, JniArgumentValue* args) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/obj/Release/net7.0/JniEnvironment.g.cs:line 11969
   at Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualBooleanMethod(String encodedMember, IJavaPeerable self, JniArgumentValue* parameters) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs:line 164
   at Android.Views.GestureDetector.OnTouchEvent(MotionEvent ev) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net8.0/android-33/mcw/Android.Views.GestureDetector.cs:line 1639
   at Microsoft.Maui.Controls.Platform.TapAndPanGestureDetector.OnTouchEvent(MotionEvent ev) in D:\a\_work\s\src\Controls\src\Core\Platform\Android\TapAndPanGestureDetector.cs:line 36
   at Microsoft.Maui.Controls.Platform.GesturePlatformManager.OnTouchEvent(MotionEvent e) in D:\a\_work\s\src\Controls\src\Core\Platform\GestureManager\GesturePlatformManager.Android.cs:line 83
   at Microsoft.Maui.Controls.Platform.GesturePlatformManager.OnPlatformViewTouched(Object sender, TouchEventArgs e) in D:\a\_work\s\src\Controls\src\Core\Platform\GestureManager\GesturePlatformManager.Android.cs:line 204
   at Android.Views.View.IOnTouchListenerImplementor.OnTouch(View v, MotionEvent e) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net8.0/android-33/mcw/Android.Views.View.cs:line 4196
   at Android.Views.View.IOnTouchListenerInvoker.n_OnTouch_Landroid_view_View_Landroid_view_MotionEvent_(IntPtr jnienv, IntPtr native__this, IntPtr native_v, IntPtr native_e) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net8.0/android-33/mcw/Android.Views.View.cs:line 4137
   at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PPLL_Z(_JniMarshal_PPLL_Z callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, IntPtr p1) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:line 236

However the exception is not persisted on Azure Storage. This only happens with the exceptions on the HandleUnhandledException method on the App.cs.

The fact the the exception is written to the Output Window but not to the Azure Table really confuses me.

Any idea on why this is happening or how I could get Unhandled Exceptions and store them on Azure Tables using Serilog? Should I change something on my code?

What I found

答案1

得分: 3

以下是翻译好的内容:

我认为这里有几种选择:

  • 异常在能够冒泡到应用程序域的“UnhandledException”事件处理程序之前被捕获了。我不熟悉MAIU如何将错误记录到控制台,但也许这可能是问题所在。
  • 在你的“CreateMauiApp”方法中,你设置应用程序并注册视图模型、视图等,可能在“OnSkipOnboardingCommand”被调用之前,尚未将“HandleUnhandledException”处理程序连接到应用程序域的“UnhandledException”事件。你可以尝试在“CreateMauiApp”方法的开始处连接“UnhandledException”事件处理程序来测试这一点。
  • 正如你的帖子上的一名评论者已经指出的,可能在进程有足够时间将日志写入Azure表之前,就被操作系统终止了。你可以通过将“UnhandledExceptionEventArgs”对象上的“ExitApplication”属性更改为“false”来测试是否是这个问题,这将允许它继续运行。

我还建议阅读Microsoft的“UnhandledException”事件的文档,根据我记忆,它不能捕获某些类别的关键异常。

英文:

I think there's a few options here:

  • The exception is being caught before it can bubble up to the app domain's UnhandledException event handler. I'm not familiar with how MAIU handles its logging of errors to the console, but perhaps this could be the issue.
  • In your CreateMauiApp method, where you're setting up your app and registering the view model, view, etc, it's possible that the OnSkipOnboardingCommand is being invoked before the HandleUnhandledException handler has been wired up to the app domain's UnhandledException event. You can test this by wiring up the UnhandledException event handler at the start of the CreateMauiApp method.
  • As already pointed out by a commenter on your post, it's possible that your process doesn't have enough time to write the log to the Azure table before it's been killed by the OS. You could test to see if this is the issue, by changing the ExitApplication property to false on the UnhandledExceptionEventArgs object, which will allow it to remain running.

I'd also recommend reading Microsoft's documentation for the UnhandledException event, from memory you won't be able to catch certain classes of critical exceptions with it.

答案2

得分: 0

这里正在进行一些有用的讨论。

你可以使用Serilog来捕获.NET MAUI应用程序中App.cs中的未处理异常。

https://github.com/dotnet/maui/discussions/653

经典但依然有价值

https://peterno.wordpress.com/2015/04/15/unhandled-exception-handling-in-ios-and-android-with-xamarin/

英文:

There are some useful discussions going on here
你可以使用Serilog来捕获.NET MAUI应用程序中App.cs中的未处理异常。

https://github.com/dotnet/maui/discussions/653
old but gold
https://peterno.wordpress.com/2015/04/15/unhandled-exception-handling-in-ios-and-android-with-xamarin/

huangapple
  • 本文由 发表于 2023年5月22日 18:51:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/76305428.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定