MessagePack-CSharp / MessagePack-CSharp/MessagePack-CSharp

Null value received in a custom formatter for Exception

Open
#2,001 3 comments 0 reactions 0 assignees View on GitHub

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.