MessagePack-CSharp / MessagePack-CSharp/MessagePack-CSharp

Null value received in a custom formatter for Exception

未關閉
#2,001 3 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

還沒有人認領這個 Issue。

主要語言
C#
星號
6.8k
分支
775
平均合併
3 小時 26 分鐘
30 天內合併 PR
6

描述

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<Exception>
 {
    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<T>(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<T>(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)

貢獻指南

開啟貢獻指南

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

研究方向

首先,使用 issue 中展示的 TypelessContractlessStandardResolver 和 MessagePackSerializerOptions 重現自訂 IMessagePackFormatter 情境,並比較 .NET Core 8.0 與 .NET Framework 4.7 的行為。追蹤 typeless 序列化和 resolver 路徑,以判斷為什麼 Serialize 會收到 null 或內部例外;當 formatter 在兩種情況下都收到原始 Exception 物件時,即表示完成。

由索引模型根據 Issue 內容生成。

評估

技術堆疊
csharp
領域
backend
Issue 類型
缺陷
難度
4/5
預估耗時
3-5 天
活躍度
停滯
描述清晰度
基本清楚
新手友好度
38/100

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。