0

Unable to map byte[] or byte[]? (nullable byte[]) using AutoMapper ForCtorParam function, I am getting below error message

AutoMapper.AutoMapperConfigurationException : Unmapped members were found. Review the types and members below. Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type For no matching constructor, add a no-arg ctor, add optional arguments, or map all of the constructor parameters ================================================================================== Model -> ModelDto (Destination member list) AutoMapperForCtorParamTest+Model -> AutoMapperForCtorParamTest+ModelDto (Destination member list) Unmapped properties: Code LinkId

Sample code to recreate below

public class AutoMapperForCtorParamTest
    {
        private readonly IMapper mapper;

        public AutoMapperForCtorParamTest()
        {
            mapper = new Mapper(new MapperConfiguration(
                cfg =>
                    {
                        cfg.AddProfile<ModelMapperProfile>();
                    }));
        }

        [Fact]
        public void MapAllProperties()
        {
            mapper.ConfigurationProvider.AssertConfigurationIsValid();
        }

        public class ModelMapperProfile : Profile
        {
            public ModelMapperProfile()
            {
                var defaultCode = Guid.NewGuid().ToByteArray();

                CreateMap<Model, ModelDto>()
                    .ForCtorParam("type", cfg => cfg.MapFrom(x => 1))
                    .ForCtorParam("code", cfg => cfg.MapFrom<byte[]>(x => defaultCode))
                    .ForCtorParam("linkId", cfg => cfg.MapFrom<byte[]?>(x => null));
            }
        }

        public class ModelDto
        {
            public ModelDto(int id, string name, int type, byte[] code, byte[]? linkId)
            {
                Id = id;
                Name = name;
                Type = type;
                Code = code;
                LinkId = linkId;
            }

            public int Id { get; }

            public string Name { get; }

            public int Type { get; }

            public byte[] Code { get; }

            public byte[]? LinkId { get; }
        }

        public class Model
        {
            public Model(int id, string name)
            {
                Id = id;
                Name = name;
            }

            public int Id { get; }

            public string Name { get; }
        }
    }

Note:

  1. I am using dotnet core 3.1 with nullable types enabled

  2. I don't want to use construct using or convert using functions

  3. I am using Automapper v 10.0.0

  • I reproduced the issue [here](https://dotnetfiddle.net/ZAJWJF). I added the two missing ctor params and ignore to both missed properties because they're mappt by ctor. This "solves" the configuration check error but it does not behave as expected because `LinkId` contains an empty array instead of `null`. – Sebastian Schumann Oct 01 '20 at 05:28
  • The problem is solve using `this.AllowNullCollections = true;` in profile ctor. – Sebastian Schumann Oct 01 '20 at 05:34
  • Thanks @Sebastian Schumann, That does work as expected, but looks a bit odd as a member has been mapped and ignored in the same config. Is this the recommended way or a workaround ? – Mahesh Talreja Oct 01 '20 at 05:43
  • The member itself is not mapped. There is a mapping for ctor param. But it is a workarround. That's the reason why I don't add this as answer because I don't understand why the same thing is working for the `Type` property. This property doesn't need to be ignored but looks the same like `Code` or `LinkId`. Only the types are different. But if a mapping is needed for each property there also should be an ignore (or mapping) for `Type`. I don't realy understand that behaviour and hope there will be anyone who ansers this question and describes that wired fact. – Sebastian Schumann Oct 01 '20 at 05:54
  • Yes I agree the issue is with byte[], ForCtorParam map works for other types. Anyways thanks for your help. – Mahesh Talreja Oct 01 '20 at 05:58
  • I think you should add a constructor with those defaults. It seems a lot cleaner that all that code in the AM config. – Lucian Bargaoanu Oct 01 '20 at 06:05
  • @MaheshTalreja I got it. I missread your code. There is an automated mapping created because CreateMap is not called using `(MemberList.None)`. – Sebastian Schumann Oct 01 '20 at 06:09
  • @LucianBargaoanu How does this change the behaviour of AutoMapper? See [here](https://dotnetfiddle.net/uYrNd4). The problem still remains. Using a `MemberList.None` will solve the issue but it does not explain why it is working for property `Type`. – Sebastian Schumann Oct 01 '20 at 06:15
  • `Type` has no setter so is ignored. Collections don't need setters to be mapped. – Lucian Bargaoanu Oct 01 '20 at 06:28
  • @MaheshTalreja The best solution I found so far is [this](https://dotnetfiddle.net/lVk69V) using `MemberList.None` and map all the ctor params. But I'm still missing an explanation for the wired `Type` behaviour. – Sebastian Schumann Oct 01 '20 at 06:28
  • @LucianBargaoanu I don't get the point. I might understand that properties without setters are ignored. But if that's true why doesn't this also work for collection? A `byte[]` is a collection but there's nothing that enforces that it supplies enough space to collect all source items. – Sebastian Schumann Oct 01 '20 at 06:35
  • Probably then it fails at runtime. The fact remains that you don't need a setter to map a collection. Hopefully that's obvious :) – Lucian Bargaoanu Oct 01 '20 at 06:37
  • https://github.com/AutoMapper/AutoMapper/issues/3449#issuecomment-651522397 – Lucian Bargaoanu Oct 01 '20 at 12:49

1 Answers1

0

Use:

.ForCtorParam("text", opt => opt.MapFrom<byte[]?>(src => null));

In my case (string) I fixed it with:

.ForCtorParam("text", opt => opt.MapFrom<string>(src => null));
Luis Gouveia
  • 8,334
  • 9
  • 46
  • 68