I have a class with some read only properties that I want to store using mongodb.
User.cs
public class User: ValueObject<User>
    {
        public UserId Id { get; }
        public string Firstname { get; }
        public string Lastname { get; }
        public User(UserId id, string firstname, string lastname)
        {
            Id = new UserId(id.Id);
            Firstname = firstname;
            Lastname = lastname;
        }
        public User(string id, string firstname, string lastname)
        {
            Id = new UserId(id);
            Firstname = firstname;
            Lastname = lastname;
        }
        protected override bool MembersEquals(User other)
        {
            return Id == other.Id && Firstname == other.Firstname && Lastname == other.Lastname;
        }
        protected override int MembersHashCode()
        {
            return Id.GetHashCode() ^ Firstname.GetHashCode() ^ Lastname.GetHashCode();
        }
    }
Class map registration:
BsonClassMap.RegisterClassMap<User>(cm =>
            {
                cm.AutoMap();
                cm.MapProperty(user => user.Id);
                cm.MapProperty(user => user.Firstname);
                cm.MapProperty(user => user.Lastname);
                cm.MapCreator(user => new User(user.Id, user.Firstname, user.Lastname));
            });
this class is stored as a subdocument. when i try to store the whole document mongodb driver tell me that the MongoDB.Bson.BsonSerializationException: Creator map for class Box.Domain.User has 3 arguments, but none are configured.. I didn't really understand what does it mean.
NB: the UserId class has a registred serializer
public class UserIdBsonSerializer : SerializerBase<UserId>
    {
        public override UserId Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
        {
            var currentBsonType = context.Reader.GetCurrentBsonType();
            return currentBsonType switch
            {
                BsonType.String => new UserId(context.Reader.ReadString()),
                _ => throw new NotSupportedException($"Cannot deserialize {currentBsonType} to an UserId")
            };
        }
        public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, UserId value)
        {
            context.Writer.WriteString(value.Id);
        }
    }
EDIT
ValueObject.cs
public abstract class ValueObject<T> : IEquatable<T>
        where T : ValueObject<T>
    {
        // Verify the value object members equality.
        protected abstract bool MembersEquals(T other);
        // Generate a hash code depending on the value object members values.
        protected abstract int MembersHashCode();
        #region Equality
        public bool Equals([AllowNull] T other)
        {
            if (ReferenceEquals(other, null))
                return false;
            if (ReferenceEquals(this, other))
                return true;
            return MembersEquals(other);
        }
        public override bool Equals(object obj)
        {
            var other = obj as T;
            return Equals(other);
        }
        public static bool operator ==(ValueObject<T> lhs, ValueObject<T> rhs)
        {
            if (ReferenceEquals(lhs, null) && ReferenceEquals(rhs, null))
                return true;
            if (ReferenceEquals(lhs, null))
                return false;
            return lhs.Equals(rhs);
        }
        public static bool operator !=(ValueObject<T> lhs, ValueObject<T> rhs) => !(lhs == rhs);
        #endregion
        public override int GetHashCode()
        {
            return MembersHashCode();
        }
    }
UserId.cs
public class UserId: ValueObject<UserId>
    {
        public string Id { get; }
        public UserId(string id)
        {
            if (id.Length < 5)
                throw new ArgumentException($"user id must be 5 characters length. {id}");
            // TODO: Add more validation rules for user id
            Id = id;
        }
        protected override bool MembersEquals(UserId other)
        {
            return Id == other.Id;
        }
        protected override int MembersHashCode()
        {
            return Id.GetHashCode();
        }
    }
                Looks like the cm.AutoMap(); in your register class map is creating 2 creators before adding your own.
If you remove that it'll start working.
BsonClassMap.RegisterClassMap<User>(cm =>
            {
                cm.MapProperty(user => user.Id);
                cm.MapProperty(user => user.Firstname);
                cm.MapProperty(user => user.Lastname);
                cm.MapCreator(user => new User(user.Id, user.Firstname, user.Lastname));
            });
An alternative would be to remove the ImmutableTypeClassMapConvention from the default convention pack.
ConventionRegistry.Remove("__defaults__");
var pack = new ConventionPack();
var defaultConventions = DefaultConventionPack.Instance.Conventions;
pack.AddRange(defaultConventions.Except(
    defaultConventions.OfType<ImmutableTypeClassMapConvention>()
    ));
ConventionRegistry.Register(
    "__defaults__",
    pack,
    t => true);
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With