Use Automapper to hide database primary key/ID (convert member with ValueConverter)

268 Views Asked by At

I am trying to hide the real Ids of the objects in a database using Automapper's value converters, however they are not called when projecting one to the other.

Nothing special, I would like to use Hashids to convert the int ID to a random string ID (DB->DTO) and vice versa. I want to do this for every object and every ID, but instead of my converter getting called the id's in the database simply get converted strings (so 1 would become "1" instead of for example "sd2+a!F").

My Class:

public class Category
{
    public Category(string name)
    {
        Name = name;
    }

    public int Id { get; set; }
    public string Name { get; set; }

    public int? ParentCategoryId { get; set; }
    public Category? ParentCategory { get; set; }

    public ICollection<Foodstuff> Foodstuffs { get; } = new List<Foodstuff>();

    public ICollection<int> FoodstuffIds { get; } = new List<int>();

    public byte[] RowVersion { get; set; }

}

My DTO:

public record class Category : IGenerateETag
{
    public Category(string name)
    {
        Name = name;
    }

    public string Id { get; init; }

    [Required(ErrorMessage = "Category name is required.", AllowEmptyStrings = false)]
    public string Name { get; init; }

    public string? ParentCategoryId { get; init; }

    public byte[] RowVersion { get; set; }
}

My converters:

public class HideIdConverter : IValueConverter<int, string>
{

    public string Convert(int sourceMember, ResolutionContext context)
    {
        var hashids = new Hashids();
        var shadow = hashids.Encode(sourceMember);
        return shadow;
    }
}


public class UnhideIdConverter : IValueConverter<string, int>
{

    public int Convert(string sourceMember, ResolutionContext context)
    {
        var hashids = new Hashids();
        var plain = hashids.Decode(sourceMember);
        return plain[0]; // TODO check this;
    }
}

Aaand my Automapper config:

CreateMap<Dal.Entities.Category, Category>()
    .ForMember(dest => dest.Id, opt => opt.ConvertUsing(new HideIdConverter(), src => src.Id))
    .ReverseMap()
    .ForMember(dest => dest.Id, opt => opt.ConvertUsing(new UnhideIdConverter(), src => src.Id));
1

There are 1 best solutions below

0
MoltenEQ On

It turns out that it this is not possible, because I was using LINQ expressions, especially ProjectTo(). It is stated that:

Value converters are only used for in-memory mapping execution. They will not work for ProjectTo.

Source.

I guess I will have to map the objects after I queried them from my database.