private static void StoreCustomExceptionProperties(Exception rootException, Exception exception) { if (exception.InnerException != null) { StoreCustomExceptionProperties(rootException, exception.InnerException); } if (exception is AggregateException aggregate) { foreach (var innerException in aggregate.InnerExceptions) { if (innerException == exception.InnerException) { // Skip the exception if it is the inner exception continue; } StoreCustomExceptionProperties(rootException, innerException); } // There are no other properties we want to track on AggregateException return; } var baseProperties = typeof(Exception).GetTypeInfo().GetProperties(); var exceptionProperties = exception.GetType().GetTypeInfo().GetProperties(); var customProperties = exceptionProperties.Except(baseProperties, new PropertyMatcher()); var typeName = exception.GetType().GetTypeInfo().Name; foreach (var property in customProperties) { var keyName = typeName + "." + property.Name; // Check that this key has not already been assigned if (rootException.HasSerializedData(keyName)) { continue; } try { var value = property.GetValue(exception); if (value == null) { continue; } rootException.AddSerializedData(keyName, value); } #pragma warning disable CC0004 // Catch block cannot be empty catch (Exception) { // We failed to get this property, skip to the next one } #pragma warning restore CC0004 // Catch block cannot be empty } }