mbdavid / LiteDB

LiteDB - A .NET NoSQL Document Store in a single data file
http://www.litedb.org
MIT License
8.52k stars 1.24k forks source link

[BUG] Cannot serialize Exception object that has been thrown #2232

Closed Iron2213 closed 9 months ago

Iron2213 commented 2 years ago

Version 5.0.12

Bug description Cannot serialize Exception object that has been thrown, objects created with the "new" keyword work fine.

Code to reproduce

// _db is a normal 'LiteDatabase' object with default settings
var coll = _db.GetCollection<ArgumentException>("test");

try
{
    throw new ArgumentException();
}
catch (ArgumentException ex)
{
    coll.Insert(ex);
}

Stack trace

System.InvalidOperationException: Method may only be called on a Type for which Type.IsGenericParameter is true.
         at System.RuntimeType.get_DeclaringMethod()
         at lambda_method111(Closure , Object )
         at LiteDB.BsonMapper.SerializeObject(Type type, Object obj, Int32 depth)
         at LiteDB.BsonMapper.Serialize(Type type, Object obj, Int32 depth)
         at LiteDB.BsonMapper.SerializeObject(Type type, Object obj, Int32 depth)
         at LiteDB.BsonMapper.Serialize(Type type, Object obj, Int32 depth)
         at LiteDB.BsonMapper.SerializeObject(Type type, Object obj, Int32 depth)
         at LiteDB.BsonMapper.Serialize(Type type, Object obj, Int32 depth)
         at LiteDB.BsonMapper.SerializeObject(Type type, Object obj, Int32 depth)
         at LiteDB.BsonMapper.Serialize(Type type, Object obj, Int32 depth)
         at LiteDB.BsonMapper.SerializeArray(Type type, IEnumerable array, Int32 depth)
         at LiteDB.BsonMapper.Serialize(Type type, Object obj, Int32 depth)
         at LiteDB.BsonMapper.SerializeObject(Type type, Object obj, Int32 depth)
         at LiteDB.BsonMapper.Serialize(Type type, Object obj, Int32 depth)
         at LiteDB.BsonMapper.SerializeObject(Type type, Object obj, Int32 depth)
         at LiteDB.BsonMapper.Serialize(Type type, Object obj, Int32 depth)
         at LiteDB.BsonMapper.ToDocument(Type type, Object entity)
         at LiteDB.BsonMapper.ToDocument[T](T entity)
         at LiteDB.LiteCollection`1.Insert(T entity)
jurasans commented 2 years ago

In the serialization logic, there is no concept of serializing an exception, so it falls back to trying to reflect the object as a plain object, but it has many System.Type nested in it that don't reflect well, put shortly.

So the question remains to be asked: how do you want to use the exceptions serialized? if you want to view them only:

@Iron2213 you can add the exception manually, using the BsonMapper : BsonMapper.Global.RegisterType<Exception> (ex => new BsonDocument{{ "m", ex.Message }, { "s", ex.StackTrace} }, bson => new Exception((string)bson.RawValue));

but if you want to deserialize them and use them in your code (WHY? O_O) you will need more code acrobatics for this.

@mbdavid do you think a log for this usecase is required? something like "exceptions not supported" or a basic Exception recording handler like mentioned above?

Iron2213 commented 2 years ago

No, my main objective was to just store message, stack trace and exception type. I resolved this problem by simply creating a simple container and extracting the informations inside it by using implicit conversions:

public class FailDetails
{
    public string Message { get; set; } = string.Empty;
    public string? ExceptionType { get; set; }
    public string? StackTrace { get; set; }

    public static implicit operator FailDetails(Exception ex) => new()
    {
        Message = ex.Message,
        ExceptionType = ex.GetType().Name,
        StackTrace = ex.StackTrace
    };

    public static implicit operator FailDetails(string message) => new()
    {
        Message = message
    };

    public override string ToString()
    {
        if (ExceptionType is null)
            return $"{{Message: {Message}}}";

        return $"{{ExceptionType: {ExceptionType}, Message: {Message}}}";
    }
}
jurasans commented 2 years ago

Yes thats the easy and simple way, if thats satisfying your usecase.