英文:
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<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();
}
}
This is my 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);
}
}
}
This is one of my ViewModels where I'm implementing logging:
public class OnboardingViewModel : BaseViewModel
{
private ILogger<OnboardingViewModel> _logger;
public OnboardingViewModel(ILogger<OnboardingViewModel> logger)
{
_logger = logger;
}
private void OnSkipOnboardingCommand()
{
try
{
throw new Exception("Oops! Something went wrong.");
}
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:
However if I change the OnSkipOnboardCommand
to this:
private void OnSkipOnboardingCommand()
{
throw new Exception("Oops! Unhandled Exception.");
}
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.<>c__DisplayClass4_0.<.ctor>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 theOnSkipOnboardingCommand
is being invoked before theHandleUnhandledException
handler has been wired up to the app domain'sUnhandledException
event. You can test this by wiring up theUnhandledException
event handler at the start of theCreateMauiApp
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 tofalse
on theUnhandledExceptionEventArgs
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
这里正在进行一些有用的讨论。
https://github.com/dotnet/maui/discussions/653
经典但依然有价值
英文:
There are some useful discussions going on here
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/
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论