ASP.NET Minimal APIs
Installation
Step 1 - Install the NuGet package
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.
Step 2 - Configure Raygun
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";
});
Step 3 - Add the Raygun middleware
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.
Step 4 - Release
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")));
Optional - Enhance your logging with Raygun
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.
Manually sending exceptions
The above instructions will set up Raygun4Net to automatically detect and send all unhandled exceptions to Raygun. Sometimes, however, you may want to send exceptions manually, such as handled exceptions from within a try/catch block.
Ideally, you will have already set up your logging service to send errors to Raygun (this can be accomplished with the Serilog Sinks Raygun provider or a global ILogger
implementation), in which case you can manually report exceptions through your logger.
If you are not using a logging service, you can manually send exceptions by creating 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 shut down 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("paste_your_api_key_here").SendInBackground(e);
}
Using a singleton RaygunClient
In an ASP.NET Minimal APIs environment, when working with a singleton RaygunClient
, you need to manually assign the HTTP context and manually send the exception. ASP.NET Minimal APIs, with its flexible route-to-code model, simplifies this process.
Assuming that the RaygunMiddleware
is already configured in your Program.cs
file, you will want to ensure that an instance of RaygunClient
is added to your service collection:
builder.Services.AddSingleton<RaygunClient>();
Here is an example of how to manually set the HTTP context and send an exception using a singleton RaygunClient
:
app.MapGet("/TestManualError", async (RaygunClient singletonRaygunClient, HttpContext context) =>
{
try
{
throw new Exception("Test exception");
}
catch (Exception ex)
{
singletonRaygunClient.SetCurrentContext(context);
await singletonRaygunClient.Send(ex);
}
// Respond with a status code or a view
return Results.Problem(detail: "An exception occurred", statusCode: StatusCodes.Status500InternalServerError);
});
In this example, we are defining a route, /TestManualError
, and an associated handler for HTTP GET requests. The RaygunClient
and HttpContext
instances are provided via dependency injection directly into the route handler. This approach ensures that the Raygun crash report contains any HttpContext
information and that the exception is sent using a singleton RaygunClient
.
Throw exceptions to avoid missing stack traces
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 before catching and sending it. This will ensure that stack traces are included, allowing for better error grouping within Raygun and easier debugging for you.
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.
With Minimal APIs in ASP.NET, when you've configured a custom ClientProvider
, you can utilize this ClientProvider
to modify the instance of the RaygunClient
used in the RaygunAspNetCoreMiddleware
.
Let's say, for instance, 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;
}
}
Assuming that the RaygunMiddleware
is already configured in your Program.cs
file, you will then add your custom ClientProvider
to the service collection in the same file like this:
builder.Services.AddSingleton<IRaygunAspNetCoreClientProvider, ExampleRaygunAspNetCoreClientProvider>();
This custom ClientProvider
will now be used by the RaygunMiddleware
to acquire an instance of the RaygunClient
when sending exceptions. This process ensures that the Raygun crash report contains any HttpContext
information and executes any code specified in your ClientProvider.GetClient()
method.
Manually sending exceptions with a custom ClientProvider
With Minimal APIs in ASP.NET, when you've configured a custom ClientProvider
, you will want to utilize this ClientProvider
to acquire an instance of the RaygunClient
when manually sending an exception. To accomplish this, use the Dependency Injection framework to furnish an instance of the IRaygunAspNetCoreClientProvider
and IOptions
to your endpoint handler. This process ensures that the Raygun crash report contains any HttpContext
information and executes any code specified in your ClientProvider.GetClient()
method.
Assuming that the RaygunMiddleware
is already configured in your Program.cs
file, you will need to create a custom ClientProvider
and add it to the service collection in Program.cs
:
builder.Services.AddSingleton<IRaygunAspNetCoreClientProvider, YourClientProvider>();
Replace YourClientProvider
with your actual implementation of IRaygunAspNetCoreClientProvider
.
Now, you can create an endpoint that uses the custom ClientProvider to manually send exceptions:
app.MapGet("/test", async (IRaygunAspNetCoreClientProvider clientProvider, IOptions<RaygunSettings> settings, HttpContext httpContext) =>
{
try
{
throw new Exception("Test exception");
}
catch (Exception ex)
{
// Get the RaygunClient using your custom ClientProvider
var raygunClient = clientProvider.GetClient(settings.Value, httpContext);
// Send the exception to Raygun
await raygunClient.SendInBackground(ex);
}
// Respond with a status code or a view
return Results.Problem(detail: "An exception occurred", statusCode: StatusCodes.Status500InternalServerError);
});
This endpoint throws a test exception which gets caught and sent to Raygun manually. The IRaygunAspNetCoreClientProvider
and IOptions<RaygunSettings>
instances are supplied via dependency injection to the endpoint handler. The RaygunClient
is then created using the custom ClientProvider
and the caught exception is sent to Raygun in the background.
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 sete.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 for 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 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. 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.
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": "paste_your_api_key_here",
"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 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
}
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": "paste_your_api_key_here",
"IgnoreFormFieldNames": ["password","creditcard","cv2"]
}
Three attributes are available, to remove values from these properties:
IgnoreFormFieldNames
(ignores values fromHttpRequest.Form
)IgnoreHeaderNames
(ignores values fromHttpRequest.Headers
)IgnoreCookieNames
(ignores values fromHttpRequest.Cookies
)
Or specify them in code with the following multi-parameter method:
raygunClient.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.
Customers
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 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.
The simplest way to set up Customers 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 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.
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 none apply to 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": "paste_your_api_key_here",
"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 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.