ASP.NET Core

This provider is for Web Applications running on .NET 6+, such as:

  • ASP.NET Core Web API
  • ASP.NET Core Web App (Model-View-Controller)

For older .NET Framework applications, see the ASP.NET Framework, and .NET Framework pages.

Installation

ASP.NET is supported through our Raygun4Net.AspNetCore provider.

The best way to install Raygun4Net.AspNetCore is to use the dotnet CLI tool. Run the following command in your project folder to install it.

dotnet add package Mindscape.Raygun4Net.AspNetCore

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


This can be done through the appsettings.json configuration file or in-code.

appsettings.json configuration:

Add a new section called RaygunSettings

"RaygunSettings": {
  "ApiKey": "paste_your_api_key_here"
}

Pass the Configuration object into the call to .AddRaygun

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRaygun(builder.Configuration);

In-code configuration:

Use a delegate to configure Raygun

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRaygun(settings => 
{
  settings.ApiKey = "paste_your_api_key_here";
});

This middleware will capture unhandled exceptions that occur durring a request.

var app = builder.Build();
app.UseRaygun();

/* The rest of your app setup */

You should call .UseRaygun after any other exception handling middleware. eg., app.UseDeveloperExceptionPage() or app.UseExceptionHandler("/Home/Error").

The above setup will capture all unhandled exceptions and send them to Raygun.


For Raygun to capture unhandled exceptions, you will need to run your application in Production mode (dotnet run --environment Production). This way, unhandled exceptions will not be passed to the Development exception handler. You can also raise a test exception like so:

app.MapGet("/throw", (Func<string>)(() => throw new Exception("Exception in request pipeline")));

To fully leverage the capabilities of Raygun, we recommend integrating it into your logging pipeline. By doing so, any time a method like _logger.LogError() is invoked, a report is also dispatched to Raygun.

This can be easily achieved by using our Serilog Sinks Raygun provider or our Microsoft ILogger provider.


A RaygunClient singleton is added to the DI container when .AddRaygun() is called. You can manually send exceptions by retrieving this RaygunClient instance from the container and calling SendInBackground. Note that SendInBackground should only be used for handled exceptions, otherwise the program may shut down before there is a chance to send the exception to Raygun. Unhandled exceptions should be sent using the SendAsync method.

Example:

Pass in a RaygunClient to the constructor of your class.

private readonly RaygunClient _raygunClient;

public MyClass(RaygunClient raygunClient)
{
  _raygunClient = raygunClient;
}

Call SendInBackground when handling exceptions within your class.

try
{
  throw new Exception("Something has gone wrong");
}
catch (Exception e)
{
  await _raygunClient.SendInBackground(e);
}

You may have code that detects that something has gone wrong but doesn't actually throw an exception. A .NET exception needs to be thrown in order for its stack trace to be populated. Ensure you throw exceptions before catching and sending it for the stack trace to be generated.

// Wont produce a stack trace
_raygunClient.SendInBackground(new Exception("Something has gone wrong"));


try
{
  // Will produce a stack trace
  throw new Exception("Something has gone wrong");
}
catch (Exception e)
{
  await _raygunClient.SendInBackground(e);
}

On the RaygunClient, attach an event handler to the SendingMessage event. This event handler will be called just before any exception reports are sent to Raygun. The event arguments provide the RaygunMessage object that is about to be sent.

There are two expected uses for this event handler:

  • Modify the message: Change the RaygunMessage object before the exception report is sent to Raygun.
  • Cancel the message: Set Cancel = true on the RaygunMessage to prevent the exception report from being sent to Raygun. Useful if the exception is from parts of the application you have no control over (such as third party packages).

Modifying a message example:

_raygunClient.SendingMessage += (sender, args) =>
{
  args.Message.Details.Tags.Add("Fruits!");
};

Cancelling a message example:

_raygunClient.SendingMessage += (sender, args) =>
{
  if ("BadServer".Equals(args.Message.Details.MachineName))
  {
    args.Cancel = true;
  }
};

Additionally, the RaygunClient can be configured by registering it with the Dependency Injection container. This provides a centralized location for the client to be configured.

builder.Services.AddSingleton(s => 
{
  var client = new RaygunClient(s.GetService<RaygunSettings>()!, s.GetService<IRaygunUserProvider>()!);

  client.SendingMessage += (sender, eventArgs) =>
  {
    eventArgs.Message.Details.Tags.Add("Fruits!");
  };

  return client;
});

// register the RaygunClient before calling AddRaygun
builder.Services.AddRaygun(builder.Configuration);

Note that if an exception occurs within your SendingMessage 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.


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 exception reports are grouped together or put into separate groups that 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.

note: 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

_raygunClient.CustomGroupingKey += (sender, args) =>
{
  // This example simply performs pure message based grouping on basic Exception instances:
  if (args.Message.Details.Error.ClassName.Equals("Exception"))
  {
    string key = args.Exception.Message;
    args.CustomGroupingKey = key;
  }
};

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.


You can exclude errors by their HTTP status code by providing an array of status codes to ignore in the configuration. For example, if you wanted to exclude errors that return the I'm a teapot response code, you could use this configuration:

"RaygunSettings": {
  "ApiKey": "paste_your_api_key_here",
  "ExcludedStatusCodes": [418]
}

To prevent Raygun4Net from sending exceptions that originate from a local origin (your debug/development machine), set the ExcludeErrorsFromLocal setting to true as seen in the code below. This is useful if you find that you are generating pointless noise in the development process. This option is a convenient alternative to using transforms to do the same thing.

"RaygunSettings": {
  "ApiKey": "paste_your_api_key_here",
  "ExcludeErrorsFromLocal": true
}

By default, Raygun4Net will send all form-fields and headers in the current HTTP request. If you have sensitive data in an HTTP request that you wish to prevent being transmitted to Raygun, you can provide a list of possible named values to remove:

"RaygunSettings": {
  "ApiKey": "paste_your_api_key_here",
  "IgnoreFormFieldNames": ["password","creditcard","cv2"]
}

Three attributes are available, to remove values from these properties:

  • IgnoreFormFieldNames (ignores values from HttpRequest.Form)
  • IgnoreHeaderNames (ignores values from HttpRequest.Headers)
  • IgnoreCookieNames (ignores values from HttpRequest.Cookies)

Or specify them in code:

builder.Services.AddRaygun(settings =>
{
  settings.IgnoreFormFieldNames = ["password", "creditcard", "cv2"];
});

Setting any of these options to true will cause Raygun4Net to ignore all values in that category. Also, by placing before, after, or at both ends of a name, Raygun4Net will use that as an ends-with, starts-with or contains condition respectively when determining what to ignore.


User information enables the Raygun dashboard to track unique users impacted by each error or crash. While you can input any useful data, remember to respect your company's privacy policies. At a minimum, input a unique GUID for user impact visibility per error. A database ID, if available, could help in resolving issues. Providing names and contact details allows for direct communication about issue resolution.

Default implementation

By default Raygun4Net ships with a DefaultRaygunUserProvider which will attempt to get the user information from the HttpContext.User object. This is Opt-In which can be added by calling:

services.AddRaygunUserProvider();

Custom implementation

If you want to provide your own implementation of the IRaygunUserProvider you can do so by creating a class that implements the interface and then adding it to the services during configuration using services.AddRaygunUserProvider<MyCustomUserProvider>().

Below is an example user provider that uses the HttpContext.User similar to our DefaultRaygunUserProvider.

public class ExampleUserProvider : IRaygunUserProvider
{
  private readonly IHttpContextAccessor _contextAccessor;
  
  public ExampleUserProvider(IHttpContextAccessor httpContextAccessor)
  {
    _contextAccessor = contextAccessor;
  }
  
  public RaygunIdentifierMessage? GetUser()
  {
    var ctx = _contextAccessor.HttpContext;
    
    if (ctx == null)
    {
      return null;
    }

    var identity = ctx.User.Identity as ClaimsIdentity;
    
    if (identity?.IsAuthenticated == true)
    {
      return new RaygunIdentifierMessage(identity.Name)
      {
        IsAnonymous = false
      };
    
    return null;
  }
}

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 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.

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.


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

_raygunClient.SendAsync(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 SendAsync 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.SendAsync(exception, null, new Dictionary<string, object>() { { "key", "value" } });

The second parameter is the list of tags (mentioned above), which can be null if none apply to the current exception.


By default, Raygun4Net will attempt to set ApplicationVersion from the entry assembly. It is possible to override this by providing a version through RaygunSettings:

Via appsettings:

"RaygunSettings": {
  "ApiKey": "paste_your_api_key_here",
  "ApplicationVersion": "1.0.0.0"
}

In code:

services.AddRaygun(settings =>
{
  settings.ApiKey = "paste_your_api_key_here";
  settings.ApplicationVersion = "1.0.0.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 TargetInvocationException will always be stripped - see below to override this behavior.

AggregateException is a special case as it can hold multiple inner exceptions. By stripping AggregateException instances using the method described above, all inner exceptions will be sent to Raygun as separate exception reports. That way, each inner exception can be put into the appropriate individual groups and managed separately.

If you want to prevent Raygun4Net from stripping the default wrapper exception (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 Raygun4Net provider uses the default Windows proxy settings when sending messages to Raygun. Unfortunately, we don't support setting a proxy server or proxy credentials by configuration yet.


On the first line of the /[Pages|Views]/Shared/_layout.cshtml file, add @inject Microsoft.Extensions.Configuration.IConfiguration Configuration

Then, at the end of the <head> element, add the Raygun4JS CDN fetch script with the API key automatically imported from your app's Configuration.

@inject Microsoft.Extensions.Configuration.IConfiguration Configuration
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - razorDemo</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
    <link rel="stylesheet" href="~/razorDemo.styles.css" asp-append-version="true" />
    <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>
    <script type="text/javascript">
      rg4js('apiKey', '@Configuration["RaygunSettings:ApiKey"]');
      rg4js('enableCrashReporting', true);
      rg4js('enableRealUserMonitoring', true); <!-- Optional, enable Real User Monitoring -->
    </script>
</head>
<body>
<!-- The rest of the body  -->
</body>

If you want to include the logged-in user's details, they can populated from the HttpContext.User object.

To do this, add @using System.Security.Claims to the top of the _layout.cshtml file, then update the Raygun4JS fetch script at the end of the <head> element to include the rg4js('setUser', {...}); section below:

<script type="text/javascript">
  rg4js('apiKey', '@Configuration["RaygunSettings:ApiKey"]');
  rg4js('enableCrashReporting', true);
  rg4js('enableRealUserMonitoring', true); <!-- Optional, enable Real User Monitoring -->
  rg4js('setUser', {
        identifier: @ViewContext.HttpContext?.User?.FindFirstValue(ClaimTypeNameIdentifier),
        isAnonymous: @(!(ViewContext.HttpContext?.User?.Identity?.IsAuthenticated ?? false)),
        email: @ViewContext.HttpContext?.User?.FindFirstValue(ClaimTypes.Email),
        fullName: @ViewContext.HttpContext?.User?.FindFirstValue(ClaimTypes.GivenName),
    });
</script>

Depending on your authentication model, you may need to adjust what ClaimTypes you use.

For more front-end configuration options, visit our JavaScript provider's Advanced Features documentation.


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