0

In the following example (executable in LinqPad), MyString becomes "Hello World".

However, if I uncomment cfg.ForAllMaps then it is just "Hello", it apparently overrides any custom settings.

I'm hoping to use cfg.ForAllMaps to set a bunch of common rules e.g a property which exists on the source with a wildly different name to the destination but follows a common pattern i.e. Person_Age in a Source DTO, would match the Age property on a destination type called Person and Animal_Age matches Animal.Age etc. On top of this, the Person type may have specific customisations which I'd wish to do.

Is ForAllMaps meant to override all other settings? If so, is it possible to use it in the manner I'm hoping i.e. having a baseline config which can be overridden? Or is there an alternative API I should be using (I've been poking around but not found anything so far)?

void Main()
{
    var config = new MapperConfiguration(cfg =>
    {
        //Uncomment this and ForCtorParam override does not work
//      cfg.ForAllMaps((typeMap, map) =>
//      {
//      });

        cfg.CreateMap<Source, Destination>()
            .ForCtorParam("myString", x => x.MapFrom(y => $"{y.MyString} World"));
    });

    config.AssertConfigurationIsValid();

    var mapper = config.CreateMapper();

    var source = new Source()
    {
        MyString = "Hello"
    };

    var dest = mapper.Map<Destination>(source);

    dest.Dump();
}

public class Source 
{
    public string MyString { get; set; }
}

public class Destination 
{
    public string MyString {get; private set;}

    public Destination(string myString)
    {
        this.MyString = myString;
    }
}

Further information:

As an aside here is the sort of function I'm executing inside of the ForAllMaps:

void SetupMemberAndRenamedContructorParameter<T>(TypeMap typeMap, IMappingExpression map, string sourcePropertyName, string destinationPropertyName, string destinationContructorParamaterName)
{
    map.ForMember(destinationPropertyName, x => x.MapFrom(sourcePropertyName));

    var propertyInfo = (PropertyInfo)typeMap.SourceTypeDetails.PublicReadAccessors.Single(w => w.Name == sourcePropertyName);

    Expression<Func<object, T>> getValue = (sourceClassInstance) => (T)propertyInfo.GetValue(sourceClassInstance);

    map.ForCtorParam(destinationContructorParamaterName, x => x.MapFrom(getValue));
}

cfg.ForAllMaps((typeMap, map) =>
{
    SetupMemberAndRenamedContructorParameter<string>(typeMap, map, $"{typeMap.DestinationType.Name.ToUpper()}_ERROR", "ErrorCode", "errorCode");
    SetupMemberAndRenamedContructorParameter<int>(typeMap, map, $"{typeMap.DestinationType.Name.ToUpper()}_RATING", "Flag", "flag");
});

To clarify my primary question is in regard to whether ForAllMaps overrides CreateMap() and whether there is a way to get both to work nicely together, my secondary example may be a distraction.

Alex KeySmith
  • 16,657
  • 11
  • 74
  • 152
  • The summary comment on ForAllMaps is _"Specify common configuration **for all type maps**."_. Can you explain more about what you're trying to achieve? – stuartd Oct 29 '19 at 18:11
  • Hi @stuartd thanks for the interest I've added some more detail. – Alex KeySmith Oct 29 '19 at 18:16
  • Ah, that's a tricky one. You're deriving both the target class and property name from the source property name? – stuartd Oct 29 '19 at 18:25
  • A tricky one indeed :-) Yes for the target property, but as all classes have follow the pattern I can take some short cuts with string concatenation. I was rather pleased with myself when working it out, then realised ForAllMaps is breaking my per type config. – Alex KeySmith Oct 29 '19 at 18:40
  • See http://docs.automapper.org/en/latest/Reverse-Mapping-and-Unflattening.html. You can write a custom naming convention. – Lucian Bargaoanu Oct 30 '19 at 05:31
  • Thanks @LucianBargaoanu the link was to the "Reverse Mapping and Flattening" section of the docs, was that purposeful? If so perhaps I'm missing a subtly in how to use it here, could you elaborate please? I've looked at the http://docs.automapper.org/en/latest/Configuration.html#naming-conventions and INamingConvention but I'd need to pass in the destinations Type name, the naming conventions seemed to be static (n.b. not static in the c# sense). – Alex KeySmith Oct 30 '19 at 09:36
  • Check the docs and the tests. It seems to me that you want unflattening, but, as the docs say, you get that only by reversing a map that flattens. – Lucian Bargaoanu Oct 30 '19 at 10:06
  • Thanks for the clarification @LucianBargaoanu . I see, sorry my example code above doesn't demonstrate what I'm hoping to achieve with ForAllMaps, it's purely to demonstrate that ForAllMaps seems to override anything else created for CreateMap(). I suppose my question wasn't really regarding the mapping as such more in that of confirming whether there was a way to do things with ForAllMaps that doesn't kill CreateMap()? – Alex KeySmith Oct 30 '19 at 10:48
  • You just have to check whether there are some things already configured. But that's not part of the API. You're free to do it nevertheless :) Check also `ForAllPropertyMaps`. – Lucian Bargaoanu Oct 30 '19 at 10:55
  • Thanks @LucianBargaoanu I'll try out ForAllPropertyMaps and continue my adventures! :-) – Alex KeySmith Oct 30 '19 at 10:56

0 Answers0