in src/StreamJsonRpc/Reflection/ExceptionSerializationHelpers.cs [30:88]
internal static T Deserialize<T>(JsonRpc jsonRpc, SerializationInfo info, TraceSource? traceSource)
where T : Exception
{
if (!TryGetValue(info, "ClassName", out string? runtimeTypeName) || runtimeTypeName is null)
{
throw new NotSupportedException("ClassName was not found in the serialized data.");
}
TryGetValue(info, AssemblyNameKeyName, out string? runtimeAssemblyName);
Type? runtimeType = jsonRpc.LoadType(runtimeTypeName, runtimeAssemblyName);
if (runtimeType is null)
{
if (traceSource?.Switch.ShouldTrace(TraceEventType.Warning) ?? false)
{
traceSource.TraceEvent(TraceEventType.Warning, (int)JsonRpc.TraceEvents.ExceptionTypeNotFound, "{0} type could not be loaded. Falling back to System.Exception.", runtimeTypeName);
}
// fallback to deserializing the base Exception type.
runtimeType = typeof(Exception);
}
// Sanity/security check: ensure the runtime type derives from the expected type.
if (!typeof(T).IsAssignableFrom(runtimeType))
{
throw new NotSupportedException($"{runtimeTypeName} does not derive from {typeof(T).FullName}.");
}
// Find the nearest exception type that implements the deserializing constructor and is deserializable.
ConstructorInfo? ctor = null;
Type? originalRuntimeType = runtimeType;
while (runtimeType is object)
{
string? errorMessage =
runtimeType.GetCustomAttribute<SerializableAttribute>() is null ? $"{runtimeType.FullName} is not annotated with a {nameof(SerializableAttribute)}." :
!jsonRpc.ExceptionOptions.CanDeserialize(runtimeType) ? $"{runtimeType.FullName} is not an allowed type to deserialize." :
(ctor = FindDeserializingConstructor(runtimeType)) is null ? $"{runtimeType.FullName} does not declare a deserializing constructor with signature ({string.Join(", ", DeserializingConstructorParameterTypes.Select(t => t.FullName))})." :
null;
if (errorMessage is null)
{
break;
}
if (runtimeType.BaseType is Type baseType)
{
errorMessage += $" {baseType.FullName} will be deserialized instead, if possible.";
}
traceSource?.TraceEvent(TraceEventType.Warning, (int)JsonRpc.TraceEvents.ExceptionNotDeserializable, errorMessage);
runtimeType = runtimeType.BaseType;
}
if (ctor is null)
{
throw new NotSupportedException($"{originalRuntimeType.FullName} is not a supported exception type to deserialize and no adequate substitute could be found.");
}
return (T)ctor.Invoke(new object?[] { info, Context });
}