diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/AppComponentBase.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/AppComponentBase.cs index 0ac667ca98..d98e8501aa 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/AppComponentBase.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/AppComponentBase.cs @@ -260,6 +260,6 @@ private void HandleException(Exception exp, } parameters["ComponentType"] = GetType().FullName; - ExceptionHandler.Handle(exp, nonInterrupting: false, parameters, lineNumber, memberName, filePath); + ExceptionHandler.Handle(exp, displayKind: ExceptionDisplayKind.Interrupting, parameters, lineNumber, memberName, filePath); } } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AuthManager.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AuthManager.cs index 4ff01a1466..8f8a0ac3c9 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AuthManager.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AuthManager.cs @@ -128,7 +128,7 @@ async Task RefreshTokenImplementation() { { "AdditionalData", "Refreshing access token failed." }, { "RefreshTokenRequestedBy", requestedBy } - }, nonInterrupting: exp is ReusedRefreshTokenException); + }, displayKind: exp is ReusedRefreshTokenException ? ExceptionDisplayKind.NonInterrupting : ExceptionDisplayKind.Interrupting); if (exp is UnauthorizedException // refresh token is also invalid. || exp is ReusedRefreshTokenException && refreshToken == await storageService.GetItem("refresh_token")) @@ -182,7 +182,7 @@ public async Task TryEnterElevatedAccessMode(CancellationToken cancellatio } catch (TooManyRequestsExceptions exp) { - exceptionHandler.Handle(exp, nonInterrupting: true); // Let's show prompt anyway. + exceptionHandler.Handle(exp, displayKind: ExceptionDisplayKind.NonInterrupting); // Let's show prompt anyway. } var token = await promptService.Show(localizer[AppStrings.EnterElevatedAccessToken], title: "Boilerplate", otpInput: true); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/ClientExceptionHandlerBase.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/ClientExceptionHandlerBase.cs index 0b5c6fa838..b62543db6d 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/ClientExceptionHandlerBase.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/ClientExceptionHandlerBase.cs @@ -12,7 +12,7 @@ public abstract partial class ClientExceptionHandlerBase : SharedExceptionHandle [AutoInject] protected readonly ILogger Logger = default!; public void Handle(Exception exception, - bool nonInterrupting = false, + ExceptionDisplayKind displayKind = ExceptionDisplayKind.Interrupting, Dictionary? parameters = null, [CallerLineNumber] int lineNumber = 0, [CallerMemberName] string memberName = "", @@ -25,11 +25,11 @@ public void Handle(Exception exception, parameters[nameof(lineNumber)] = lineNumber; parameters["exceptionId"] = Guid.NewGuid(); // This will remain consistent across different registered loggers, such as Sentry, Application Insights, etc. - Handle(exception, nonInterrupting, parameters.ToDictionary(i => i.Key, i => i.Value ?? string.Empty)); + Handle(exception, displayKind, parameters.ToDictionary(i => i.Key, i => i.Value ?? string.Empty)); } protected virtual void Handle(Exception exception, - bool nonInterrupting, + ExceptionDisplayKind displayKind, Dictionary parameters) { var isDevEnv = AppEnvironment.IsDev(); @@ -50,16 +50,15 @@ protected virtual void Handle(Exception exception, string exceptionMessageToShow = GetExceptionMessageToShow(exception); - if (nonInterrupting) + if (displayKind is ExceptionDisplayKind.NonInterrupting) { SnackBarService.Error("Boilerplate", exceptionMessageToShow); } - else + else if (displayKind is ExceptionDisplayKind.Interrupting) { MessageBoxService.Show(exceptionMessageToShow, Localizer[nameof(AppStrings.Error)]); } - - if (isDevEnv) + else if (displayKind is ExceptionDisplayKind.None && isDevEnv) { Debugger.Break(); } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/IExceptionHandler.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/IExceptionHandler.cs index 39f6473f4a..bcaff71916 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/IExceptionHandler.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/IExceptionHandler.cs @@ -2,10 +2,26 @@ namespace Boilerplate.Client.Core.Services.Contracts; +public enum ExceptionDisplayKind +{ + /// + /// No error message is shown to the user. + /// + None, + /// + /// Requires the user to acknowledge the error (e.g., by tapping "OK"). + /// + Interrupting, + /// + /// Shows an auto-dismissed message (e.g., a toast notification) + /// + NonInterrupting +} + public interface IExceptionHandler { - void Handle(Exception exception, - bool nonInterrupting = false, + void Handle(Exception exception, + ExceptionDisplayKind displayKind = ExceptionDisplayKind.Interrupting, Dictionary? parameters = null, [CallerLineNumber] int lineNumber = 0, [CallerMemberName] string memberName = "", diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.cs index b430d25058..6259f4c1dc 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.cs @@ -201,7 +201,7 @@ private static void LogException(object? error, string reportedBy) services.GetRequiredService().Handle(exp, parameters: new() { { nameof(reportedBy), reportedBy } - }, nonInterrupting: true); + }, displayKind: AppEnvironment.IsDev() ? ExceptionDisplayKind.NonInterrupting : ExceptionDisplayKind.None); } else { diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiExceptionHandler.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiExceptionHandler.cs index b134234281..c3e053748f 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiExceptionHandler.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiExceptionHandler.cs @@ -9,13 +9,13 @@ namespace Boilerplate.Client.Maui.Services; /// public partial class MauiExceptionHandler : ClientExceptionHandlerBase { - protected override void Handle(Exception exception, bool nonInterrupting, Dictionary parameters) + protected override void Handle(Exception exception, ExceptionDisplayKind displayKind, Dictionary parameters) { exception = UnWrapException(exception); if (IgnoreException(exception)) return; - base.Handle(exception, nonInterrupting, parameters); + base.Handle(exception, displayKind, parameters); } } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/Program.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/Program.cs index 86f6471c70..ee1440bbe6 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/Program.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/Program.cs @@ -80,7 +80,7 @@ private static void LogException(object? error, string reportedBy, WebAssemblyHo services.GetRequiredService().Handle(exp, parameters: new() { { nameof(reportedBy), reportedBy } - }, nonInterrupting: true); + }, displayKind: AppEnvironment.IsDev() ? ExceptionDisplayKind.NonInterrupting : ExceptionDisplayKind.None); } else { diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/Services/WebExceptionHandler.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/Services/WebExceptionHandler.cs index 3af6507cf8..c716a5927b 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/Services/WebExceptionHandler.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/Services/WebExceptionHandler.cs @@ -2,13 +2,13 @@ public partial class WebExceptionHandler : ClientExceptionHandlerBase { - protected override void Handle(Exception exception, bool nonInterrupting, Dictionary parameters) + protected override void Handle(Exception exception, ExceptionDisplayKind displayKind, Dictionary parameters) { exception = UnWrapException(exception); if (IgnoreException(exception)) return; - base.Handle(exception, nonInterrupting, parameters); + base.Handle(exception, displayKind, parameters); } } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.cs index 73009adeb6..4a5405502e 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.cs @@ -129,7 +129,7 @@ private static void LogException(object? error, string reportedBy) Services.GetRequiredService().Handle(exp, parameters: new() { { nameof(reportedBy), reportedBy } - }, nonInterrupting: true); + }, displayKind: AppEnvironment.IsDev() ? ExceptionDisplayKind.NonInterrupting : ExceptionDisplayKind.None); } else { diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsExceptionHandler.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsExceptionHandler.cs index 784793c994..53875eb311 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsExceptionHandler.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsExceptionHandler.cs @@ -2,13 +2,13 @@ public partial class WindowsExceptionHandler : ClientExceptionHandlerBase { - protected override void Handle(Exception exception, bool nonInterrupting, Dictionary parameters) + protected override void Handle(Exception exception, ExceptionDisplayKind displayKind, Dictionary parameters) { exception = UnWrapException(exception); if (IgnoreException(exception)) return; - base.Handle(exception, nonInterrupting, parameters); + base.Handle(exception, displayKind, parameters); } } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Web/Program.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Web/Program.cs index 2bfa6eafb0..554278a1bf 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Web/Program.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Web/Program.cs @@ -61,7 +61,7 @@ private static void LogException(object? error, string reportedBy, WebApplicatio scope.ServiceProvider.GetRequiredService().Handle(exp, parameters: new() { { nameof(reportedBy), reportedBy } - }, nonInterrupting: true); + }, displayKind: AppEnvironment.IsDev() ? ExceptionDisplayKind.NonInterrupting : ExceptionDisplayKind.None); } else {