DEV Community

LuisNogal
LuisNogal

Posted on • Edited on

How to use Hashids with AutoMapper

Why to use Hashids?

Hashids helps you to convert a number Id to a string, this can make your app a little more secure hiding the actual id or related key of your DB when the data is requested by an API.

Why is useful ValueConverter of AutoMapper?

ValueConverter can handle the convertion inside te .Map<TDestination>(source) method allowing you put the convertion logic in only one place.

The model

//Model of your data
public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int ClassEnrollmentId { get; set; }
}

//Data Transfer Object (DTO) for your client
public class StudentDto
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string ClassEnrollmentId { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

The configuration

After you install the nuget packages:

  • Install-Package hashids.net
  • Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection

Add the following code to the Program.cs to use hashids and AutoMapper with dependency injection, if you prefer to use a class Startup you have to put it on the ConfigureServices method.

builder.Services.AddSingleton<IHashids>(_ => 
new Hashids("this is my salt"));
// Optional, you can set the length of the string 
// new Hashids("this is my salt", [the number you want])

builder.Services.AddAutoMapper(typeof(AutoMapperProfile));
Enter fullscreen mode Exit fullscreen mode

AutoMapperProfile

using AutoMapper; // To use the Profile class

public class AutoMapperProfile: Profile
{
    public AutoMapperProfile()
    {
        //This configuration convert the int property who saves Ids to hash string
        CreateMap<Student, StudentDto>()
            .ForMember(d => d.Id, opt => opt.ConvertUsing<HashFormatter, int>())
            .ForMember(d => d.ClassEnrollmentId, opt => opt.ConvertUsing<HashFormatter, int>());


        //This configuration makes the oposite from the above configuration
        CreateMap<StudentDto, Student>()
            .ForMember(d => d.Id, opt => opt.ConvertUsing<IntFromHash, string>())
            .ForMember(d => d.ClassEnrollmentId, opt => opt.ConvertUsing<IntFromHash, string>());
    }
}
Enter fullscreen mode Exit fullscreen mode

Convertion classes

using AutoMapper; //To use IValueConverter interface
using HashidsNet; //To use IHashids interface

public class HashFormatter : IValueConverter<int, string>
{
    private readonly IHashids hashids;

    public HashFormatter(IHashids hashids)
    {
        this.hashids = hashids;
    }

    public string Convert(int source, ResolutionContext context)
    {
        return hashids.Encode(source);
    }
}
public class IntFromHash : IValueConverter<string, int>
{
    private readonly IHashids hashids;

    public IntFromHash(IHashids hashids)
    {
        this.hashids = hashids;
    }

    public int Convert(string source, ResolutionContext context)
    {
        return hashids.DecodeSingle(source);
    }
}
Enter fullscreen mode Exit fullscreen mode

How to use it

In a controller only have to inject AutoMapper and call the .Map method like this.

public class StudentstController : ControllerBase
{
    private readonly IMapper mapper;

    public StudentstController(IMapper mapper)
    {
        this.mapper = mapper;
    }

    [HttpGet]
    public IActionResult Get()
    {
        //Summaries is the data as List<Student>
        return Ok(mapper.Map<List<StudentDto>>(Summaries));
    }
}
Enter fullscreen mode Exit fullscreen mode

Result

Data without hash

[
  {
    "id": 1,
    "name": "Juan",
    "classEnrollmentId": 2
  },
  {
    "id": 2,
    "name": "Pedro",
    "classEnrollmentId": 1
  }
]
Enter fullscreen mode Exit fullscreen mode

Data with hash

[
  {
    "id": "NV",
    "name": "Juan",
    "classEnrollmentId": "6m"
  },
  {
    "id": "6m",
    "name": "Pedro",
    "classEnrollmentId": "NV"
  }
]
Enter fullscreen mode Exit fullscreen mode

Thank you so much for reading this, I hope this be helpful.

Top comments (2)

Collapse
 
cuonghbu2011 profile image
coung • Edited

Thank you so much for sharing!
Just a very small spelling. inject or inyect, AutoMapper not autommaper.

Collapse
 
luisnogal profile image
LuisNogal

Thank you! It's corrected now.