UWP

Installation

1. Install the NuGet package

Raygun4UWP is available as a NuGet package. Using your IDE of choice, or the package manager console, install the Raygun4UWP NuGet package into your project. More information about the NuGet package can be found here.

2. Initialize the RaygunClient and enable unhandled exception tracking

The most basic setup of Raygun4UWP can be achieved with a single line of code. Place the following code within the App.xaml.cs constructor. Your app API key is displayed on the instructions page, whenever you create a new application in Raygun. You can also find the API key by clicking the “Application Settings” button in the side menu of the Raygun app.

RaygunClient.Initialize("YOUR_APP_API_KEY").EnableCrashReporting();

Here is a break down of what this does:

Initialize creates a new RaygunClient and sets it on the static RaygunClient.Current property. This is so you can access the RaygunClient instance anywhere in your code to adjust settings, or manually send data to Raygun.

EnableCrashReporting will cause the RaygunClient to automatically listen to all unhandled exceptions that your application experiences, and send them off to your Raygun account.

3. Upload your PDB files

In order to get line numbers and file names in your crash report stack traces, you can upload your application’s PDB file to Raygun. There are a couple of different ways to do this which are outlined in the Upload your PDB files section.


Manually sending exceptions

The above instructions will setup Raygun4UWP 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.

Below is a simple code example of manually sending an exception. Note that the asynchronous ‘fire and forget’ method is used here so that your application can immediately continue.

try
{
  
}
catch (Exception ex)
{
  RaygunClient.Current.SendAsync(ex);
}

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

Custom tags

The send exception method has an optional argument for sending a list of string tags. These tags are useful to categorize exceptions in different ways which you can filter in Raygun.

RaygunClient.Current.SendAsync(ex, new List<string>{"Critical", "Data"});

Custom data

Another optional argument of the send exception method is a dictionary of string keys and object values. This lets you attach custom data that helps to investigate the exception further, such as the state of related models.

RaygunClient.Current.SendAsync(ex, userCustomData: new Dictionary<string, object>
{
  {"ExperimentalFeaturesEnabled", true}
});

The SendingCrashReport event

Every time an exception message is about to be serialized and sent to Raygun, the RaygunClient.SendingCrashReport event is invoked. This will be called regardless of if the exception is being reported manually, or automatically by the RaygunClient. The event arguments contain both the Raygun exception message and the original Exception object. Attaching a handler to this event can be used in a few different ways:

Modifying the message

Any changes you make to e.CrashReport will be included when the report is serialized and sent to Raygun. Since this event handler is called for both manually and automatically sent exceptions, it’s a good place to put common report logic. For example, you could use this to attach tags or global application data.

public App()
{
  RaygunClient.Initialize("YOUR_APP_API_KEY").EnableCrashReporting().EnableRealUserMonitoring();
  RaygunClient.Current.SendingCrashReport += RaygunClient_SendingCrashReport;

  this.InitializeComponent();
  this.Suspending += OnSuspending;
}

private void RaygunClient_SendingCrashReport(object sender, RaygunSendingCrashReportEventArgs e)
{
  if (e.OriginalException.Message.Contains("Unknown error"))
  {
    // Tags
    IList<string> tags = e.CrashReport.Details.Tags ?? new List<string>();

    tags.Add("Unknown");
    tags.Add("Low priority");
    tags.Add("Not important");

    e.CrashReport.Details.Tags = tags;
  }
  
  // Custom data
  IDictionary customData = e.CrashReport.Details.UserCustomData ?? new Dictionary<string, object>();

  customData["currentState"] = MyApplicationModel.State;

  e.CrashReport.Details.UserCustomData = customData;
}

Custom exception grouping

Another common use for the SendingCrashReport event handler is to control the way that Raygun groups your exceptions. If you set the e.CrashReport.Details.GroupingKey property, then Raygun will use that as a grouping key when processing that report. Any reports that have the same GroupingKey value will be grouped together. You can include logic to only provide a GroupingKey for specific reports. Any report that doesn’t have a GroupingKey will simply be grouped by the Raygun processing pipeline in the usual way.

public App()
{
  RaygunClient.Initialize("YOUR_APP_API_KEY").EnableCrashReporting().EnableRealUserMonitoring();
  RaygunClient.Current.SendingCrashReport += RaygunClient_SendingCrashReport;

  this.InitializeComponent();
  this.Suspending += OnSuspending;
}

private void RaygunClient_SendingCrashReport(object sender, RaygunSendingCrashReportEventArgs e)
{
  if (e.OriginalException.Message.Contains("Unknown error"))
  {
    e.CrashReport.Details.GroupingKey = "UnknownErrorsThatWeJustGroupTogether";
  }
}

Canceling a message

Setting e.Cancel to true within the SendingCrashReport event handler will tell the RaygunClient not to send the report to Raygun. You could check values on the RaygunCrashReport or/and the Exception object to filter out messages that you don’t want. For example, you could cancel certain types of exceptions or reports from old devices / operating systems.

public App()
{
  RaygunClient.Initialize("YOUR_APP_API_KEY").EnableCrashReporting().EnableRealUserMonitoring();
  RaygunClient.Current.SendingCrashReport += RaygunClient_SendingCrashReport;

  this.InitializeComponent();
  this.Suspending += OnSuspending;
}

private void RaygunClient_SendingCrashReport(object sender, RaygunSendingCrashReportEventArgs e)
{
  if (e.OriginalException.Message.Contains("Unknown error"))
  {
    e.Cancel = true;
  }
}

Strip wrapper exceptions

Sometimes an exception will wrap one or more inner exceptions. When these are sent to Raygun, all inner exceptions are included in a single exception report and will be considered during the grouping logic. In these cases, you may find outer exceptions that you’re not interested in which wrap valuable inner exceptions. Below is an example of how you can specify which exceptions you’re not interested in. When these are reported, they’ll be stripped away and the inner exceptions will be sent as individual messages to Raygun. Note that TargetInvocationException will be stripped by default and setting the StrippedWrapperExceptions list will override the default list.

RaygunClient.Current.Settings.StrippedWrapperExceptions = new List<Type>
{
  typeof(TargetInvocationException),
  typeof(AggregateException)
};

Offline storage

If Raygun4UWP is unable to communicate with the Raygun API when sending an error, the error will be saved to a temporary folder called “Raygun4UWPOfflineCrashReports”. When another error occurs or the next time the app is started, Raygun4UWP will attempt to send all saved errors. Up to 10 errors can be saved at a time and any additional errors will replace the oldest saved error.


Unique user tracking

By default, a random GUID will be stored in the roaming data of your application. This will be included as a unique user identifier on all crash reports sent to Raygun. This is a non-identifiable way to get statistics about how many unique users are affected by exceptions.

If you want to include more information about users affected by crash reports, there are two different ways that you can do this as described below. Please be aware of any company privacy policies you have when choosing what type of user information you send to Raygun.

The User property

If all you need to identify a user is a single string, then you can set the User property. Note that setting this to null or whitespace will cause the default random GUID described above to be used. This string can be whatever you like. Below are some common suggestions.

  • Identifying information such as name or email address.
  • An id that doesn’t reveal any information about the user, but can be looked up in your own systems to find out who the user is.
  • Your own random string if you don’t want to use the one Raygun stores in roaming app data. This may however result in unreliable user statistics in Raygun.

The UserInfo property

If a single string is not enough to describe the information that you want to log about a user, then you can set the UserInfo property. Below are the various properties that you can use to describe the user. The Identifier is the only required field, which can be provided through the constructor.

  • Identifier The unique identifier you want to use to identify this user. Suggestions for what you could set this to are listed in the User property section above.
  • IsAnonymous A flag indicating whether the user is logged in (or identifiable) or if they are anonymous. An anonymous user still requires an identifier.
  • UUID A device identifier. Could be used to identify users across devices, or machines that are breaking for many users.
  • Email
  • FullName
  • FirstName

Application version

By default, each exception report will include the version of your application package. If you need to provide your own custom version value, you can do so by setting the ApplicationVersion property of the RaygunClient (in the format x.x.x.x where x is a positive integer).

RaygunClient.Current.ApplicationVersion = "2.5.1.0";

Upload your PDB files

Crash reports that are generated from the release build of you application will not include line numbers or file names in the stack traces. Some stack trace frames may not even have class or method names. This is because this information is not available within your application while it’s running, but can be looked up from associated PDB files.

PDB files can be uploaded to Raygun, which will be used to process your crash reports and resolve missing information. Raygun provides two ways to upload your files - an API end point which is useful for automation and manual upload from within the Raygun web app.

Which PDB file do I upload?

The PDB you’ll want to upload will typically be found at:
<APPLICATION_NAME>\bin\<ENVIRONMENT>\Release\ilc\<APPLICATION_NAME>.pdb
Where <ENVIRONMENT> is x64 or x86. Upload the PDB file for each environment that your application supports. If you’re unsure which PDB to upload, you can learn the correct path by looking at a crash report sent from your application to Raygun. Find a crash report and click the Raw tab. Find the Images section and you’ll see the path of the expected PDB files from the machine that built the application.

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

API endpoint

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
  -H "Authorization: Basic <BASIC_AUTH_TOKEN>"
  -F "file=@<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
  -F "file=@<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 option to get more information about what’s wrong.

-v

Possible results

200 if the upload was successul.

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.

Manual upload

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

Managing your uploaded PDB files

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.

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