Skip to content

Enrich exceptions logs in Boilerplate server exception handler (#9933)#9934

Merged
msynk merged 18 commits intobitfoundation:developfrom
yasmoradi:release
Feb 18, 2025
Merged

Enrich exceptions logs in Boilerplate server exception handler (#9933)#9934
msynk merged 18 commits intobitfoundation:developfrom
yasmoradi:release

Conversation

@yasmoradi
Copy link
Member

@yasmoradi yasmoradi commented Feb 17, 2025

closes #9933

Summary by CodeRabbit

  • Build & Deployment
    • Optimized the Windows build to target 64‑bit systems with faster startup performance.
  • User Experience
    • Enhanced feedback for authentication and account actions, providing clearer error messages on lockout and retry timings.
  • Refactor
    • Streamlined error handling and logging across services to ensure improved diagnostics and overall reliability.

@yasmoradi yasmoradi requested a review from msynk February 17, 2025 23:11
@coderabbitai
Copy link

coderabbitai bot commented Feb 17, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This pull request introduces significant improvements in error handling, logging, and build configuration. The changes update the Windows build process to target 64-bit and enable ReadyToRun. Numerous modifications across client and server components add contextual data to exceptions using new extension methods and centralized handling via a ServerExceptionHandler. Service registration and configuration adjustments further streamline error reporting and telemetry, while updates in shared DTOs and logging configurations enhance serialization and log filtering. Overall, the modifications advance predictable exception flows and improve diagnostics.

Changes

File(s) Change Summary
.github/workflows/admin-sample.cd.yml Updated Windows build configuration: switched from win-x86 to win-x64, enabled ReadyToRun, and removed an unused environment variable.
src/.../DiagnosticModal.razor.cs
src/.../SignInPage.razor.cs
src/.../ClientExceptionHandlerBase.cs
src/.../ExceptionDelegatingHandler.cs
Enhanced client-side exception handling by adding contextual data using WithData and incorporating detailed exception information.
src/.../IdentityController.EmailConfirmation.cs
src/.../IdentityController.PhoneConfirmation.cs
src/.../IdentityController.ResetPassword.cs
src/.../IdentityController.SocialSignIn.cs
src/.../IdentityController.cs
src/.../UserController.cs
Improved error reporting in identity controllers with added exception context (user IDs, emails, phone numbers) and centralized handling via a new ServerExceptionHandler.
src/.../ProductConfiguration.cs
src/.../Program.Services.cs
src/.../EmailService.cs
src/.../NugetStatisticsService.cs
src/.../PhoneService.cs
src/.../PushNotificationService.cs
src/.../ServerExceptionHandler.cs
Refined server-side configurations and service registrations. Updates include property configuration changes, replacing direct logger calls with the centralized ServerExceptionHandler, and adding richer contextual logging.
src/.../AppHub.cs Added connection identifier to exceptions in unauthorized SignalR connections for improved traceability.
src/.../AppJsonContext.cs
src/.../IdentityRequestDto.cs
src/.../KnownException.cs
src/.../KnownExceptionExtensions.cs
src/.../ExceptionExtensions.cs
Introduced new extension methods for adding exception data, a custom string representation for IdentityRequestDto, and enhanced serialization options with TimeSpan support.
src/.../appsettings.Development.json
src/.../appsettings.json
Configured logging by setting specific log levels for exception handling middleware to "None" across several logging sections.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant API_Controller
    participant Service
    participant ServerExceptionHandler
    participant Logger

    Client->>API_Controller: Request operation
    API_Controller->>Service: Invoke business logic
    Service-->>Service: Exception occurs with added context (WithData)
    Service-->>API_Controller: Throws enhanced exception
    API_Controller->>ServerExceptionHandler: Handle(exception, context)
    ServerExceptionHandler->>Logger: Log exception details with additional data
    Logger-->>ServerExceptionHandler: Confirm logged details
    ServerExceptionHandler-->>API_Controller: Returns detailed problem response
Loading

Poem

Hey there, I'm a coding bunny, full of glee,
Hopping through errors with data set free.
My logs now sparkle like carrots at night,
Each exception enriched with extra insight.
With changes so crisp and fixes so neat,
My code garden’s blooming—oh, how sweet!
Let's hop into tomorrow with optimized delight!


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@yasmoradi yasmoradi marked this pull request as ready for review February 18, 2025 11:05
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (22)
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.SocialSignIn.cs (1)

95-95: Consider using object initialization for better readability.

Good enhancement of exception handling with contextual information. Consider making the dictionary creation more concise and explicit:

-serverExceptionHandler.Handle(exp, new() { { "LoginProvider", info?.LoginProvider }, { "Principal", info?.Principal?.GetDisplayName() } });
+serverExceptionHandler.Handle(exp, new()
+{
+    ["LoginProvider"] = info?.LoginProvider ?? "(none)",
+    ["Principal"] = info?.Principal?.GetDisplayName() ?? "(unknown)"
+});

This makes the code more readable and provides explicit fallback values for logging when the values are null.

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppHub.cs (1)

28-31: Consider adding more diagnostic context.

While the addition of ConnectionId is valuable, consider enriching the exception data further with:

  • Token expiration timestamp (if available)
  • Token type (access/refresh)
    This additional context could help identify patterns in token expiration issues.

Example enhancement:

- throw new HubException(nameof(AppStrings.UnauthorizedException)).WithData("ConnectionId", Context.ConnectionId);
+ throw new HubException(nameof(AppStrings.UnauthorizedException))
+     .WithData("ConnectionId", Context.ConnectionId)
+     .WithData("TokenType", Context.GetHttpContext()?.Request.Headers.Authorization.FirstOrDefault()?.StartsWith("Bearer ") == true ? "Bearer" : "Unknown")
+     .WithData("AuthorizationPresent", true);
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/UserController.cs (1)

395-395: Consider using a more explicit capacity for List initialization.

The list initialization at line 395 uses an empty collection initializer. For better performance, consider specifying an initial capacity based on the maximum number of possible tasks (email, SMS, SignalR, push notification).

-List<Task> sendMessagesTasks = [];
+List<Task> sendMessagesTasks = new(capacity: 4); // Max 4 tasks: email, SMS, SignalR, push notification
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.PhoneConfirmation.cs (1)

39-42: Simplify the lockout duration calculation.

While the error context enrichment is good, the lockout duration calculation can be simplified.

Consider this simpler calculation:

-            var tryAgainIn = (user.LockoutEnd! - DateTimeOffset.UtcNow).Value;
-            throw new BadRequestException(Localizer[nameof(AppStrings.UserLockedOut), (DateTimeOffset.UtcNow - user.LockoutEnd!).Value.Humanize(culture: CultureInfo.CurrentUICulture)]).WithData("UserId", user.Id).WithExtensionData("TryAgainIn", tryAgainIn);
+            var tryAgainIn = user.LockoutEnd!.Value - DateTimeOffset.UtcNow;
+            throw new BadRequestException(Localizer[nameof(AppStrings.UserLockedOut), tryAgainIn.Humanize(culture: CultureInfo.CurrentUICulture)])
+                .WithData("UserId", user.Id)
+                .WithExtensionData("TryAgainIn", tryAgainIn);
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.ResetPassword.cs (3)

21-21: LGTM! Enhanced exception with user context.

Including the user ID in the exception is valuable for tracing issues. Consider also including the confirmation status (email/phone) to provide more specific context about which confirmation is missing.

-throw new BadRequestException(Localizer[nameof(AppStrings.UserIsNotConfirmed)]).WithData("UserId", user.Id);
+throw new BadRequestException(Localizer[nameof(AppStrings.UserIsNotConfirmed)])
+    .WithData("UserId", user.Id)
+    .WithData("EmailConfirmed", await userManager.IsEmailConfirmedAsync(user))
+    .WithData("PhoneConfirmed", await userManager.IsPhoneNumberConfirmedAsync(user));

26-26: Fix typo in exception class name and approve enhanced context.

The exception includes comprehensive context with both user ID and retry delay, which is excellent. However, there's a typo in the exception class name.

-throw new TooManyRequestsExceptions(
+throw new TooManyRequestsException(

89-89: LGTM! Consider adding remaining attempts information.

While adding the user ID is valuable, consider including the remaining attempts before account lockout to provide more context.

-throw new BadRequestException(nameof(AppStrings.InvalidToken)).WithData("UserId", user.Id);
+throw new BadRequestException(nameof(AppStrings.InvalidToken))
+    .WithData("UserId", user.Id)
+    .WithData("RemainingAttempts", await userManager.GetAccessFailedCountAsync(user));
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/appsettings.json (1)

2-6: Preprocessor Directives in JSON Configuration
The file includes preprocessor-like comments (e.g., //#if (appInsights == true) and //#endif) that are not standard JSON syntax and are triggering static analysis errors. Please ensure that your build or pre-processing pipeline properly strips or handles these directives before the file is consumed by a strict JSON parser.

🧰 Tools
🪛 Biome (1.9.4)

[error] 2-3: Expected a property but instead found '//#if (appInsights == true)'.

Expected a property here.

(parse)


[error] 3-3: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 3-3: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 3-5: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Services/ServerExceptionHandler.cs (3)

10-13: Consider consolidating environment references if not strictly necessary.
You're injecting both IHostEnvironment and IWebHostEnvironment. If you only need the environment name, consider using one of them to simplify maintenance.


111-123: Use more granular log levels for known exceptions.
Currently, you use LogError for known exceptions and LogCritical for the rest. Consider further distinctions (e.g., LogWarning or LogInformation) for specific exceptions that do not constitute an error or critical condition.


125-130: Decide on a fallback approach when instance or traceIdentifier is missing.
The code returns early if either is null, thus no ProblemDetails is written. In certain edge cases (e.g., diagnostics), you might prefer to provide partial details or a different fallback.

src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Extensions/ExceptionExtensions.cs (1)

8-17: Consider updating dictionary insertion to avoid duplicate key exceptions.
exception.Data.Add(item.Key, item.Value) can throw if the key already exists. Using index assignment (e.g., exception.Data[item.Key] = item.Value) might be safer if overwriting is acceptable.

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Extensions/KnownExceptionExtensions.cs (1)

9-18: Evaluate merging or reusing extension data logic.
WithExtensionData iterates through a dictionary and repeatedly calls WithExtensionData(key, value). This is consistent but duplicates the logic for each pair. Consider a single logic path to maintain consistency and reduce code duplication.

src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Exceptions/KnownException.cs (1)

34-52: LGTM! Well-implemented TryGet pattern with comprehensive type handling.

The implementation safely handles both direct type casting and JSON deserialization scenarios.

Consider adding XML documentation for the type parameter and return value:

 /// <summary>
 /// Read KnownExceptionExtensions.WithExtensionData comments.
 /// </summary>
+/// <typeparam name="T">The type of the value to retrieve.</typeparam>
+/// <param name="key">The key of the extension data to retrieve.</param>
+/// <param name="value">When this method returns, contains the value associated with the specified key, if found; otherwise, the default value for the type.</param>
+/// <returns>true if the key was found; otherwise, false.</returns>
 public bool TryGetExtensionDataValue<T>(string key, out T value)
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Services/PhoneService.cs (1)

41-63: Consider using a proper background job system.

The current fire-and-forget pattern using Task.Run could lead to lost exceptions or unhandled failures if the application shuts down. Consider using a proper message queue or background job system like Hangfire, as mentioned in the comment.

Example implementation using a background job interface:

-_ = Task.Run(async () => // Let's not wait for the sms to be sent. Consider using a proper message queue or background job system like Hangfire.
-{
-    await using var scope = rootServiceScopeProvider.Invoke();
-    var serverExceptionHandler = scope.ServiceProvider.GetRequiredService<ServerExceptionHandler>();
-    MessageResource? smsMessage = null;
-    try
-    {
-        var messageOptions = new CreateMessageOptions(new(phoneNumber))
-        {
-            From = new(from),
-            Body = messageText
-        };
-
-        smsMessage = MessageResource.Create(messageOptions);
-
-        if (smsMessage.ErrorCode is not null)
-            throw new InvalidOperationException(smsMessage.ErrorMessage).WithData(new() { { "Code", smsMessage.ErrorCode } });
-    }
-    catch (Exception exp)
-    {
-        serverExceptionHandler.Handle(exp, new() { { "PhoneNumber", phoneNumber } });
-    }
-}, default);
+await _backgroundJob.EnqueueAsync<IPhoneService>(
+    service => service.SendSmsBackground(messageText, phoneNumber, from),
+    cancellationToken);

Add a new method for background processing:

public async Task SendSmsBackground(string messageText, string phoneNumber, string from)
{
    MessageResource? smsMessage = null;
    try
    {
        var messageOptions = new CreateMessageOptions(new(phoneNumber))
        {
            From = new(from),
            Body = messageText
        };

        smsMessage = MessageResource.Create(messageOptions);

        if (smsMessage.ErrorCode is not null)
            throw new InvalidOperationException(smsMessage.ErrorMessage).WithData(new() { { "Code", smsMessage.ErrorCode } });
    }
    catch (Exception exp)
    {
        var serverExceptionHandler = _serviceProvider.GetRequiredService<ServerExceptionHandler>();
        serverExceptionHandler.Handle(exp, new() { { "PhoneNumber", phoneNumber } });
        throw; // Re-throw to let the background job system handle the failure
    }
}
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/DiagnosticModal.razor.cs (3)

136-138: LGTM! Consider adding more test data.

The addition of contextual data to test exceptions using WithData aligns with the PR objective of enriching exception logs. Consider adding more test data fields to better simulate real-world scenarios.

-            ? new InvalidOperationException("Something critical happened.").WithData("TestData", 1)
-            : new DomainLogicException("Something bad happened.").WithData("TestData", 2);
+            ? new InvalidOperationException("Something critical happened.")
+                .WithData("TestData", 1)
+                .WithData("TestTimestamp", DateTimeOffset.UtcNow)
+                .WithData("TestSource", "DiagnosticModal")
+            : new DomainLogicException("Something bad happened.")
+                .WithData("TestData", 2)
+                .WithData("TestTimestamp", DateTimeOffset.UtcNow)
+                .WithData("TestSource", "DiagnosticModal");

137-138: LGTM! Consider adding more test data.

The addition of contextual data to test exceptions using WithData aligns with the PR objective of enriching exception logs. Consider adding more test data to simulate real-world scenarios.

-            ? new InvalidOperationException("Something critical happened.").WithData("TestData", 1)
-            : new DomainLogicException("Something bad happened.").WithData("TestData", 2);
+            ? new InvalidOperationException("Something critical happened.")
+                .WithData("TestData", 1)
+                .WithData("TestTimestamp", DateTimeOffset.UtcNow)
+                .WithData("TestContext", "DiagnosticModal")
+            : new DomainLogicException("Something bad happened.")
+                .WithData("TestData", 2)
+                .WithData("TestTimestamp", DateTimeOffset.UtcNow)
+                .WithData("TestContext", "DiagnosticModal");

137-138: LGTM! Good enhancement of exception data.

The addition of contextual data to exceptions using WithData improves debugging capabilities by providing more context when exceptions are thrown.

Consider adding more descriptive test data to better simulate real-world scenarios. For example:

-            ? new InvalidOperationException("Something critical happened.").WithData("TestData", 1)
-            : new DomainLogicException("Something bad happened.").WithData("TestData", 2);
+            ? new InvalidOperationException("Something critical happened.").WithData("Operation", "CriticalTest").WithData("Severity", "High")
+            : new DomainLogicException("Something bad happened.").WithData("Domain", "TestModule").WithData("Impact", "Medium");
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Services/EmailService.cs (2)

140-141: LGTM! Consider adding more context data.

The transition from direct logging to using ServerExceptionHandler with contextual data aligns with the PR objective. Consider adding more context data to help with debugging.

-                serverExceptionHandler.Handle(exp, new() { { "Subject", subject }, { "ToEmailAddress", toEmailAddress } });
+                serverExceptionHandler.Handle(exp, new() 
+                { 
+                    { "Subject", subject }, 
+                    { "ToEmailAddress", toEmailAddress },
+                    { "FromEmail", defaultFromEmail },
+                    { "FromName", defaultFromName },
+                    { "IsHtml", true }
+                });

Also applies to: 157-157


140-141: LGTM! Good transition to centralized exception handling.

The change from direct logging to using ServerExceptionHandler improves consistency in error handling across the application. The contextual data (Subject and ToEmailAddress) provides valuable information for debugging email-related issues.

Consider adding more contextual data to enrich the exception further:

-                serverExceptionHandler.Handle(exp, new() { { "Subject", subject }, { "ToEmailAddress", toEmailAddress } });
+                serverExceptionHandler.Handle(exp, new() 
+                { 
+                    { "Subject", subject }, 
+                    { "ToEmailAddress", toEmailAddress },
+                    { "EmailProvider", emailSettings.Host },
+                    { "IsTestEnvironment", emailSettings.UseLocalFolderForEmails }
+                });

Also applies to: 157-158

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.cs (2)

56-56: Excellent enhancement of exception handling with contextual data!

The changes consistently enrich exceptions with relevant contextual data (user IDs, session IDs, etc.), which will significantly improve debugging and monitoring capabilities. This aligns perfectly with the PR's objective of enhancing exception logs.

However, consider adding structured logging for these exceptions to ensure the contextual data is properly captured in the logs.

Add structured logging after throwing exceptions:

 throw new BadRequestException(Localizer[nameof(AppStrings.DuplicateEmailOrPhoneNumber)]).WithData("UserId", existingUser.Id);
+logger.LogError("Duplicate email or phone number detected for user {UserId}", existingUser.Id);

Also applies to: 96-96, 120-120, 124-126, 141-142, 149-150, 156-157, 231-231, 238-244, 301-301, 303-304, 308-309, 351-352, 361-361, 365-366, 370-371, 419-419


233-234: Consider using string interpolation for better readability.

The session stamp value comparison could be more readable using string interpolation.

-var sessionStampValueInDatabase = (userSession.RenewedOn ?? userSession.StartedOn).ToUnixTimeSeconds();
-var sessionStampValueInJwtToken = long.Parse(refreshTicket.Principal.Claims.Single(c => c.Type == AppClaimTypes.SESSION_STAMP).Value);
+var sessionStampValueInDatabase = (userSession.RenewedOn ?? userSession.StartedOn).ToUnixTimeSeconds();
+var sessionStampValueInJwtToken = long.Parse(refreshTicket.Principal.GetClaimValue(AppClaimTypes.SESSION_STAMP));

Also applies to: 235-235

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 83be4f6 and 779c8c3.

📒 Files selected for processing (26)
  • .github/workflows/admin-sample.cd.yml (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/DiagnosticModal.razor.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignIn/SignInPage.razor.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/ClientExceptionHandlerBase.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/HttpMessageHandlers/ExceptionDelegatingHandler.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.EmailConfirmation.cs (4 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.PhoneConfirmation.cs (3 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.ResetPassword.cs (2 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.SocialSignIn.cs (3 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.cs (10 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/UserController.cs (4 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Configurations/Product/ProductConfiguration.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Extensions/KnownExceptionExtensions.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Program.Services.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Services/EmailService.cs (2 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Services/NugetStatisticsService.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Services/PhoneService.cs (2 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Services/PushNotificationService.cs (2 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Services/ServerExceptionHandler.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppHub.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/AppJsonContext.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/Identity/IdentityRequestDto.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Exceptions/KnownException.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Extensions/ExceptionExtensions.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/appsettings.Development.json (3 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/appsettings.json (3 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignIn/SignInPage.razor.cs
🧰 Additional context used
🪛 Biome (1.9.4)
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/appsettings.json

[error] 13-14: Expected a property but instead found '//#if (appInsights == true)'.

Expected a property here.

(parse)


[error] 13-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 14-14: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 40-42: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 42-42: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 42-42: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 61-62: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 62-62: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 62-62: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 62-68: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 68-69: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 69-69: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 69-69: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)

src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/appsettings.Development.json

[error] 10-11: Expected a property but instead found '//#if (appInsights == true)'.

Expected a property here.

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 11-11: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 36-38: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 38-38: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 38-38: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 61-62: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 62-62: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 62-62: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 62-69: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 69-70: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 70-70: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)


[error] 70-70: End of file expected

Use an array for a sequence of values: [1, 2]

(parse)

⏰ Context from checks skipped due to timeout of 90000ms (20)
  • GitHub Check: deploy api + blazor
  • GitHub Check: deploy api + blazor
  • GitHub Check: deploy api + blazor
  • GitHub Check: deploy api + blazor
  • GitHub Check: build blazor wasm standalone (small)
  • GitHub Check: build blazor wasm standalone (Offline database)
  • GitHub Check: build blazor wasm standalone (AOT)
  • GitHub Check: build blazor hybrid (windows)
  • GitHub Check: build blazor hybrid (android)
  • GitHub Check: build blazor hybrid (iOS-macOS)
  • GitHub Check: build blazor wasm standalone
  • GitHub Check: build api + blazor web
  • GitHub Check: build blazor hybrid (iOS-macOS)
  • GitHub Check: build blazor hybrid (windows)
  • GitHub Check: build blazor hybrid (android)
  • GitHub Check: build api + blazor web
  • GitHub Check: build blazor hybrid (windows)
  • GitHub Check: build blazor hybrid (iOS-macOS)
  • GitHub Check: build blazor hybrid (android)
  • GitHub Check: build and test
🔇 Additional comments (43)
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.SocialSignIn.cs (1)

11-11: LGTM! Clean dependency injection.

The ServerExceptionHandler is properly injected following the existing patterns.

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppHub.cs (1)

31-31: Great enhancement to exception context!

The addition of ConnectionId to the exception data improves debugging capabilities by providing crucial context about which connection triggered the unauthorized access attempt. This aligns well with the PR's objective of enriching exception logs.

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/UserController.cs (4)

132-134: Improved user feedback for account lockouts.

The enhanced error handling now includes the exact duration until the user can retry, improving the user experience.


163-163: Verify email token resend delay calculation.

The resend delay calculation at line 160 uses DateTimeOffset.Now which can lead to time-related issues in distributed systems.

Consider using DateTimeOffset.UtcNow for consistency:

-var resendDelay = (DateTimeOffset.Now - user!.EmailTokenRequestedOn) - AppSettings.Identity.EmailTokenLifetime;
+var resendDelay = (DateTimeOffset.UtcNow - user!.EmailTokenRequestedOn) - AppSettings.Identity.EmailTokenLifetime;

224-224: Verify phone token resend delay calculation.

Similar to the email token, the phone token resend delay calculation at line 221 uses local time instead of UTC.

Consider using DateTimeOffset.UtcNow for consistency:

-var resendDelay = (DateTimeOffset.Now - user!.PhoneNumberTokenRequestedOn) - AppSettings.Identity.PhoneNumberTokenLifetime;
+var resendDelay = (DateTimeOffset.UtcNow - user!.PhoneNumberTokenRequestedOn) - AppSettings.Identity.PhoneNumberTokenLifetime;

381-381: Verify elevated access token resend delay calculation.

The elevated access token resend delay calculation at line 377 also uses local time.

Consider using DateTimeOffset.UtcNow for consistency:

-var resendDelay = (DateTimeOffset.Now - user!.ElevatedAccessTokenRequestedOn) - AppSettings.Identity.BearerTokenExpiration;
+var resendDelay = (DateTimeOffset.UtcNow - user!.ElevatedAccessTokenRequestedOn) - AppSettings.Identity.BearerTokenExpiration;
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.PhoneConfirmation.cs (4)

18-18: LGTM! Enhanced error context for phone confirmation.

The additions of phone number and user ID to the exceptions improve error traceability and debugging capabilities.

Also applies to: 21-21


49-49: LGTM! Consistent error context enrichment.

Good addition of user ID context to all exceptions, improving error traceability throughout the phone confirmation process.

Also applies to: 54-54, 60-60


73-73: LGTM! Well-structured rate limit exception.

Good separation of metadata and extension data, with proper localization and rate limit information.


79-79: LGTM! Consistent error context.

Maintains consistency in error context enrichment throughout the file.

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.ResetPassword.cs (4)

18-18: LGTM! Enhanced exception with request context.

The addition of request data to the exception provides valuable debugging context while maintaining security by not exposing internal user data.


71-71: LGTM! Comprehensive exception context for password reset scenarios.

The enhanced exceptions provide excellent context for debugging while maintaining security:

  • Request data for user not found
  • User ID for expired tokens
  • User ID and humanized retry timing for locked accounts

Also applies to: 76-76, 80-82


95-95: LGTM! Enhanced validation exception with user context.

Adding user ID to validation exceptions helps correlate validation failures with specific users.


101-101: LGTM! Enhanced update result exception with user context.

Adding user ID to update result exceptions maintains consistency with other exception enhancements.

src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/appsettings.json (7)

10-11: Setting ExceptionHandlerMiddleware LogLevel Globally
The addition of "Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware": "None" under the global "Logging.LogLevel" section aligns with the PR’s objective by reducing logging noise from exception middleware. Confirm that suppressing these logs does not interfere with any critical diagnostic data required in production.


17-18: ApplicationInsights Logging Configuration Updated
Under the "ApplicationInsights" logging section, explicitly setting "Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware": "None" ensures consistent log filtering across providers that are conditional on the appInsights build flag.


36-38: Sentry Log Level Adjustment
The Sentry logger configuration now includes "Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware": "None", which helps reduce redundant exception logs in Sentry. Please verify that this suppression does not prevent Sentry from capturing any exceptions that are critical for monitoring and alerting.


45-46: Console Logging Configuration Updated
Within the "Console" logger configuration, the change to set "Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware": "None" is consistent with other configurations and should help keep console output focused by filtering out middleware exception logs.


58-59: EventLog Logger Configuration Updated
The EventLog logging section now explicitly sets the log level for "Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware" to "None". This update is in line with the overall goal of reducing excessive logging from exception middleware across all providers.


65-66: EventSource Logger Configuration Updated
Similarly, the "EventSource" logger configuration now includes the property to disable logs from exception middleware. This helps to achieve a consistent log filtering strategy across different logging systems.


74-75: DiagnosticLogger Configuration Update
By adding "Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware": "None" under the "DiagnosticLogger" section, the file ensures that verbose middleware exception logs are suppressed, thereby streamlining diagnostic outputs for easier analysis.

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Services/ServerExceptionHandler.cs (2)

16-18: Clarify use of a static appSessionId.
A static Guid set at application start might suffice for single-tenant scenarios. However, in multi-tenant or scaled-out environments, this could be misleading.


41-75: Monitor for key collisions in combined data dictionaries.
This block merges environment, request, and default data into a single dictionary. If keys overlap, their values may be overwritten. Confirm this behavior is intended. Also, be cautious about storing potentially sensitive or personal data.

src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Extensions/ExceptionExtensions.cs (1)

22-28: Validate data keys to avoid accidental collisions.
When adding single key-value pairs, ensure the same collision handling strategy as the bulk-insertion method. Otherwise, repeated calls with the same key could raise an exception or overwrite data unexpectedly.

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Extensions/KnownExceptionExtensions.cs (1)

23-33: Validate potential overwrites when storing custom extension data.
The extension data dictionary keys are replaced if they already exist. Confirm this behavior aligns with your business requirements. If partial merges are desired, add a collision check.

src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/Identity/IdentityRequestDto.cs (1)

32-35: LGTM! Well-structured ToString() implementation.

The prioritization order (Email > PhoneNumber > UserName) makes sense, and the implementation is concise using null-coalescing operators.

src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/AppJsonContext.cs (1)

25-25: LGTM! TimeSpan serialization support added.

The addition aligns with the existing pattern and supports the new exception extension data feature.

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Services/PhoneService.cs (2)

44-44: LGTM! Centralized exception handling.

Using ServerExceptionHandler improves consistency in error handling across the application.


57-57: LGTM! Enhanced error context.

Adding error code as extension data improves error diagnostics.

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/ClientExceptionHandlerBase.cs (1)

28-35: Great enhancement to exception context!

The addition of exception data to parameters enriches the logging context, making it easier to diagnose issues by capturing all relevant exception metadata.

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.EmailConfirmation.cs (1)

17-17: Excellent enhancement to exception context!

The consistent addition of contextual data (user IDs, email addresses, and retry times) to exceptions significantly improves debugging and troubleshooting capabilities. This implementation:

  • Makes it easier to track user-specific issues
  • Provides clear retry timing information
  • Maintains consistency across different exception types

Also applies to: 20-20, 29-29, 34-34, 38-40, 47-47, 74-74

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/HttpMessageHandlers/ExceptionDelegatingHandler.cs (1)

59-62: Excellent preservation of server-side exception context!

The addition ensures that all extension data from the server's problem details is preserved in the client-side exception, maintaining the rich context throughout the error handling chain.

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Services/PushNotificationService.cs (2)

82-82: Good move towards centralized exception handling!

The switch from direct logging to using ServerExceptionHandler ensures consistent exception handling across services.


121-122: Great addition of push notification context!

Adding the UserRelatedPush flag to the exception data helps distinguish between different types of push notification failures, making it easier to monitor and debug user-specific issues.

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Configurations/Product/ProductConfiguration.cs (3)

17-17:

Details

❓ Verification inconclusive

Verify the property rename impact.

The configuration has been updated to use ShortId instead of Number with the "ProductShortId" sequence. This suggests a property rename that might require a database migration.

Run the following script to verify the property rename impact:


🏁 Script executed:

#!/bin/bash
# Description: Check for any remaining references to the old property name.

# Test: Search for any remaining references to the 'Number' property.
rg -A 5 'Product.*Number'

# Test: Search for any migration files that might handle this rename.
fd -e cs -e sql migration

Length of output: 818


Verify the Property Rename Impact in Database Migration

After running the verification scripts, no remaining references to the old "Number" property were found in the codebase. The configuration now correctly maps to ShortId with the "ProductShortId" sequence. Additionally, migration files (including the one at src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Migrations/20250217191441_InitialMigration.cs) are present, which should include the changes for this property update.

Please double-check the migration file(s) to ensure that the column is renamed appropriately in the database schema.


17-17:

Details

✅ Verification successful

LGTM! Verify sequence usage in the database.

The sequence configuration has been correctly updated to use the ShortId property, which has a unique index. This change ensures proper ID generation for products.

Run the following script to verify the sequence usage:


🏁 Script executed:

#!/bin/bash
# Description: Check for any remaining references to the old property name in sequence configurations.

# Test: Search for any remaining references to 'Number' property in sequence configurations.
rg -A 5 $'UseSequence.*Number'

# Test: Verify that ShortId is used consistently in other configurations.
rg -A 5 $'UseSequence.*ShortId'

Length of output: 1058


Sequence configuration verified — no remaining issues.

The updated code in src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Configurations/Product/ProductConfiguration.cs now uses the ShortId property with UseSequence("ProductShortId") correctly. The verification script confirmed that there are no references to the old “Number” property, and the ShortId configuration is consistent.


17-17:

Details

❓ Verification inconclusive

Verify the sequence change impact.

The sequence "ProductShortId" is now used for ShortId instead of Number. This change could affect existing data and database migrations.

Please run the following script to check for potential conflicts or issues:


🏁 Script executed:

#!/bin/bash
# Description: Check for usage of Product.Number and existing migrations

# Check for references to Product.Number
rg -A 5 "Product\.Number"

# Check for existing migrations that might be affected
fd -e cs -p ".*Migration.*" -x cat {} \; | rg -A 10 -B 10 "ProductShortId|Product.*Number"

Length of output: 123


Action Required: Manually Verify the Impact of the Sequence Change

The update now uses the sequence "ProductShortId" for ShortId instead of what was previously implied by Number. Although our automated searches for references to Product.Number and for migration files mentioning either ProductShortId or Product.*Number produced no output, the absence of evidence from these scripts isn’t conclusive. Please manually verify that:

  • There are no lingering references in the code or migration files to the old Product.Number or its associated sequence.
  • The database migrations (if any) that manage sequence changes will handle the transition safely without data conflicts.

Location:
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Configurations/Product/ProductConfiguration.cs (line 17)

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Program.Services.cs (3)

93-94: LGTM! Clean service registration.

The service registration has been simplified while maintaining the interface contract. This change supports the centralized exception handling strategy.


93-94: LGTM! Improved service registration for better flexibility.

The changes improve the service registration by:

  1. Registering ServerExceptionHandler as itself first
  2. Then registering it as IProblemDetailsWriter through a cast
    This allows the handler to be injected both as ServerExceptionHandler and IProblemDetailsWriter, providing more flexibility in usage.

93-94: LGTM! Good improvement in service registration.

The change improves service registration by:

  1. Registering ServerExceptionHandler directly as a singleton
  2. Registering it as IProblemDetailsWriter through type casting

This approach provides better flexibility while maintaining the required interface implementation.

src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/appsettings.Development.json (1)

7-8: Consistent logging configuration across providers!

The changes establish uniform logging levels across different providers by:

  1. Setting consistent log level "Warning" for HttpClient LogicalHandler
  2. Disabling logs for DeveloperExceptionPageMiddleware and ExceptionHandlerMiddleware

This aligns with the PR's goal of improving exception handling by ensuring middleware exceptions are handled by the custom exception handler instead.

Also applies to: 15-16, 33-34, 42-43, 58-59, 66-67, 74-76

.github/workflows/admin-sample.cd.yml (1)

209-209: Improved Windows build optimization!

The changes enhance the Windows build process by:

  1. Targeting 64-bit architecture (win-x64) instead of 32-bit
  2. Enabling ReadyToRun compilation for better startup performance
  3. Updating the VPK packaging command to match the new architecture

These optimizations will improve application performance and compatibility with modern systems.

Also applies to: 211-211

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Services/EmailService.cs (1)

140-141: LGTM! Improved error handling with enriched context.

The changes enhance error handling by:

  1. Using the centralized ServerExceptionHandler
  2. Including relevant email context (subject and recipient) in the exception data

Also applies to: 157-158

@msynk msynk merged commit 1e40112 into bitfoundation:develop Feb 18, 2025
19 checks passed
@yasmoradi yasmoradi deleted the release branch February 18, 2025 12:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Boilerplate server exception handler must enrich error logs

2 participants