0

I am currently using Automapper (8.0.0) in my .net core (2.1) api project. Below is my sample of code to simulate an update process of my dto mapping to my database object. I wish to have automapper ignore mapping of null object in Dto.

using AutoMapper;
using System;

namespace testAutoMapper
{
public class SourceObject
{
    public bool TestReverseFalse { get; set; }
    public bool TestReverseTrue { get; set; }
    public bool IFalse { get; set; }
    public bool ITrue { get; set; }
    public int TestInteger { get; set; }
    public int TestNullInteger { get; set; }
}

public class ModelObject
{
    public bool? TestReverseFalse { get; set; }
    public bool? TestReverseTrue { get; set; }
    public bool? IFalse { get; set; }
    public bool? ITrue { get; set; }
    public int? TestInteger { get; set; }
    public int? TestNullInteger { get; set; }
}

public class Program
{
    public static void Main(string[] args)
    {
        AutoMapper.Mapper.Initialize(mapper =>
        {
            //global ignore for all
            //mapper.ForAllMaps((tm, me) => me.ForAllMembers(option => option.Condition((src, destination, sourceMember) => sourceMember != null)));

            mapper.CreateMap<ModelObject, SourceObject>().ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null));
        });

        var model = new ModelObject
        {
            TestReverseFalse = true,
            TestReverseTrue = false,

        };
        var source = new SourceObject
        {
            TestReverseFalse = false,
            TestReverseTrue = true,
            ITrue = true,
            IFalse = false,
            TestInteger = 100,
            TestNullInteger = 100
        };

        Console.WriteLine("Source Before Mapping");
        Console.WriteLine("TestReverseFalse: " + source.TestReverseFalse);
        Console.WriteLine("TestReverseTrue: " + source.TestReverseTrue);
        Console.WriteLine("ITrue:" + source.ITrue);
        Console.WriteLine("IFalse:" + source.IFalse);
        Console.WriteLine("TestInteger:" + source.TestInteger);
        Console.WriteLine("TestNullInteger:" + source.TestNullInteger);


        Mapper.Map(model, source);

        Console.WriteLine();
        Console.WriteLine("After Mapping");
        Console.WriteLine("TestReverseFalse: " + source.TestReverseFalse);
        Console.WriteLine("TestReverseTrue: " + source.TestReverseTrue);
        Console.WriteLine("ITrue:" + source.ITrue);
        Console.WriteLine("IFalse:" + source.IFalse);
        Console.WriteLine("TestInteger:" + source.TestInteger);
        Console.WriteLine("TestNullInteger:" + source.TestNullInteger);
        Console.ReadLine();
    }
}

}

The sample output


Source Before Mapping
TestReverseFalse: False
TestReverseTrue: True
ITrue:True
IFalse:False
TestInteger:100
TestNullInteger:100

After Mapping
TestReverseFalse: True
TestReverseTrue: False
ITrue:False
IFalse:False
TestInteger:0
TestNullInteger:0

I found my source object being reset to its default value. Not sure which part I did wrong.

tchuat
  • 11
  • 2
  • 1
    have you tried to use IgnoreNullResolver like here https://stackoverflow.com/a/44986528/4353251 – Lorenzo Isidori Mar 13 '19 at 09:00
  • Thanks @LorenzoIsidori The solution doesn't seem work for version 8. I had also make a reference to https://github.com/AutoMapper/AutoMapper/issues/2999#issuecomment-472692335 – tchuat Mar 14 '19 at 06:18

1 Answers1

1

Use a custom resolver that null checks to fix this issue. Replace your initialize with this:

Initialize:

Mapper.Initialize(mapper =>
{
    mapper.ForAllPropertyMaps(pm => true /*Whether to use this resolver. This returning true means it's always used*/, (pm, c) => c.MapFrom<NonNullOnlyResolver, object>(pm.SourceMember.Name));

    mapper.CreateMap<ModelObject, SourceObject>();
});

Resolver:

class NonNullOnlyResolver : IMemberValueResolver<object, object, object, object>
{
    public object Resolve(object source, object destination, object sourceMember, object destMember, ResolutionContext context)
    {
        return sourceMember ?? destMember;
    }
}

Output after my changes:

Source Before Mapping
TestReverseFalse: False
TestReverseTrue: True
ITrue:True
IFalse:False
TestInteger:100
TestNullInteger:100

After Mapping
TestReverseFalse: True
TestReverseTrue: False
ITrue:True
IFalse:False
TestInteger:100
TestNullInteger:100
marksfrancis
  • 1,722
  • 1
  • 13
  • 14
  • 1
    Using this resolver always (`pm => true`) breaks some complex maps, or even simple ones, when source type doesn't have all properties of destination type. I ended up applying it only for nullable types, like @tchuat posted [in this issue](https://github.com/AutoMapper/AutoMapper/issues/2999#issuecomment-472692335) – Ivan Sveshnikov May 11 '20 at 13:03