37

ForAllOtherMembers extension method was removed from Automapper 11 I use it to ignore conventional mappings for properties other than the one mentioned before like this

ForAllOtherMembers(opt=>opt.ignore())

How to do this in Automapper 11 ?

3 Answers3

15

I will never ever change even a single line in my code simply because the authors of AutoMapper decided that its not a "right" thing to do for whatever "reason".

Quick and dirty solution, makes sense to add a unit test:

using AutoMapper.Internal;
using AutoMapper.Configuration;

public static class AutoMapperExtensions
{
    private static readonly PropertyInfo TypeMapActionsProperty = typeof(TypeMapConfiguration).GetProperty("TypeMapActions", BindingFlags.NonPublic | BindingFlags.Instance);

    // not needed in AutoMapper 12.0.1
    private static readonly PropertyInfo DestinationTypeDetailsProperty = typeof(TypeMap).GetProperty("DestinationTypeDetails", BindingFlags.NonPublic | BindingFlags.Instance);

    public static void ForAllOtherMembers<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression, Action<IMemberConfigurationExpression<TSource, TDestination, object>> memberOptions)
    {
        var typeMapConfiguration = (TypeMapConfiguration)expression;

        var typeMapActions = (List<Action<TypeMap>>)TypeMapActionsProperty.GetValue(typeMapConfiguration);

        typeMapActions.Add(typeMap =>
        {
            var destinationTypeDetails = (TypeDetails)DestinationTypeDetailsProperty.GetValue(typeMap);

            foreach (var accessor in destinationTypeDetails.WriteAccessors.Where(m => typeMapConfiguration.GetDestinationMemberConfiguration(m) == null))
            {
                expression.ForMember(accessor.Name, memberOptions);
            }
        });
    }
}
kemsky
  • 14,727
  • 3
  • 32
  • 51
  • 3
    Seems like a completely unnecessary high horse. The reason given for the deprecation is `That was used to disable mapping by convention, not something we want to support. When only used for validation, it can be replaced with MemberList.None.` Unless there's a technical reason why it can't work any more it should have just been deprecated instead. My problem is any usage I have of this worked just fine for over 3 years - sometimes I don't want properties mapped and frankly I've forgotten how I did it. Maybe it will reveal mistakes in my code but fortunately I only used it a couple times. – Simon_Weaver Nov 12 '22 at 04:04
  • 6
    Even more, AutoMapper 10.X.X has a bug that prevents upgrade to .NET 7, so you are forced to update AutoMapper to the version which contains breaking changes. – kemsky Nov 14 '22 at 11:17
  • 2
    that's exactly what led me here (and why I was a bit annoyed by it!). When I'm busy testing everything else for a .NET update an AutoMapper change is the last thing I want to deal with. Turned out not to be too bad. I only had it in one place and since I knew the code worked I just removed it. I wasn't validating the model at runtime so it was safe. Honestly what annoyed me the most was the suggestion in the upgrade guide to use `MemberList.None` without any example code. I've never used that before! Is it the same? Subtlely different. I think I got away with it it for now! – Simon_Weaver Nov 15 '22 at 20:57
  • @Simon_Weaver were yo uable to fix it? I keep getting a null reference exception at runtime. Doe this mean that a field that was previously working will now fail due to the upgrade and i have to explicitly map it? – sam Nov 28 '22 at 16:19
  • 1
    Thanks! For anyone using this you'll need to add `using AutoMapper.Internal` and `using AutoMapper.Configuration`. VisualStudio doesn't suggest these for whatever reason – p3tch Dec 02 '22 at 10:16
  • 4
    The code reads, that `DestinationTypeDetailsProperty` is not needed for Automapper 12+. In newer versions, that property is made public. So replace the line using this property with `var destinationTypeDetails = typeMap.DestinationTypeDetails;`. – Mike Jan 29 '23 at 09:23
  • We have over 100 projects with a lot of mappings and changing to a higher automapper version (> 10) would break so much business code. Here is a solution for all sad devs which use automapper 10, want to stay on this version (keep the mappings as is) and updated to dotnet7: during creation of the automapper config (`IMapperConfigurationExpression`) you should set `config.ShouldMapMethod = _ => false;` to disable mapping to methods. Here is a lengthy explanation why this was broken with the update of dotnet: https://github.com/AutoMapper/AutoMapper/issues/3988 – SeriousM Mar 30 '23 at 13:03
  • 1
    @SeriousM, in the long term I would recommend to move away from this library because maintenance has already became unbearable. – kemsky Mar 30 '23 at 16:02
0

You can set this on the CreateMap call:

CreateMap<TSource, TDest>(MemberList.None)
Felix Planjer
  • 89
  • 1
  • 6
  • 3
    This doesn't address the other properties that are mapped before the now-removed ForAllOtherMembers call though, correct? – G_P Apr 14 '22 at 14:27
  • 1
    As the code summary stands, `MemberList` is an enum to tell what to check for configuration validation. It can be Destination, Source or None. So specifying MemberList.None will tell AutoMapper not to validate the mapping of any member of the Source nor of the Destination, which is what we often seek when using `ForAllOtherMembers(opt=>opt.ignore())` – Adrien Desfarges May 02 '22 at 20:22
  • 8
    In my experience, this will **not** prevent mapping from occurring like `ForAllOtherMembers(opt=>opt.ignore())` used to. It will just prevent the profile from detecting that fields are being mapped. Exact-matching field names will still be auto-mapped unless ignored. Try it yourself by unit testing whether fields with identical names get auto-mapped when `MemberList.None` is set on the map. – nbrosz Jun 28 '22 at 16:38
0

MemberList.None does not prevent auto-mapped properties with the same member names.

I also tried some other solutions to find the map for the given profile and change the property map to ignore for unmapped property names, however this did not work since the properties were already considered to be mapped.

The unfortunate answer to this problem for me was to use a CustomTypeConverter

public class OrderTypeConverter : ITypeConverter<ThirdPartyOrder, MyOrder>
{
    public Order.Order Convert(ThirdPartyOrder source, MyOrder destination, ResolutionContext context) =>
        new MyOrder()
        {
            id = source.id,
            __type = source.__type,
            company_id = source.company_id,
            stops = source.stops
        };
}

Then

    private readonly OrderTypeConverter orderTypeConverter;

    public OrderProfile()
    {
        this.orderTypeConverter = new OrderTypeConverter();

        this.CreateMap<ThirdPartyOrder, MyOrder>().ConvertUsing(orderTypeConverter);
    }