How can I log an error, no matter where it is called from?

David Thielen 3,121 Reputation points
2024-09-27T16:28:27.32+00:00

Hi;

In my MainLayout.razor I have set up:

<ErrorBoundary>
    <ChildContent>
        <!-- lots of nodes -->
    </ChildContent>
    <ErrorContent Context="error">
        <main class="page--error">
            <div class="main-content">
                @{
                    var guid = Guid.NewGuid().ToString();
                    Logger.LogError(error, $"{error.GetType().Name}: {guid}");
                }
                <h1>Unexpected Error (sorry)</h1>
                <p>
                    The program has encountered an unexpected error (yes there are expected errors). This error has been
                    logged and we will look at it.
                </p>
            </div>
        </main>
    </ErrorContent>
</ErrorBoundary>

And I am able to log these with no problem (all good).

And in Error.cshtml I have:

public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    _logger.LogError($"HttpContext ERROR - RequestId: {RequestId}");
}

Question 1: How can I get more information here? I have no idea what the RequestId is. And what I really want is the call stack that generated the error.

I also have found that in some cases, when rendering a page, neither of the above is called.

Question 2: How do I log these swallowed render exceptions? And any other unhandled exceptions?

thanks - dave

Blazor
Blazor
A free and open-source web framework that enables developers to create web apps using C# and HTML being developed by Microsoft.
1,594 questions
{count} votes

Accepted answer
  1. youzeliang 735 Reputation points
    2024-09-27T16:38:57.0733333+00:00

    In Blazor, handling and logging unhandled exceptions during rendering or in general can sometimes be tricky, but it can be achieved with some adjustments.

    Question 1: How to get more information (e.g., call stack)?

    In your Error.cshtml, you’re only logging the RequestId, but if you want to log more detailed information like the call stack, you need to log the full Exception details. In the OnGet() method, you can capture the exception and log the call stack directly. Here’s an example:

    public void OnGet()

    {

    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    
    
    
    // Assuming you want to log the exception
    
    var exceptionHandlerFeature = HttpContext.Features.Get<IExceptionHandlerFeature>();
    
    
    
    if (exceptionHandlerFeature != null)
    
    {
    
        var exception = exceptionHandlerFeature.Error;
    
        _logger.LogError(exception, $"HttpContext ERROR - RequestId: {RequestId}, StackTrace: {exception.StackTrace}");
    
    }
    
    else
    
    {
    
        _logger.LogError($"HttpContext ERROR - RequestId: {RequestId}");
    
    }
    

    }

    •	This uses the IExceptionHandlerFeature to get the exception and then logs the exception message and stack trace.
    
    •	Make sure that in your middleware pipeline (Startup.cs or Program.cs), you are using UseExceptionHandler() to enable error handling middleware that will catch exceptions for HttpContext.
    

    Question 2: Logging swallowed render exceptions

    Blazor sometimes swallows rendering exceptions silently, especially if they happen during asynchronous operations. However, you can capture and log these exceptions by setting up global exception handling.

    Here’s how you can do that:

    1.	Catching Unhandled Exceptions in Blazor’s Rendering Process:
    

    You can override the default exception handling in Blazor by subscribing to the AppDomain.UnhandledException and TaskScheduler.UnobservedTaskException events. This will help catch and log any unhandled exceptions that may be swallowed during rendering.

    Add the following code in your Program.cs:

    using Microsoft.AspNetCore.Components.WebAssembly.Hosting;

    using System.Threading.Tasks;

    var builder = WebAssemblyHostBuilder.CreateDefault(args);

    // Your usual setup...

    // builder.RootComponents.Add<App>("#app");

    var host = builder.Build();

    // Global exception handling

    AppDomain.CurrentDomain.UnhandledException += (sender, eventArgs) =>

    {

    var exception = eventArgs.ExceptionObject as Exception;
    
    Console.Error.WriteLine($"Unhandled exception: {exception?.Message}");
    
    // You can also log this to your logging service here
    

    };

    TaskScheduler.UnobservedTaskException += (sender, eventArgs) =>

    {

    var exception = eventArgs.Exception;
    
    Console.Error.WriteLine($"Unobserved task exception: {exception?.Message}");
    
    // You can also log this to your logging service here
    

    };

    await host.RunAsync();

    2.	Using ErrorBoundary in Blazor:
    

    You already have ErrorBoundary in place, but for some exceptions that don’t make it to the boundary (like those in asynchronous tasks), the previous step ensures you log them.

    3.	Handling and Logging Rendering Exceptions:
    

    Sometimes rendering exceptions are

    If my answer is helpful to you, you can adopt it, thank you!

    1 person found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.