In enterprise-grade applications built with Blazor Server, ensuring stability is critical. A single unhandled error can disrupt the persistent SignalR connection, crash the UI, or even terminate user sessions.
That’s why Blazor error handling isn’t just optional—it’s essential.
This blog outlines robust strategies for global error handling in Blazor, how to isolate errors at the component level, and how to build centralized services for error logging and user feedback.
Whether you’re developing admin dashboards, real-time financial apps, or enterprise portals, these practices will keep your Blazor app running smoothly.
Why Blazor Error Handling Matters?
Blazor Server apps rely on a real-time, two-way connection between the browser and the server using SignalR.
This architecture introduces unique challenges:
- Any Blazor Server exception can break the connection.
- Silent failures lead to poor UX or data loss.
- A small component crash may freeze the entire page.
Implementing Blazor error handling ensures a resilient, fault-tolerant experience for your users.
Common Blazor Error Handling Mistakes
- Unhandled Exceptions in Lifecycle Methods
Lifecycle events like OnInitializedAsync() often run async logic that can fail silently.
- Misusing async void
Using async void methods prevents proper exception capture.
- No User Feedback or Logging
Exceptions may occur without notifying users or being logged—making debugging difficult.
- No Centralized Logging System
Logs scattered across components lack consistency and become hard to track.
Global Error Handling in Blazor Server
1. Use ErrorBoundary in App.razor
Wrap your routing component with Blazor’s built-in ErrorBoundary to catch unhandled component errors globally.
razor
CopyEdit
<ErrorBoundary>
<Router AppAssembly=”@typeof(App).Assembly” />
</ErrorBoundary>
2. Custom ErrorBoundary with Recovery
Enable user-triggered recovery after an error:
razor
CopyEdit
<ErrorBoundary @ref=”errorBoundary”>
<ChildContent>
@Body
</ChildContent>
</ErrorBoundary>
@code {
private ErrorBoundary? errorBoundary;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
errorBoundary?.Recover();
}
}
}
3. Centralized Logging with Serilog or ILogger
Use structured logging to track all Blazor exceptions consistently:
csharp
CopyEdit
try
{
var result = await _service.GetDataAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, “Error fetching data in DashboardComponent”);
throw;
}
4. Real-World Example: Financial Dashboard
In an enterprise dashboard for tracking stock data:
- Log backend errors.
- Show UI toasts like “Unable to load data.”
- Avoid disconnections and freeze states with graceful fallbacks.
Component-Level Error Handling in Blazor
Blazor’s component-based architecture requires fault isolation. A bug in one component shouldn’t affect the whole page.
1. Wrap Components in ErrorBoundary
razor
CopyEdit
<ErrorBoundary>
<MyReportComponent />
</ErrorBoundary>
2. Add Custom Error UI and Retry Options
razor
CopyEdit
<ErrorBoundary>
<ChildContent>
<SensitiveComponent />
</ChildContent>
<ErrorContent>
<p class=”text-danger”>Oops! Something went wrong. Try again.</p>
</ErrorContent>
</ErrorBoundary>
<button @onclick=”RecoverComponent”>Try Again</button>
@code {
private ErrorBoundary? boundary;
private void RecoverComponent()
{
boundary?.Recover();
}
}
3. Show Toast or Alert for User Feedback
razor
CopyEdit
@if (hasError)
{
<div class=”alert alert-danger”>Unable to load data</div>
}
@code {
private bool hasError = false;
protected override async Task OnInitializedAsync()
{
try
{
await LoadSensitiveData();
}
catch (Exception ex)
{
_logger.LogError(ex, “Error in SensitiveComponent”);
hasError = true;
}
}
}
Centralized Error Handling Service in Blazor
For large-scale applications, managing errors in each component becomes chaotic. A centralized error service streamlines everything.
1. Define the Service
csharp
CopyEdit
public interface IErrorService
{
void HandleError(Exception ex, string context);
event Action<string>? OnError;
}
public class ErrorService : IErrorService
{
public event Action<string>? OnError;
public void HandleError(Exception ex, string context)
{
Console.WriteLine($”Error in {context}: {ex.Message}”);
OnError?.Invoke($”An error occurred: {ex.Message}”);
}
}
2. Register the Service
csharp
CopyEdit
builder.Services.AddSingleton<IErrorService, ErrorService>();
3. Inject and Use in Components
razor
CopyEdit
@inject IErrorService ErrorService
@code {
protected override async Task OnInitializedAsync()
{
try
{
await DoSomethingAsync();
}
catch (Exception ex)
{
ErrorService.HandleError(ex, “MyComponent”);
}
}
}
4. Display Centralized Error Message in UI
razor
CopyEdit
@inject IErrorService ErrorService
@if (!string.IsNullOrEmpty(latestError))
{
<div class=”alert alert-danger”>@latestError</div>
}
@code {
private string? latestError;
protected override void OnInitialized()
{
ErrorService.OnError += msg =>
{
latestError = msg;
StateHasChanged();
};
}
}
Best Practices for Blazor Error Handling
- Always wrap async methods with try-catch.
- Never use async void.
- Use ILogger<T> or structured logging tools like Serilog.
- Show meaningful error messages to users (alerts, toasts, retries).
- Wrap individual components with ErrorBoundary.
- Leverage a centralized error handling service for better maintainability.
Final Thoughts
Implementing effective Blazor error handling ensures your application is robust, scalable, and user-friendly. From global strategies using ErrorBoundary, to building centralized services for error logging, these practices provide enterprise-grade stability.
Whether you’re building complex dashboards, business portals, or internal tools—error management should be at the core of your development strategy.
Additional Resources: