// TODO: Remove recursion. public static void WriteException( this Utf8JsonWriter writer, Exception?exception, JsonSerializerOptions options ) { // Validate parameters. if (writer == null) { throw new ArgumentNullException(nameof(writer)); } if (options == null) { throw new ArgumentNullException(nameof(options)); } // If there is no exception, write null. if (exception == null) { // Write null. writer.WriteNullValue(); // Get out. return; } // Start writing the object. writer.WriteStartObject(); // Write properties. writer.WriteString(ExceptionPropertyInfo.Message, exception.Message, options); writer.WriteString(ExceptionPropertyInfo.Source, exception.Source, options); writer.WriteNumber(ExceptionPropertyInfo.HResult, exception.HResult, options); writer.WriteString(ExceptionPropertyInfo.HelpLink, exception.HelpLink, options); writer.WriteString(ExceptionPropertyInfo.StackTrace, exception.StackTrace, options); // Write the property name. writer.WritePropertyName(ExceptionPropertyInfo.Data, options); // Write the data property. JsonSerializer.Serialize(writer, exception.Data, options); // Need to write the type shim. Write the meta property writer.WritePropertyName("$Meta"); // Write all the type information. Type type = exception.GetType(); // Write a new object. writer.WriteStartObject(); // Write the type. writer.WritePropertyName("Type"); // Write a new object. writer.WriteStartObject(); // Write properties. writer.WriteString(nameof(Type.Namespace), type.Namespace); writer.WriteString(nameof(Type.FullName), type.FullName); writer.WriteString(nameof(Type.AssemblyQualifiedName), type.AssemblyQualifiedName); writer.WriteString(nameof(Type.Name), type.Name); // Close the type then the meta object. writer.WriteEndObject(); writer.WriteEndObject(); // Are there any properties which are assignable // to exception or IEnumerable<Exception>? // If so, write those. Cycle through the properties. foreach (PropertyInfo propertyInfo in type.GetPropertiesWithPublicInstanceGetters()) { // Is it assignable to exception? if (Constant.ExceptionTypeInfo.IsAssignableFrom(propertyInfo.PropertyType)) { // Write the property name. writer.WritePropertyName(propertyInfo, options); // Write the object. writer.WriteException((Exception?)propertyInfo.GetValue(exception), options); } // If this is assignable to an IEnumerable<Exception> then // get that. else if (Constant.EnumerableExceptionTypeInfo.IsAssignableFrom(propertyInfo.PropertyType)) { // Get the value. var exceptions = (IEnumerable <Exception>?)propertyInfo.GetValue(exception); // Write the property name. writer.WritePropertyName(propertyInfo, options); // Write the exception array. writer.WriteExceptionArray(exceptions, options); // Continue. continue; } } // Write the end of the object. writer.WriteEndObject(); }