Question

I am trying to do something like this:

AutoMapper.Mapper.CreateMap<UrlPickerState, Link>()
        .ForMember(m=>m.OpenInNewWindow,map=>map.MapFrom(s=>s.NewWindow))
        .AfterMap((picker, link) => link = !string.IsNullOrWhiteSpace(link.Url)?link:null) ;

var pickerState = new UrlPickerState();
var linkOutput = AutoMapper.Mapper.Map<Link>(pickerState);

However, the assigned value of link is not used in any execution path.
I would like linkOutput to be null, but it is not.
How would I make the destination object null?

Details of objects involved:

public class Link
{
    public string Title { get; set; }
    public string Url { get; set; }
    public bool OpenInNewWindow { get; set; }
}

public class UrlPickerState
{
    public string Title { get; set; }
    public string Url { get; set; }
    public bool NewWindow { get; set; }
    //.... etc
}

Here's a fiddle: http://dotnetfiddle.net/hy2nIa

Was it helpful?

Solution 2

I created the following extension method to solve this problem.

public static IMappingExpression<TSource, TDestination> PreCondition<TSource, TDestination>(
   this IMappingExpression<TSource, TDestination> mapping
 , Func<TSource, bool> condition
)
   where TDestination : new()
{
   // This will configure the mapping to return null if the source object condition fails
   mapping.ConstructUsing(
      src => condition(src)
         ? new TDestination()
         : default(TDestination)
   );

   // This will configure the mapping to ignore all member mappings to the null destination object
   mapping.ForAllMembers(opt => opt.PreCondition(condition));

   return mapping;
}

For the case in question, it can be used like this:

Mapper.CreateMap<UrlPickerState, Link>()
      .ForMember(dest => dest.OpenInNewWindow, opt => opt.MapFrom(src => src.NewWindow))
      .PreCondition(src => !string.IsNullOrWhiteSpace(src.Url));

Now, if the condition fails, the mapper will return null; otherwise, it will return the mapped object.

OTHER TIPS

This is the solution I used in the end, it was a bit more manual internally, but does not require any extra plumbing.

If anyone has a more elegant solution, it would be appreciated.

config.CreateMap<UrlPickerState, Link>()
            .ConvertUsing(arg =>
            {
                if (string.IsNullOrWhiteSpace(arg.Url))
                {
                    return null;
                }
                return new Link()
                {
                    Url = arg.Url,
                    OpenInNewWindow = arg.NewWindow,
                    Title = arg.Title,
                };
            });

I think that will have to be done outside the mapping. Since AutoMapper requires an instance to map to, setting the destination to null seems like it should go outside the mapping.

I would instead do something like:

AutoMapper.Mapper.CreateMap<UrlPickerState, Link>()
        .ForMember(m=>m.OpenInNewWindow,map=>map.MapFrom(s=>s.NewWindow));

var pickerState = new UrlPickerState();
Link linkOutput = null;
if(!string.IsNullOrWhiteSpace(pickerState.Url))  // or whatever condition is appropriate
    linkOutput = AutoMapper.Mapper.Map<Link>(pickerState);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top