Skip to content

Commit 1897b05

Browse files
fix: handle component rendering exceptions
1 parent 58b11b8 commit 1897b05

1 file changed

Lines changed: 48 additions & 7 deletions

File tree

src/BlazorDesktop/Services/BlazorDesktopService.cs

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System.Diagnostics.CodeAnalysis;
6+
using System.Reflection;
67
using System.Windows;
8+
using System.Windows.Threading;
79
using BlazorDesktop.Wpf;
810
using WebView2.Runtime.AutoInstaller;
911

@@ -17,28 +19,34 @@ namespace BlazorDesktop.Services;
1719
/// </remarks>
1820
/// <param name="lifetime">The <see cref="IHostApplicationLifetime"/>.</param>
1921
/// <param name="services">The <see cref="IServiceProvider"/>.</param>
22+
/// <param name="logger">The <see cref="ILogger{TCategoryName}"/>.</param>
2023
/// <param name="webViewInstaller">The <see cref="WebViewInstaller"/>.</param>
21-
public class BlazorDesktopService(IHostApplicationLifetime lifetime, IServiceProvider services, WebViewInstaller webViewInstaller) : IHostedService, IDisposable
24+
public partial class BlazorDesktopService(IHostApplicationLifetime lifetime, IServiceProvider services, ILogger<BlazorDesktopService> logger, WebViewInstaller webViewInstaller) : IHostedService, IDisposable
2225
{
2326
/// <summary>
24-
/// The cancellation token registration.
27+
/// The application lifetime.
2528
/// </summary>
26-
private CancellationTokenRegistration _applicationStoppingRegistration;
29+
private readonly IHostApplicationLifetime _lifetime = lifetime;
2730

2831
/// <summary>
29-
/// The application lifetime.
32+
/// The services.
3033
/// </summary>
31-
private readonly IHostApplicationLifetime _lifetime = lifetime;
34+
private readonly IServiceProvider _services = services;
35+
36+
/// <summary>
37+
/// The <see cref="ILogger{TCategoryName}"/>.
38+
/// </summary>
39+
private readonly ILogger<BlazorDesktopService> _logger = logger;
3240

3341
/// <summary>
3442
/// The web view installer.
3543
/// </summary>
3644
private readonly WebViewInstaller _webViewInstaller = webViewInstaller;
3745

3846
/// <summary>
39-
/// The services.
47+
/// The cancellation token registration.
4048
/// </summary>
41-
private readonly IServiceProvider _services = services;
49+
private CancellationTokenRegistration _applicationStoppingRegistration;
4250

4351
/// <summary>
4452
/// Starts the service.
@@ -69,6 +77,15 @@ public Task StopAsync(CancellationToken cancellationToken)
6977
return Task.CompletedTask;
7078
}
7179

80+
/// <summary>
81+
/// Logs an unhanded component exception,
82+
/// </summary>
83+
/// <param name="logger">The <see cref="ILogger"/>.</param>
84+
/// <param name="message">The message.</param>
85+
/// <param name="exception">The <see cref="Exception"/>.</param>
86+
[LoggerMessage(0, LogLevel.Critical, "Unhandled exception rendering component: {Message}", EventName = "ExceptionRenderingComponent")]
87+
private static partial void LogUnhandledExceptionRenderingComponent(ILogger logger, string message, Exception exception);
88+
7289
/// <summary>
7390
/// The application thread.
7491
/// </summary>
@@ -79,10 +96,15 @@ private void ApplicationThread()
7996

8097
app.Startup += OnApplicationStartup;
8198
app.Exit += OnApplicationExit;
99+
app.DispatcherUnhandledException += OnApplicationException;
82100

83101
app.MainWindow = mainWindow;
84102

85103
app.Run();
104+
105+
app.DispatcherUnhandledException -= OnApplicationException;
106+
app.Exit -= OnApplicationExit;
107+
app.Startup -= OnApplicationStartup;
86108
}
87109

88110
/// <summary>
@@ -109,6 +131,25 @@ private void OnApplicationExit(object? sender, ExitEventArgs e)
109131
_lifetime.StopApplication();
110132
}
111133

134+
/// <summary>
135+
/// Occurs when the application throws an exception.
136+
/// </summary>
137+
/// <param name="sender">The sending object.</param>
138+
/// <param name="e">The arguments.</param>
139+
private void OnApplicationException(object sender, DispatcherUnhandledExceptionEventArgs e)
140+
{
141+
if (e.Exception is TargetInvocationException && e.Exception.InnerException is not null)
142+
{
143+
LogUnhandledExceptionRenderingComponent(_logger, e.Exception.InnerException.Message, e.Exception.InnerException);
144+
}
145+
else
146+
{
147+
LogUnhandledExceptionRenderingComponent(_logger, e.Exception.Message, e.Exception);
148+
}
149+
150+
e.Handled = true;
151+
}
152+
112153
/// <summary>
113154
/// Occurs when the application is stopping.
114155
/// </summary>

0 commit comments

Comments
 (0)