Blazor

To monitor Blazor applications, we will add both Raygun4NET which provides C#/Razor error monitoring and Raygun4JS which is a JavaScript library that will handle client side javascript error monitoring.


The best way to install Raygun is to use use the dotnet cli tool.

  1. In your Blazor Server project folder run dotnet add package Mindscape.Raygun4Net.AspNetCore to install Raygun.
  2. In your Blazor Client project folder run dotnet add package Mindscape.Raygun4Net.NetCore to install Raygun.

Alternatively, visit https://www.nuget.org/packages/Mindscape.Raygun4Net.AspNetCore/ and https://www.nuget.org/packages/Mindscape.Raygun4Net.NetCore/ for instructions on installation using the package manager console.


Add the following code to your appsettings.json (if you're using another type of config, add it there):


 "RaygunSettings": {
   "ApiKey": "YOUR_APP_API_KEY"
 }
 

Your app API key is displayed when you create a new application in your Raygun account, or can be viewed in the application settings. RaygunSettings has many options which are explained further down this page.


Configure the RaygunAspNetCore Middleware to handle exceptions that have been triggered; and send unhandled exceptions automatically.

In Program.cs:

  1. Add using Mindscape.Raygun4Net.AspNetCore; to your using statements.
  2. Add builder.Services.AddRaygun(builder.Configuration); .
  3. Add app.UseRaygun(); after any other ExceptionHandling methods e.g. app.UseDeveloperExceptionPage() or app.UseExceptionHandler("/Home/Error").
using Mindscape.Raygun4Net.AspNetCore;
using Mindscape.Raygun4Net.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRaygun(builder.Configuration);
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseWebAssemblyDebugging();
}
else
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseRaygun();
app.UseHttpsRedirection();

app.UseBlazorFrameworkFiles();
app.UseStaticFiles();

app.UseRouting();


app.MapRazorPages();
app.MapControllers();
app.MapFallbackToFile("index.html");

app.Run();

The above set up, will capture unhandled exceptions in your application code; and send them to Raygun. (For errors thrown inside Razor components, see the next section)

Unhandled exceptions which occur during the Blazor circuit will cause a fatal error in your application. For this reason, you'll need to manually catch exceptions that occur in code inside your Razor components.

We recommend following the Blazor fundamentals documentation on global exception handling:

Create a new <Error> component.

Shared/Error.razor:

@using Mindscape.Raygun4Net
@inject IConfiguration Configuration

<CascadingValue Value="this">
    @ChildContent
</CascadingValue>

@code {

    [Parameter]
    public RenderFragment ChildContent { get; set; } = null!;

    RaygunClient Raygun => new RaygunClient(Configuration["RaygunSettings:ApiKey"]);

    public void ProcessError(Exception ex)
    {
        Raygun.SendInBackground(ex);
    }
}

Wrap the <Router> component in the new <Error> component

/App.razor:

<Error>
    <Router ...>
        ...
    </Router>
</Error>

Once this is setup you catch exceptions in your components, and send it to Raygun.

Pages/SomePage.razor:

@page "/SomePage"

<PageTitle>SomePage</PageTitle>

<h1>SomePage</h1>

<button class="btn btn-primary" @onclick="OnClick">Click me</button>

@code {

    [CascadingParameter]
    public Error Error { get; set; } = null!;

    private void OnClick()
    {
        try
        {
           // ... Your code
        }
        catch (Exception e)
        {
            Error.ProcessError(e);
            throw;
        }
    }
}

For more details about the Raygun4Net provider and additional documentation about this provider and configuration options that can be specified, please see the documentation for the ASP.NET Core provider.


In wwwroot/index.html add this snippet to your markup immediately before the closing </head> tag:

<script type="text/javascript">
  !function(a,b,c,d,e,f,g,h){a.RaygunObject=e,a[e]=a[e]||function(){
  (a[e].o=a[e].o||[]).push(arguments)},f=b.createElement(c),g=b.getElementsByTagName(c)[0],
  f.async=1,f.src=d,g.parentNode.insertBefore(f,g),h=a.onerror,a.onerror=function(b,c,d,f,g){
  h&&h(b,c,d,f,g),g||(g=new Error(b)),a[e].q=a[e].q||[],a[e].q.push({
  e:g})}}(window,document,"script","//cdn.raygun.io/raygun4js/raygun.min.js","rg4js");
</script>

This will fetch the Raygun4JS script from our CDN asynchronously so it doesn't block the page load.


Paste this at the bottom of the <body> section in Pages/_Host, just below the line: <script src="_framework/blazor.webassembly.js"></script>

<script type="text/javascript">
  rg4js('apiKey', 'paste_your_api_key_here');
  rg4js('trackEvent', {  type: 'pageView', path: window.location.pathname});
  rg4js('enableCrashReporting', true);
  rg4js('enableRUM', true); <!-- optional, enable RealUserMonitoring -->
  window.rg4js = rg4js;     <!-- This is needed to connect Raygun4JS with Blazor callbacks -->
</script>

For more details about the Raygun4JS provider and additional documentation about this provider and configuration options that can be specified, please see the documentation for the JavaScript provider.


Setup server side user tracking by setting the following information against the active RaygunClient instance.

raygunClient.UserInfo = new RaygunIdentifierMessage("users_email_address@domain.com")
{
  IsAnonymous = false,
  FullName = "Firstname Lastname",
  FirstName = "Firstname"
};

Setup client side user tracking by adding the following information to the script block at the bottom of the page in Pages/_Host.

rg4js('setUser', {
  identifier: 'users_email_address_or_unique_id',
  isAnonymous: false,
  email: 'users_email_address@domain.com',
  firstName: 'Firstname',
  fullName: 'Firstname Lastname'
});

Alternatively, this can be provided from a server rendered code section by using a JavaScript invoke call:

var userData = new
{
  Identifier = "users_email_address_or_unique_id",
  IsAnonymous = false,
  Email = "users_email_address@domain.com",
  FirstName = "Firstname",
  FullName = "Firstname Lastname"
};

await JSRuntime.InvokeVoidAsync("rg4js", "setUser", userData);

These providers are open source and are available from the Raygun4Net repository and the Raygun4JS repository