Error boundary
CustomErrorBoundary is an ErrorBoundary that logs what it catches with a correlation id and shows the user something they can act on. Hosts typically wrap all content in it once, from MainLayout, so whatever it decides applies app-wide.
@* MainLayout.razor *@
<CustomErrorBoundary>
<ChildContent>@Body</ChildContent>
</CustomErrorBoundary>
What the user sees
The boundary renders one of three ways, in this order.
1. Your own ErrorContent, if you supply it. It replaces the panel entirely — the boundary adds no heading of its own above it.
<CustomErrorBoundary>
<ChildContent>@Body</ChildContent>
<ErrorContent Context="exception">
<MyErrorPanel Exception="@exception" />
</ErrorContent>
</CustomErrorBoundary>
2. An access-denied panel, for UnauthorizedAccessException. A permission failure is an expected outcome, not a crash, so it gets a compact panel carrying the exception's own message — no "Something went wrong!", no stack trace, no correlation id — and is logged at Warning rather than Error.
<div class="access-denied-content">
<h3>Access denied</h3>
<p>You do not have access to this team.</p>
<button class="btn btn-primary">Try again</button>
</div>
Throw UnauthorizedAccessException from your authorization layer and this happens app-wide with no per-page code. The message is shown to the user verbatim, so write it for them.
3. The crash panel, for everything else. Heading, the correlation id the failure was logged under with a copy button, and a recovery button. Exception details appear only if you allow them — see below.
Stack traces are off by default
BlazorOptions.ShowExceptionDetails controls whether the crash panel renders the exception message and stack trace. Unset means off, so a production user is never shown a stack trace.
Turn it on for development from the host environment:
builder.Services.AddThargaBlazor(o => o.ShowExceptionDetails = builder.Environment.IsDevelopment());
Or per environment, in appsettings.Development.json, with the configuration overload:
{
"Tharga": {
"Blazor": {
"ShowExceptionDetails": true
}
}
}
The setting has no effect on the access-denied panel, which never renders a stack trace.
Why you have to say. The library cannot work this out for itself. It holds no ASP.NET Core hosting reference, and neither IWebHostEnvironment nor IHostEnvironment is registered on Blazor WebAssembly, which uses IWebAssemblyHostEnvironment instead. A library that guessed would silently answer "not development" on every WebAssembly host. The host always knows, so the host decides.
Logging
Every caught exception gets a fresh CorrelationId, attached to the exception's Data and included in the log scope, so the id on screen matches the entry in your log store.
| Exception | Level |
|---|---|
UnauthorizedAccessException |
Warning |
| everything else | Error |
Styling
The boundary ships no CSS. It emits error-content, dev-error-details and access-denied-content for you to style — the access-denied class is separate precisely so a permission notice need not look like a failure.
Parameters
| Parameter | Type | Description |
|---|---|---|
ChildContent |
RenderFragment |
Content the boundary protects. |
ErrorContent |
RenderFragment<Exception> |
Replaces the built-in panels entirely when supplied. |
MaximumErrorCount |
int |
Inherited from ErrorBoundary. How many errors are tolerated before the boundary stops recovering. |