2020年7月14日 星期二

[AutoMapper] Custom Type and Value converter


 .NET Core   .NET   AutoMapper 


Introduction


We can implement the following AutoMapper’s interface to customize the Type or Value converter:


This article will show a few samples for how to use them.


Environment


AutoMapper 8.0.0


Implement


We are going to convert a MyClass1 object to MyClas2 object, that the classes are like following,


MyClass1

public class MyClass1 {
        public string Amount { getset; }
        public string PayDate { getset; }
        public string PayTime { getset; }
    }


MyClass2

public class MyClass2 {
        public decimal Amount { getset; }
        public DateTime PayOn { getset; }
    }



ITypeConverter

If the source and destination classes have too many differences to map their properties, we can implement ITypeConverter to put all the convert logic inside.


public class MyConverter : ITypeConverter<MyClass1MyClass2>
{
    public DtoMerchantCreation Convert(MyClass1 sourceMyClass2 destinationResolutionContext context)
    {
        // Convert MyClass1 instance to MyClass2
    }
}


Usage:

var configuration = new MapperConfiguration(cfg => {
                cfg.CreateMap<MyClass1MyClass2>().ConvertUsing<MyConverter>();
            });




IValueConverter


Implement IValueConverter if the destination property’s value comes from a single property of the source.



public class AmountConverter : IValueConverter<stringdecimal>
{
    public decimal Convert(string sourceMemberResolutionContext context)
    {
         // Convert string to decimal
    }
}


Usage:

var configuration = new MapperConfiguration(cfg => {
        cfg.CreateMap<MyClass1MyClass2>()
                    .ForMember(dest => dest.Amountopt => opt.ConvertUsing(new AmountConverter()));

});



IValueResolver


Implement IValueResolver if the destination property’s value comes from multiple properties of the source.



public class PayOnResolver : IValueResolver<MyClass1MyClass2DateTime>
{
    public DateTime Resolve(MyClass1 sourceMyClass2 destinationDateTime destMemberResolutionContext context)
    {
        string dateTimeStr = $"{source.PayDate} {source.PayTime}+08:00"// e.q. "2020-03-10 08:00:00+08:00"
        return Convert.ToDateTime(dateTimeStr);
    }
}


Usage:

var configuration = new MapperConfiguration(cfg => {
        cfg.CreateMap<MyClass1MyClass2>()
                    .ForMember(dest => dest.PayOnopt => 
                               opt.MapFrom<PayOnResolver>())
});



Notice that if we have the other class: MyClassA, which inherits MyClass1

public class MyClassA : MyClass1 {
    }

Then it can also reuse the PayOnResolver as well. For example,

var configuration = new MapperConfiguration(cfg => {
        cfg.CreateMap<MyClassAMyClass2>()
                    .ForMember(dest => dest.PayOnopt => 
                               opt.MapFrom<PayOnResolver>())
});



Reference