16

When I try to map an object that has a null string property, the destination is also null. Is there a global settings I can turn on that says all null string should be mapped to empty?

4 Answers 4

27

Something like this should work:

public class NullStringConverter : ITypeConverter<string, string>
  {
    public string Convert(string source)
    {
      return source ?? string.Empty;
    }
  }

And in your configuration class:

public class AutoMapperConfiguration
{
    public static void Configure()
    {
        Mapper.CreateMap<string, string>().ConvertUsing<NullStringConverter>();

        Mapper.AddProfile(new SomeViewModelMapper());
        Mapper.AddProfile(new SomeOtherViewModelMapper());
        ...
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

What is: Mapper.AddProfile(new SomeViewModelMapper());? Is this something where I can add multiple mappers?
20

If you need a non-global setting, and want to do it per property:

Mapper.CreateMap<X, Y>()
.ForMember(
    dest => dest.FieldA,
    opt => opt.NullSubstitute(string.Empty)
);

Comments

14

Similar to David Wick's answer, you can also use ConvertUsing with a lambda expression, which eliminates the requirement for an additional class.

Mapper.CreateMap<string, string>().ConvertUsing(s => s ?? string.Empty);

Comments

0

I'm using EF Reverse Engineering and it has a nasty habit of defining

string Name { get; set; } = null!;

The null on a non-nullable string causes many headaches. Finally, I added this mapping function and created "ghost" intermediate objects to absorb the mapping.

/// <inheritdoc />
[PublicAPI]
internal class MapperProfile<TSrcType, TDstType> : Profile
    where TSrcType : class
    where TDstType : class, new()
{
    public MapperProfile()
    {
        CreateMap<TSrcType, TDstType>(MemberList.None)
            .ConvertUsing((src, dst) =>
            {
                ArgumentNullException.ThrowIfNull(src);
                dst ??= new TDstType();

                var dstType = dst.GetType()!;
                var srcType = src.GetType()!;

                foreach (var dstInfo in dstType.GetProperties()
                    .Where(x => x.CanWrite)
                    .Select(x => dstType.GetProperty(x.Name)!))
                {
                    var srcInfo = srcType.GetProperties()
                        .SingleOrDefault(info => info.Name == dstType.Name && info.CanRead);

                    try
                    {
                        var value = (srcInfo is not null)
                            ? srcInfo.GetValue(src, null)
                            : dstInfo.CanRead
                                ? dstInfo.GetValue(dst, null)
                                : dstInfo.PropertyType.IsValueType
                                    ? Activator.CreateInstance(dstInfo.PropertyType)
                                    : null;   // I give up..., anyone have an idea?

                        if (dstInfo.PropertyType == typeof(string))
                            value ??= string.Empty;

                        dstInfo.SetValue(dst, value);
                    }
                    catch (Exception e)
                    {
                        Trace.WriteLine(e);
                        Debugger.Break();
                    }
                }

                return dst;
            });
    }
}

You may wish to further qualify which strings get remapped. I used the NotNullAttribute, and I had control of the sources so adding it to those strings that I wanted to insure non-null-ness was fairly easy.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.