MessagePack-CSharp / MessagePack-CSharp/MessagePack-CSharp
Null value received in a custom formatter for Exception
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 6.8k
- Forks
- 775
- Avg merge
- 3h 26m
- Merged PRs (30d)
- 6
Description
#### Bug description
When trying to serialize/deserialize an exception object using TypelessContractlessStandardResolver, some details like StackTrace and Source are getting lost on the deserialized object.
Hence, I tried to write a custom IMessagePackFormatter. There are two scenarios now :
1. Serialize an exception with no inner exception
The value parameter received in Serialize method is always null
2. Serialize an exception with inner exception
The value parameter received in Serialize method is the inner exception and not the actual exception that was passed for serialization
As a result, I am not able to get a workaround even with a custom IMessagePackFormatter.
#### Repro steps
- Add a custom IMessagePackFormatter
```
internal class ExceptionFormatter : IMessagePackFormatter
{
public Exception Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
{
}
public void Serialize(ref MessagePackWriter writer, Exception value, MessagePackSerializerOptions options)
{
/// value is null here if exception has no inner exception else inner exception instead of actual exception passed for serialization
}
}
```
- Configure a custom resolver to use the custom ExceptionFormatter
```
interface ISerializer
{
byte[] Serialize(object obj);
T Deserialize(byte[] bytes);
}
public class MessagePackTypeLessSerializer : ISerializer
{
private static MessagePackSerializerOptions serializerOptions;
static MessagePackTypeLessSerializer()
{
var resolver = CompositeResolver.Create(
[new ExceptionFormatter()],
[TypelessContractlessStandardResolver.Instance]);
serializerOptions = MessagePackSerializerOptions.Standard.WithResolver(resolver); ;
}
public byte[] Serialize(object obj)
{
return MessagePackSerializer.Typeless.Serialize(obj, serializerOptions);
}
public T Deserialize(byte[] bytes)
{
if (MessagePackSerializer.Typeless.Deserialize(bytes, serializerOptions) is T result)
{
return result;
}
throw new ArgumentException($"Deserialized object is not of type {typeof(T)}");
}
}
```
- Throw an exception and try to serialize
```
ISerializer serializer = new MessagePackContractLessSerializer();
var exception = GetException();
var exceptionSerialized = serializer.Serialize(exception);
Exception GetException()
{
try
{
throw new InvalidOperationException("Invalid Operation");
//throw new InvalidOperationException("Invalid Operation", new ArgumentException("Inner Exception"));
}
catch (Exception ex)
{
return ex;
}
}
```
#### Expected behavior
Correct exception object should be received in Serialize method of the IMessagePackFormatter that was passed for serialization.
#### Actual behavior
null/inner exception object is received in Serialize method of the IMessagePackFormatter instead of actual exception passed for serialization.
#### Version used:
.Net Core 8.0 , MessagePack 2.5.172 : **Broken**
.Net Framework 4.7, MessagePack 2.5.172 : **Partly broken** (When no inner exception, we get the correct value. Same as .net core when there is inner exception)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the custom IMessagePackFormatter scenario with TypelessContractlessStandardResolver and the MessagePackSerializerOptions shown in the issue, comparing .NET Core 8.0 and .NET Framework 4.7 behavior. Trace the typeless serialization and resolver path to determine why Serialize receives null or the inner exception; done means the formatter receives the original exception object in both cases.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100