Logging to elmah.io from Blazor
Blazor Web App
.NET 8 introduced a new project template for Blazor applications, called Blazor Web App (briefly known as Blazor United during preview), now the default template for new Blazor projects. It splits into two projects: a Server project, running the Static Server and Interactive Server render modes, and a Client project compiled to WebAssembly, running the Interactive WebAssembly and Interactive Auto render modes (Auto starts on the server, then switches to WebAssembly once downloaded).
Since these are two separate projects, install a different elmah.io package in each, matching the sections below:
- In the Server project, install
Elmah.Io.Extensions.Logging(and optionallyElmah.Io.AspNetCore.ExtensionsLogging). - In the Client project, install
Elmah.Io.Blazor.Wasm.
Both packages can be installed and configured at the same time, since they live in different projects. Doing so logs uncaught exceptions to elmah.io no matter which render mode a component uses. A full example combining both is available in the Elmah.Io.Blazor.Wasm samples on GitHub.
Blazor Server App
To start logging to elmah.io from a Blazor Server App, install the Elmah.Io.Extensions.Logging NuGet package:
dotnet add package Elmah.Io.Extensions.Logging
Install-Package Elmah.Io.Extensions.Logging
<PackageReference Include="Elmah.Io.Extensions.Logging" Version="5.*" />
paket add Elmah.Io.Extensions.Logging
In the Program.cs file, add elmah.io logging configuration:
builder.Logging.AddElmahIo(options =>
{
options.ApiKey = "API_KEY";
options.LogId = new Guid("LOG_ID");
});
Replace API_KEY with your API key (Where is my API key?) and LOG_ID with the ID of the log you want messages sent to (Where is my log ID?). The package can be configured through settings if you prefer. Check out appsettings.json configuration for details.
All uncaught exceptions are automatically logged to elmah.io. Exceptions can be logged manually, by injecting an ILogger into your view and adding try/catch:
@using Microsoft.Extensions.Logging
@inject ILogger<FetchData> logger
<!-- ... -->
@functions {
WeatherForecast[] forecasts;
protected override async Task OnInitAsync()
{
try
{
forecasts = await Http
.GetJsonAsync<WeatherForecast[]>("api/SampleData/WeatherForecasts-nonexisting");
}
catch (Exception e)
{
logger.LogError(e, e.Message);
}
}
}
Information and other severities can be logged as well:
@using Microsoft.Extensions.Logging
@inject ILogger<Counter> logger
<!-- ... -->
@functions {
int currentCount = 0;
void IncrementCount()
{
currentCount++;
logger.LogInformation("Incremented count to {currentCount}", currentCount);
}
}
Include details from the HTTP context
Microsoft.Extensions.Logging doesn't know that it is running inside a web server. That is why Elmah.Io.Extensions.Logging doesn't include HTTP contextual information like URL and status code as default. To do so, install the Elmah.Io.AspNetCore.ExtensionsLogging NuGet package:
dotnet add package Elmah.Io.AspNetCore.ExtensionsLogging
Install-Package Elmah.Io.AspNetCore.ExtensionsLogging
<PackageReference Include="Elmah.Io.AspNetCore.ExtensionsLogging" Version="5.*" />
paket add Elmah.Io.AspNetCore.ExtensionsLogging
And add the following code to the Program.cs file:
app.UseElmahIoExtensionsLogging();
Make sure to call this method just before the call to UseRouting and UseEndpoints. This will include some of the information you are looking for.
There's a problem when running Blazor Server where you will see some of the URLs logged as part of errors on elmah.io having the value /_blazor. This is because Blazor doesn't work like traditional websites where the client requests the server and returns an HTML or JSON response. When navigating the UI, parts of the UI are loaded through SignalR, which causes the URL to be /_blazor. Unfortunately, we haven't found a good way to fix this globally. You can include the current URL on manual log statements by injecting a NavigationManager in the top of your .razor file:
@inject NavigationManager navigationManager
Then wrap your logging code in a new scope:
Uri.TryCreate(navigationManager.Uri, UriKind.Absolute, out Uri url);
using (Logger.BeginScope(new Dictionary<string, object>
{
{ "url", url.AbsolutePath }
}))
{
logger.LogError(exception, "An error happened");
}
The code uses the current URL from the injected NavigationManager object.
Blazor WebAssembly App (wasm)
To start logging to elmah.io from a Blazor Wasm App, install the Elmah.Io.Blazor.Wasm NuGet package:
dotnet add package Elmah.Io.Blazor.Wasm
Install-Package Elmah.Io.Blazor.Wasm
<PackageReference Include="Elmah.Io.Blazor.Wasm" Version="4.*" />
paket add Elmah.Io.Blazor.Wasm
In the Program.cs file, add elmah.io logging configuration:
builder.Logging.AddElmahIo(options =>
{
options.ApiKey = "API_KEY";
options.LogId = new Guid("LOG_ID");
});
Replace API_KEY with your API key (Where is my API key?) and LOG_ID with the ID of the log you want messages sent to (Where is my log ID?).
All uncaught exceptions are automatically logged to elmah.io after calling AddElmahIo. Errors and other severities can be logged manually, by injecting an ILogger into your view and adding try/catch or by implementing error boundaries:
@page "/"
@inject ILogger<Index> logger
@code {
protected override void OnInitialized()
{
logger.LogInformation("Initializing index view");
try
{
object text = "Text";
var cast = (int)text;
}
catch (InvalidCastException e)
{
logger.LogError(e, "An error happened");
}
}
}
The following may be implemented by the package later:
- Additional information about the HTTP context (like cookies, URL, and user).
- Internal message queue and/or batch processing like
Microsoft.Extensions.Logging. - Support for logging scopes.
Configuration in appsettings.json
Blazor WebAssembly doesn't provide an appsettings.json file as part of the default template. To add one, create a new file named appsettings.json in the wwwroot directory. Make sure to set Build Action to Content and Copy to Output Directory to Copy if Newer. In the file, add the following content:
{
"ElmahIo": {
"ApiKey": "API_KEY",
"LogId": "LOG_ID"
}
}
As before, API_KEY and LOG_ID should be replaced with real values. In the Program.cs file you can load the config and set up Elmah.Io.Blazor.Wasm using the overloaded AddElmahIo method:
builder.Services.Configure<ElmahIoBlazorOptions>(builder.Configuration.GetSection("ElmahIo"));
builder.Logging.AddElmahIo();
Note
The AddElmahIo mehtod without parameters was introduced in Elmah.Io.Blazor.Wasm v5 package. For earlier versions, provide empty options like this: builder.Logging.AddElmahIo(options => {});
This article was brought to you by the elmah.io team. elmah.io is the best error management system for .NET web applications. We monitor your website, alert you when errors start happening, and help you fix errors fast.
See how we can help you monitor your website for crashes Monitor your website