Automapper null string to empty
Asked Answered
F

4

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?

Formative answered 3/10, 2011 at 22:16 Comment(0)
H
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());
        ...
    }
}
Hin answered 3/10, 2011 at 22:32 Comment(1)
What is: Mapper.AddProfile(new SomeViewModelMapper());? Is this something where I can add multiple mappers?Formative
R
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)
);
Remington answered 10/5, 2013 at 6:18 Comment(0)
H
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);
Hue answered 15/4, 2014 at 14:8 Comment(0)
S
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.

Stagnant answered 4/3 at 15:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.