sebd
sebd

Reputation: 612

Using Profiles in Automapper to map the same types with different logic

I am using AutoMapper in my ASP.NET MVC website to map my database objects to ViewModel objects and I am trying to use several profiles to map the same types, but using another logic. I had the idea of doing so by reading Matt's blog post where he says:

The really key part is the AutoMapper configuration profile. You can group configurations with profiles. Maybe in one profile you format dates in one way, in another profile you format dates in another way. I’m just using one profile here.

So I created a profile for one case:

public class MyProfile : Profile
{
    protected override string ProfileName
    {
        get
        {
            return "MyProfile";
        }
    }

    protected override void Configure()
    {
        CreateMap<DateTime, String>().ConvertUsing<StringFromDateTimeTypeConverter>();
    }
}

public class StringFromDateTimeTypeConverter : ITypeConverter<DateTime, String>
{
    public string Convert(DateTime source)
    {
        return source.ToString("dd/mm/yyyy", CultureInfo.InvariantCulture);
    }
}

And another one for another case:

public class MyProfile2 : Profile
{
    protected override string ProfileName
    {
        get
        {
            return "MyProfile2";
        }
    }

    protected override void Configure()
    {
        CreateMap<DateTime, String>().ConvertUsing<AnotherStringFromDateTimeTypeConverter>();
    }
}

public class AnotherStringFromDateTimeTypeConverter : ITypeConverter<DateTime, String>
{
    public string Convert(DateTime source)
    {
        return source.ToString("mm - yyyy", CultureInfo.InvariantCulture);
    }
}

However, I cannot find any overload of the Mapper.Map<>() method to specify a profile. I also had a look at the Configuration object with no luck.
The last registered profile always takes precedence.

Is there a way to use profiles for this purpose?

Upvotes: 52

Views: 51983

Answers (2)

Batibot323
Batibot323

Reputation: 93

As of AutoMapper v10. You need to instantiate an IMapper that uses the the specific Profile that you wanted. Something like this:

MapperConfiguration config = new MapperConfiguration(cfg => {
    cfg.AddProfile(new MyProfile());
});
IMapper mapper = new Mapper(config);
var myHuman = mapper.map<Human>(myPerson);

Example that can map a Person to a Human with either a Name that is lowercase or uppercase.

class Program
{
    static void Main(string[] args)
    {
        Person myPerson = new Person
        {
            Name = "HAzEL NUtt"
        };
        Console.WriteLine(myPerson.Name);

        MapperConfiguration configUpper = new MapperConfiguration(cfg => {
            cfg.AddProfile(new UpperCaseProfile());
        });
        IMapper mapperUpper = new Mapper(configUpper);
        Console.WriteLine(mapperUpper.Map<Human>(myPerson).Name);

        MapperConfiguration configLower = new MapperConfiguration(cfg => {
            cfg.AddProfile(new LowerCaseProfile());
        });
        IMapper mapperLower = new Mapper(configLower);
        Console.WriteLine(mapperLower.Map<Human>(myPerson).Name);
    }
}

public class LowerCaseProfile : Profile
{
    public LowerCaseProfile()
    {
        CreateMap<Person, Human>()
                .ForMember(d => d.Name, opt => opt.MapFrom(src => src.Name.ToLower()));
    }
}

public class UpperCaseProfile : Profile
{
    public UpperCaseProfile()
    {
        CreateMap<Person, Human>()
            .ForMember(d => d.Name, opt => opt.MapFrom(src => src.Name.ToUpper()));
    }
}

Here is the output:

HAzEL NUtt
HAZEL NUTT
hazel nutt

Upvotes: 5

Jimmy Bogard
Jimmy Bogard

Reputation: 26765

Profiles are for segregating common configuration applied across several type maps, like formatting. However, type maps are still global. You're better off creating separate Configuration objects, and creating a separate MappingEngine for each. The Mapper class is merely a static facade over each of those, with some lifecycle management.

Upvotes: 51

Related Questions