.NET Core 6+

For instructions on Web Applications running on .NET 6+, please see:

Installation

Install the Mindscape.Raygun4Net.NetCore NuGet package into your project. You can either use the below dotnet CLI command, or the NuGet management GUI in the IDE you use.

dotnet add package Mindscape.Raygun4Net.NetCore

NuGet documentation for the Mindscape.Raygun4Net.NetCore package can be found here.


Create an instance of RaygunClient by passing it a RaygunSettings object with your app API key. Optionally, you can also set CatchUnhandledExceptions to true to automatically catch and log all unhandled exceptions in your application.

Note: Your app API key is displayed when you create a new application in your Raygun account, or can be viewed in the application settings.

using Mindscape.Raygun4Net;
private static RaygunClient _raygunClient = new RaygunClient(new RaygunSettings()
{
  ApiKey = "paste_your_api_key_here",
  CatchUnhandledExceptions = true // Enable to log all unhandled exceptions
});

Deploy Raygun into your production environment for best results, or raise a test exception like the example below. Once we detect your first error event, the Raygun app will automatically update.

try
{
  throw new Exception("Temporary example exception to send to Raygun");
}
catch (Exception ex)
{
  _raygunClient.SendInBackground(ex);
}

The above instructions will setup Raygun4Net to automatically detect and send all unhandled exceptions. Sometimes you may want to send exceptions manually, such as handled exceptions from within a try/catch block.

RaygunClient provides Send and SendInBackground methods for manually sending to Raygun. It's important to note that SendInBackground should only be used for handled exceptions, rather than exceptions that will cause the application to crash - otherwise the application will most likely shutdown all threads before Raygun is able to finish sending. Both the Send and SendInBackground methods have many overloads for sending additional data which are explained in the various feature sections below.

Here's an example of manually sending exceptions from a try/catch block:

try
{
  // Do something here that might go wrong
}
catch (Exception e)
{
  _raygunClient.SendInBackground(e);
}

Sometimes you may have code that detects that something has gone wrong, but doesn't actually throw an exception. If you want to log this to Raygun, it is tempting to just create a new exception instance and pass it through one of the RaygunClient send methods. Note however that a .NET exception needs to be thrown in order for its stack trace to be populated. So whenever you want to send a new exception instance to Raygun, make sure you are throwing the exception, then catch and send it from within a try/catch block as in the code example above. This will ensure that you log the stack trace which is useful for you to debug, and is used by Raygun to group exceptions.


On a RaygunClient instance, attach an event handler to the SendingMessage event. This event handler will be called just before the RaygunClient sends an exception report - either automatically or manually. The event arguments provide the RaygunMessage object that is about to be sent. There are two different uses for this event handler:

  • Modify the message. You can make any changes you want to the RaygunMessage object such as removing, adding or changing values. Any changes that you make will affect the exception report that gets sent to Raygun.
  • Cancel the message. Sometimes you may get exceptions from parts of the application that you have no control over (such as 3rd party libraries) or due to issues that cannot be solved. In this event handler, you can look through the properties of the RaygunMessage to determine if the exception is one that you don't care about. If so, you can then set e.Cancel = true to prevent Raygun4Net from sending it.

When exception reports are sent to Raygun, they get grouped using our classification logic. We improve this logic every now and then, but sometimes you may come across scenarios where exceptions reports are grouped together or put into separate groups where you were not expecting. This can be from cases we are not yet handling, scenarios that are specific to your application, or unique grouping preferences you have. Raygun4Net lets you provide your own custom grouping logic before exceptions are sent to Raygun.

To use the custom grouping key feature, start by getting the RaygunClient instance used to send your exception reports and attach an event handler to the CustomGroupingKey event. This event gets fired before the SendingMessage event described in the section above. The event arguments provide both the original Exception object and the RaygunMessage object that is about to be sent. In the event handler, you can use whatever logic you want to build a grouping key (string) for the given exception. When the key is ready, set it to the CustomGroupingKey property of the event arguments. Exceptions that end up with the same key will be grouped together. Grouping keys have a limit of 100 characters.

Unless you have extreme grouping logic that needs to be applied to all exceptions, we recommend that you only apply custom grouping logic to scenarios that we are not handling for you. You can include checks in your event handler for certain types of exceptions for example, and only create a custom grouping key for them. Exceptions that you don't provide a custom grouping key for will be grouped in Raygun using the grouping classifiers we provide.

Here is an example of providing a custom grouping key. This code extends upon the setup instructions detailed above.

public class Program
{
  private static RaygunClient _raygunClient = new RaygunClient("paste_your_api_key_here");

  static void Main(string[] args)
  {
    // Attach the event handler:
    _raygunClient.CustomGroupingKey += RaygunClient_CustomGroupingKey;

    // Proceed with program execution here
  }

  private static void RaygunClient_CustomGroupingKey(object sender, RaygunCustomGroupingKeyEventArgs e)
  {
    // This example simply performs pure message based grouping on basic Exception instances:
    if (e.Message.Details.Error.ClassName.Equals("Exception"))
    {
      string key = e.Exception.Message;
      e.CustomGroupingKey = key;
    }
  }

  private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
  {
    _raygunClient.Send(e.ExceptionObject as Exception);
  }
}

Note that if an exception occurs within your CustomGroupingKey event handler, Raygun4Net will detect this and send the new exception as well as the original exception that was being processed. When processing the new exception, the event handler will not be called again in order to avoid an infinite loop.


Providing user information will allow your Raygun dashboard to display the number of unique users that each error or crash has affected. This is a huge help with prioritising issues to solve those that have the largest impact. You can provide whatever user information that will help you solve issues, but make sure to abide by any privacy policies that your company follows. At the very least, providing a unique guid will allow you to see the number of users that are affected by each error. If available, you could provide an ID that is meaningful to you such as a database ID. This could help you to look up information at your end that aids in solving issues. If you are able to provide a name and contact details, you'd be able to contact customers to let them know that issues they've encountered are being worked on, or have been solved.

To enable this feature you must create your own implementation of the IRaygunUserProvider and add it to the services during configuration using services.AddRaygunUserProvider<MyCustomUserProvider>().

Below is an example user provider that allows you to set the user.

public class ExampleRaygunUserProvider : IRaygunUserProvider
{
    private RaygunIdentifierMessage _currentUser;

    public ExampleRaygunUserProvider()
    {
        _currentUser = new RaygunIdentifierMessage("anonymous") { IsAnonymous = true };
    }

    public void UpdateUser(string userId, string fullName = null, string email = null, bool isAnonymous = false)
    {
        _currentUser = new RaygunIdentifierMessage(userId)
        {
            FullName = fullName,
            Email = email,
            IsAnonymous = isAnonymous
        };
    }

    public override RaygunIdentifierMessage GetUser()
    {
        return _currentUser;
    }
}

This can be registered in the services during configuration like so:

services.AddRaygunUserProvider<ExampleUserProvider>();

note: This behaviour is new since Raygun4Net v10.0.0. The previous User and UserInfo properties are marked as obsolete but are still functioning for now.

Here are all the available RaygunIdentifierMessage properties:

  • Identifier (passed into the constructor) is the unique identifier from your system for this user.
  • IsAnonymous is a flag indicating whether the user is logged in (or identifiable) or if they are anonymous. An anonymous user can still have a unique identifier.
  • Email The user's email address. If you use email addresses to identify your users, feel free to set the identifier to their email and leave this blank. We will use the identifier as the email address if it looks like one, and if no email address is specified in this field.
  • FullName The user's full name.
  • FirstName The user's first (or preferred) name.
  • UUID A device identifier. Could be used to identify users across devices, or machines that are breaking for many users.

Another way to provide the user information is to use one of the Send or SendInBackground overloads which has a RaygunIdentifierMessage as a parameter. The overloads include 'tags' and 'custom data' parameters (see below) which you can set as null if you don't need to use them. This should be used if you only get the user information when a crash occurs, or if the user information is not fixed, or in heavily threaded scenarios where you have a separate RaygunClient instance for each thread.

_raygunClient.SendInBackground(exception, null, null, new RaygunIdentifierMessage("user@email.com") { IsAnonymous = false, FullName = "Robbie Robot", FirstName = "Robbie" });

note: The string properties on a User have a maximum length of 255 characters. Users that have fields that exceed this amount will not be processed.


Portable PDB (Program Database) files in .NET are a modern, cross-platform alternative to traditional Windows PDB files used for debugging. They store debugging information, such as source code line numbers, variable names, and metadata, in a more compact and efficient format. Portable PDBs are designed to work across different operating systems and platforms, making them ideal for cross-platform .NET applications.

You can upload your application's Portable PDB files directly to Raygun. We will automatically detect any stack traces that can be symbolicated using the uploaded PDB's. This process enhances the stack trace information, providing you with more detailed insights into your application's runtime behavior and making it easier to debug issues.

It's important to note that every time you build a release of your application, you'll need to upload the newly generated PDB file if you want more information in the stack traces from that build. Raygun is most valuable when your application is in production and being used by customers, rather than while debugging. So you generally only need to upload PDB files for builds of your application that get released to your customers.

The recommended way of uploading the PDB files to Raygun is by automating a POST to the API endpoint. Below are examples of uploading a PDB file using cURL and different authentication methods. Each needs to be substituted (including the angle brackets) with your own value as described below each code example.

Basic authentication

curl -L
  -H "Authorization: Basic <BASIC_AUTH_TOKEN>"
  -F "SymbolFile=@<PATH_TO_PDB_FILE>"
  https://app.raygun.com/upload/pdbsymbols/<RAYGUN_APPLICATION_ID>

BASIC_AUTH_TOKEN can be generated by taking your Raygun account credentials in the format username:password and then using the base 64 encoded result.
PATH_TO_PDB_FILE is an absolute or relative path to your PDB file including the file name and .pdb extension.
RAYGUN_APPLICATION_ID is available in the URL of Raygun when viewing your application data.

External access token

curl -L
  -F "SymbolFile=@<PATH_TO_PDB_FILE>"
  https://app.raygun.com/upload/pdbsymbols/<RAYGUN_APPLICATION_ID>?authToken=<EXTERNAL_ACCESS_TOKEN>

PATH_TO_PDB_FILE is an absolute or relative path to your PDB file including the file name and .pdb extension.
RAYGUN_APPLICATION_ID is available in the URL of Raygun when viewing your application data.
EXTERNAL_ACCESS_TOKEN can be obtained from Raygun by clicking your name in the top right corner, select "My settings" and then hit "Generate external access token" or copy it if you already have one.

Additional options

If the upload is clearly not working, add the verbose -v option to get more information about what's wrong.

curl -v
  -L
  -F "SymbolFile=@<PATH_TO_PDB_FILE>"
  https://app.raygun.com/upload/pdbsymbols/<RAYGUN_APPLICATION_ID>?authToken=<EXTERNAL_ACCESS_TOKEN>

Possible results

200 if the upload was successful.

302 if you don't provide any form of authentication.

401 if credentials are incorrect, or you don't have access to the application.

404 if the URL or app id is incorrect.

curl (26) if the path to the PDB file is incorrect.

A drag and drop zone is available in the Raygun web application for manually uploading PDB files. This can be found by first visiting the desired application in your Raygun account, selecting "Application settings" from the side menu, and then clicking "Symbol center".

Regardless of how you upload your PDB files, they will all be listed in the Symbol Center as seen in the image above. Each listed PDB file includes a button to delete the file which is useful if you upload the wrong PDB or want to tidy up old files.


An overload of Send and SendInBackground allows you to include a list of tags with each manually sent exception:

_raygunClient.Send(exception, new List<string>() { "tag1", "tag2" });

Exceptions can be searched in your Raygun dashboard by tags that you've included.


You can include key-value custom data using an overload of the Send or SendInBackground method. Values can be primitive types or rich object structures. All properties of objects and their children will be sent to Raygun. Cyclic object references will be detected and handled as appropriate, and any property getter that produces an exception will cause that property value to be displayed as the exception message.

_raygunClient.Send(exception, null, new Dictionary<string, object>() { { "key", "value" } });

The second parameter is the list of tags (mentioned above) which can be null if you don't have tags for the current exception.


We support the inclusion of environment variables such as PATH which will be displayed under the "Environment" tab of your crash report. In RaygunSettings provide a list of strings that will match the keys you would like to record from the environment variables. These queries are case-insensitive, so if you query for PATH we can still obtain Path for you.

Supported query types:

  • Exact Match: PATH
  • Starts With: POSH_*
  • Ends With: *_VALUE
  • Contains: *Program*

note: We prevent the use of * queries, we intend this to be an explicit opt-in for each environment variable.

Below is an example of how to add a query that gets all USER and POSH_ related environment variables.

settings.EnvironmentVariables.Add("USER*");
settings.EnvironmentVariables.Add("POSH_*");

By default, Raygun4Net will attempt to send the assembly version of your project with each report. If this is unavailable, or if you need to provide your own custom version value, you can do so by setting the ApplicationVersion property of the RaygunClient.

_raygunClient.ApplicationVersion = "1.3.37.0";

If you have common outer exceptions that wrap a valuable inner exception which you'd prefer to group by, you can specify these by using the following multi-parameter method:

_raygunClient.AddWrapperExceptions(typeof(MyWrapperException));

The above example will cause MyWrapperException instances to be stripped away and never sent to Raygun. Instead, only the inner exception of any stripped exceptions will be sent. By default HttpUnhandledException and TargetInvocationException will always be stripped - see below to override this behavior.

If you want to prevent Raygun4Net from stripping the default wrapper exceptions (HttpUnhandledException and TargetInvocationException) then you can call the multi-parameter RemoveWrapperExceptions method as shown below. This can also be useful if you've used the above instructions to cause Raygun4Net to strip a wrapper exception type that you later don't want to strip within a single execution of the app.

_raygunClient.RemoveWrapperExceptions(typeof(TargetInvocationException));

The provider is open source and available at the Raygun4Net repository.


You can optionally specify an Offline Store for crash reports when creating your RaygunClient.

When an offline store is specified, if there are any issues sending an exception to the Raygun API, a copy of the exception may be stored locally to be retried at a later date.

An exception is stored offline when one of the following conditions are met:

  • There was a network connectivity issue, e.g. no active internet connection on a mobile device
  • The Raygun API responded with an HTTP 5xx, indicating an unexpected server error
// Attempt to send any offline crash reports every 30 seconds
var sendStrategy = new TimerBasedSendStrategy(TimeSpan.FromSeconds(30));

// Store crash reports in Local AppData
var offlineStore = new LocalApplicationDataCrashReportStore(sendStrategy);

var raygunClient = new RaygunClient(new RaygunSettings()
{
  ApiKey = "paste_your_api_key_here",

  // Optionally store 
  OfflineStore = offlineStore
});

You may extend and create your own custom implementations of OfflineStoreBase and IBackgroundSendStrategy to further customize where errors are stored, and when they are sent.