ASP.NET
Installation
1. Install the NuGet package
The best way to install Raygun4Net.AspNetCore is to use use the dotnet
cli tool. In your project folder run dotnet add package Mindscape.Raygun4Net.AspNetCore
to install it.
Another method is to directly edit your .csproj file and add "Mindscape.Raygun4Net.AspNetCore": "6.6.6"
to your dependencies. After you've done this, run dotnet.exe restore or restore packages within Visual Studio to download and install the package.
Alternatively, visit https://www.nuget.org/packages/Mindscape.Raygun4Net.AspNetCore/ for instructions on installation.
2. Setup Raygun in appsettings.json
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.
3. Configure the Raygun Middleware
To configure the Raygun Middleware to handle exceptions that have been triggered and send unhandled exceptions automatically.
In Program.cs
:
- Add
using Mindscape.Raygun4Net.AspNetCore;
to your using statements. - Add
builder.Services.AddRaygun(builder.Configuration);
. - Add
app.UseRaygun();
after any other ExceptionHandling methods e.g.app.UseDeveloperExceptionPage()
orapp.UseExceptionHandler("/Home/Error")
.
using Mindscape.Raygun4Net.AspNetCore;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRaygun(builder.Configuration);
/*The rest of your builder setup*/
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
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();
/*The rest of your app setup*/
The above set up will cause all unhandled exceptions to be sent to your Raygun account, where you can easily view all of your error monitoring and crash report data.
Note: To test and see unhandled errors in Raygun, you need to run your app in, Production mode (
dotnet run --environment Production
) That way the 'unhandled errors' are not handled by the Development exception handler.
We recommend also adding to the logging system. So when you use _logger.LogError()
, it is also sent to Raygun.
One of the easiest ways of doing this is to use the Serilog Raygun Sink.
Adding Raygun to the Front End in ASP.Net
In the /[Pages|Views]/Shared/_layout.cshtml file, on the first line, add @inject Microsoft.Extensions.Configuration.IConfiguration Configuration
The at the end of the <head/>
section add the Raygun4js code with the API key automatically imported from the app 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('enableRUM', true); <!-- optional, enable RealUserMonitoring -->
</script>
</head>
<body>
<!-- the rest of the body -->
</body>
If you want to include the logged-in users details, they can populated from the HttpContext.User
object
Add @using System.Security.Claims
to the top of the _layout.cshtml
file
Then update the end of the <head>
section to include the rg4js('setUser', {});
section below.
Depending on your authentication model, you may need to adjust what
ClaimTypes
you use.
<script type="text/javascript">
rg4js('apiKey', '@Configuration["RaygunSettings:ApiKey"]');
rg4js('enableCrashReporting', true);
rg4js('enableRUM', true); <!-- optional enable RUM -->
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>
There are more configuration options for the javascript Raygun provider. See the javascript language guide for more details.
Manually sending exceptions
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 and you are no using the global ILogger
implementation
To manually send exceptions, create an instance of the RaygunClient class.
With the RaygunClient, you can call either the Send or SendInBackground methods. 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)
{
new RaygunClient("YOUR_APP_API_KEY").SendInBackground(e);
}
Using a singleton RaygunClient
If you are using a singleton RaygunClient, you'll need to manually set the HTTP context (if applicable) before manually sending an exception.
Example:
public class RaygunController : Controller
{
private readonly RaygunClient _singletonRaygunClient;
public RaygunController(RaygunClient singletonRaygunClient)
{
_singletonRaygunClient = singletonRaygunClient;
}
public async Task<IActionResult> TestManualError()
{
try
{
throw new Exception("Test from .NET Core MVC app");
}
catch (Exception ex)
{
_singletonRaygunClient.SetCurrentContext(HttpContext);
await _singletonRaygunClient.Send(ex);
}
return View();
}
}
Throw exceptions to avoid missing stack traces
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 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 a stack trace which is useful for you to debug is included, and will used by Raygun to group exceptions.
Configure RaygunClient or settings in RaygunAspNetCoreMiddleware
The AddRaygun method has an overload that takes a RaygunMiddlewareSettings object. These settings control the middleware (not to be confused with RaygunSettings which are the common settings we use across all of our .NET providers). Currently there's just one property on it, ClientProvider. This gives you a hook into the loading of RaygunSettings and the construction of the RaygunAspNetCoreClient used to send errors.
For example, say you want to set user details on your error reports. You'd create a custom client provider like this:
using Microsoft.AspNetCore.Http;
using Mindscape.Raygun4Net;
using Mindscape.Raygun4Net.AspNetCore;
using System.Linq;
using System.Security.Claims;
public class ExampleRaygunAspNetCoreClientProvider : DefaultRaygunAspNetCoreClientProvider
{
public override RaygunClient GetClient(RaygunSettings settings, HttpContext context)
{
var client = base.GetClient(settings, context);
var identity = context?.User?.Identity as ClaimsIdentity;
if (identity?.IsAuthenticated == true)
{
var email = identity.Claims.Where(c => c.Type == ClaimTypes.Email).Select(c => c.Value).FirstOrDefault();
client.UserInfo = new RaygunIdentifierMessage(email)
{
IsAnonymous = false,
Email = email,
FullName = identity.Name
};
}
return client;
}
}
Then you would change your services.AddRaygun(Configuration) call in ConfigureServices to this:
services.AddRaygun(Configuration, new RaygunMiddlewareSettings()
{
ClientProvider = new ExampleRaygunAspNetCoreClientProvider()
});
Manually sending exceptions with a custom ClientProvider
When configuring a custom ClientProvider you will also want to leverage this ClientProvider to get an instance of the RaygunClient when manually sending an exception. To do this use the Dependency Injection framework to provide an instance of the IRaygunAspNetCoreClientProvider and IOptions to your MVC Controller. This will then ensure that the Raygun crash report also contains any HttpContext information and will execute any code defined in your ClientProvider.GetClient() method.
public class RaygunController : Controller
{
private readonly IRaygunAspNetCoreClientProvider _clientProvider;
private readonly IOptions<RaygunSettings> _settings;
public RaygunController(IRaygunAspNetCoreClientProvider clientProvider, IOptions<RaygunSettings> settings)
{
_clientProvider = clientProvider;
_settings = settings;
}
public async Task TestManualError()
{
try
{
throw new Exception("Test from .NET Core MVC app");
}
catch (Exception ex)
{
var raygunClient = _clientProvider.GetClient(_settings.Value, HttpContext);
await raygunClient.SendInBackground(ex);
}
return View();
}
}
Modify or cancel messages
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 plugins) or due to issues that cannot be solved (such as various bot attacks). 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.
Here is an example of cancelling a message. Notice that this code uses the technique described above of configuring the RaygunMiddlewareSettings with a custom client provider.
public class ExampleRaygunAspNetCoreClientProvider : DefaultRaygunAspNetCoreClientProvider
{
public override RaygunClient GetClient(RaygunSettings settings, HttpContext context)
{
var client = base.GetClient(settings, context);
client.SendingMessage += (sender, args) =>
{
// This is an example of cancelling a message:
if ("BadServer".Equals(args.Message.Details.MachineName))
{
args.Cancel = true;
}
};
return client;
}
}
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.
Custom grouping
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. Notice that this code uses the technique described above of configuring the RaygunMiddlewareSettings with a custom client provider.
public class ExampleRaygunAspNetCoreClientProvider : DefaultRaygunAspNetCoreClientProvider
{
public override RaygunClient GetClient(RaygunSettings settings, HttpContext context)
{
var client = base.GetClient(settings, context);
client.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;
}
};
return client;
}
}
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.
Replace unseekable request streams
Raygun will try to send the raw request payload with each exception report where applicable, but this is only possible with request streams that are seekable.
If you are not seeing any raw request payloads in your exception reports where you'd expect to see them, then you can set the ReplaceUnseekableRequestStreams
setting to true
in your appsettings.json
file. This will attempt to replace any unseekable streams with a seekable copy on the request object so that Raygun can later read the raw request payload.
"RaygunSettings": {
"ApiKey": "YOUR_APP_API_KEY",
"ReplaceUnseekableRequestStreams": true
}
This setting is false
by default to avoid breaking changes or any unforseen issues with its initial deployment.
Raygun will not attempt to send raw request payloads for GET
, x-www-form-urlencoded
or text/html
requests.
Exclude errors by HTTP status code
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": "YOUR_APP_API_KEY",
"ExcludedStatusCodes": [418]
}
Exclude errors that originate from a local origin
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 everyone in your team sending exceptions from their local machines is noisy and pointless. This option is a convenient alternative to using transforms to do the same thing.
"RaygunSettings": {
"ApiKey": "YOUR_APP_API_KEY",
"ExcludeErrorsFromLocal": true
}
Remove sensitive request data
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": "YOUR_APP_API_KEY",
"IgnoreFormFieldNames": ["password","creditcard","cv2"]
}
``` json
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 with the following multi-parameter method:
``` csharp
raygunClient.IgnoreFormFieldNames("password", "creditcard", "cv2");
Setting any of these options to will cause Raygun4Net to ignore all values in that category, so none of them are sent to Raygun. 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.
Unique user tracking
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 prioritizing issues to solve 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.
There are a couple of ways to provide user information, the simplest of which is to set the User property of the RaygunClient instance to an identifier of your choosing:
raygunClient.User = "user@email.com";
If a single identifier string isn't enough, you can set the UserInfo property instead to provide more information:
raygunClient.UserInfo = new RaygunIdentifierMessage("user@email.com")
{
IsAnonymous = false,
FullName = "Robbie Robot",
FirstName = "Robbie"
};
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.
The string properties on a User have a maximum length of 255 characters. Users who have fields that exceed this amount will not be processed.
Tags
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.
Custom data
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.
Version numbering
You can provide an application version value by setting the ApplicationVersion property of the RaygunClient
raygunClient.ApplicationVersion = "1.3.37.0";
Alternatively, you can set the applicationVersion in configuration as follows. If both are set, the property mentioned above takes precedence over the configuration setting.
"RaygunSettings": {
"ApiKey": "YOUR_APP_API_KEY",
"ApplicationVersion": "1.3.37.0"
}
Stripping wrapper exceptions
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 support
AggregateException is a special case as they 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.
Prevent wrapper exception stripping
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));
Proxy settings
The Raygun4Net provider uses the default Windows proxy settings (as set in Internet Explorer's Connection tab) when sending messages to Raygun. Unfortunately we don't support setting a proxy server or proxy credentials by configuration yet.
The provider is open source and available at the Raygun4Net repository.