Skip to content

IgnoreAllPropertiesWithAnInaccessibleSetter interferes with ForCtorParam #3412

@ghost

Description

Version: 9.0.0

Expected behavior

Maybe I have misunderstood the intention of IgnoreAllPropertiesWithAnInaccessibleSetter, but my interpretation of it is to safeguard against AutoMapper constructing the destination object using the default constructor and then mapping to a private/protected setter. This is especially important to ensure encapsulation and valid invariants, i.e. that all validation in the destination object's constructor are run. So I would like to set IgnoreAllPropertiesWithAnInaccessibleSetter globally to ensure this never happens, but still be able to map to constructor parameters by name with ForCtorParam.

Actual behavior

Exception is thrown, with message Destination needs to have a constructor with 0 args or only optional args.

Steps to reproduce

You can reproduce this with the existing unit test below. Just add IgnoreAllPropertiesWithAnInaccessibleSetter to it's config.

    public class When_renaming_class_constructor_parameter : AutoMapperSpecBase
    {
        Destination _destination;

        public class Source
        {
            public InnerSource InnerSource { get; set; }
        }

        public class InnerSource
        {
            public string Name { get; set; }
        }

        public class Destination
        {
            public Destination(InnerDestination inner)
            {
                InnerDestination = inner;
            }

            public InnerDestination InnerDestination { get; }
        }

        public class InnerDestination
        {
            public string Name { get; set; }
        }

        protected override MapperConfiguration Configuration => new MapperConfiguration(c =>
        {
            // Line below added
            c.ForAllMaps((tm, me) => me.IgnoreAllPropertiesWithAnInaccessibleSetter());

            c.CreateMap<Source, Destination>().ForCtorParam("inner", o => o.MapFrom(s => s.InnerSource));
            c.CreateMap<InnerSource, InnerDestination>();
        });

        protected override void Because_of()
        {
            _destination = Mapper.Map<Destination>(new Source { InnerSource = new InnerSource { Name = "Core" } });
        }

        [Fact]
        public void Should_map_ok()
        {
            _destination.InnerDestination.Name.ShouldBe("Core");
        }
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions