Instances of abstract class cannot be created unless I write to database first

I have two functions one for write and one for read when i try to use the read function first i get this error:

An error occurred while deserializing the Message property of class DDSRecorder.MessageContainer: Instances of abstract classes cannot be created

Here is what i dont get, if i use the write first at least once then the read works fine. i dont understand what happens in the background that makes it ok to initialize abstract class if we used it once to write.

Adding the map for it didn’t resolve the problem:

    if (BsonClassMap.IsClassMapRegistered(typeof(MessageContainer)))
    {
        BsonClassMap.RegisterClassMap<MessageBase>(cm =>
        {
            cm.AutoMap();
            cm.SetIsRootClass(true);
        });
    }

Here is the class i am using for the mongo collection.

[BsonIgnoreExtraElements(true)]
public class MessageContainer
{
    [BsonId]
    public ObjectId Id { get; set; }

    [BsonDateTimeOptions(Kind = DateTimeKind.Utc)]
    public DateTime TimeStamp { get; set; }

    [BsonElement]
    public string MessageType { get; set; }

    public MessageBase Message { get; set; }

    [BsonConstructor]
    public MessageContainer()
    {

    }

    [BsonConstructor]
    public MessageContainer(MessageBase message)
    {
        Message = message ?? throw new ArgumentNullException(nameof(message));
        TimeStamp = DateTime.UtcNow;
        MessageType = message.GetType().Name;
    }

    [BsonConstructor]
    public MessageContainer(DateTime timeStamp, string messageType, MessageBase message)
    {
        TimeStamp = timeStamp;
        MessageType = messageType ?? throw new ArgumentNullException(nameof(messageType));
        Message = message ?? throw new ArgumentNullException(nameof(message));
    }  
}

And the abstract class inside:

public abstract class MessageBase
    {
        protected MessageBase();

        public MessageBase CreateCopy();
    }

Example of write method:

public bool Write(MessageContainer message)
{
    if (message != null && _mongoCollection != null)
    {
        try
        {

            if (!BsonClassMap.IsClassMapRegistered(typeof(MessageContainer)))
            {
                BsonClassMap.RegisterClassMap<MessageContainer>();
                BsonClassMap.RegisterClassMap<MessageBase>(cm =>
                {
                    cm.AutoMap();
                    cm.SetIsRootClass(true);
                });
            }

            _mongoCollection.InsertOne(message);
           
            return true;                                      
        }
        catch (Exception Ex)
        {
            Console.WriteLine(Ex.Message);
        }
    }
	
    return false;
}

Example of read method:

public bool GetFirstAndLastMessageTime(out DateTime firstMessageTime, out DateTime lastMessageTime)
{
  if (BsonClassMap.IsClassMapRegistered(typeof(MessageContainer)))
  {
      BsonClassMap.RegisterClassMap<MessageBase>(cm =>
      {
          cm.AutoMap();
          cm.SetIsRootClass(true);
      });
  }
  
  var filter = Builders<MessageContainer>.Filter.Empty;    
  var first = _mongoCollection.Find(filter).Sort(Builders<MessageContainer>.Sort.Ascending("TimeStamp")).Limit(5).ToList().First();
  var last = _mongoCollection.Find(filter).Sort(Builders<MessageContainer>.Sort.Descending("TimeStamp")).Limit(5).ToList().First();       
  firstMessageTime = first.TimeStamp; 
  lastMessageTime = last.TimeStamp;
  return true;
}

What am i missing for it to be able to initialize the abstract class without the need of writing first?

I’ve never written a line of .NET but the answer looks pretty obvious:

Apparently in .NET abstract classes don’t get registered unless an implementing class has already been instanced.

I think you are in a life-and-death struggle with the language model, @Arkady_Levin :slight_smile: