ThommyB
ThommyB

Reputation: 1546

Nested object members null after mapping with Automapper

I have an object

public class Tenant : EntityBase
{
    public virtual string Name { get; set; }
    public virtual string Description { get; set; }
    public virtual string CreatorName { get; set; }
    public virtual TenantState State { get; set; }
    public virtual Address Address { get; set; }

    public virtual IList<TenantActivity> Activities { get; set; }
    public virtual IList<AppUser> Users { get; set; }
    public virtual IList<TenantConfig> TenantConfigs { get; set; }

    ....
}

A DTO like so:

public class TenantDto
{
    public Guid Id { get; set; }
    public DateTime CDate { get; set; }
    public string CUser { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string CreatorName { get; set; }
    public TenantState State { get; set; }
    public AddressDto Address { get; set; }
    public List<TenantActivityDto> Activities { get; set; }
    public List<AppUserDto> Users { get; set; }
    public List<TenantConfigDto> TenantConfigs { get; set; }
    ....
}

The class Address is a ValueObject which also has a DTO. I use the following mapping (standard, no special configs)

public class TenantMapperProfile : Profile
{
    protected override void Configure()
    {
        CreateMap<Tenant, TenantDto>();
        CreateMap<TenantDto, Tenant>();
    }
}

public class AddressMapperProfile : Profile
{
    protected override void Configure()
    {
        CreateMap<Address, AddressDto>();
        CreateMap<AddressDto, Address>();
    }
}

And in my App.xaml.cs I have:

        var mapperConfig = new MapperConfiguration(cfg =>
        {
            cfg.AddProfile<TenantMapperProfile>();
            cfg.AddProfile<TenantActivityMapperProfile>();
            cfg.AddProfile<AppUserMapperProfile>();
            cfg.AddProfile<AddressMapperProfile>();
            //cfg.ShouldMapProperty = p => p.SetMethod.IsPrivate || p.GetMethod.IsAssembly;
        });
        Mapper = mapperConfig.CreateMapper();

Then I call it in a service like so:

    public TenantDto CreateTenant(TenantDto tenantDto)
    {
        tenantDto.CreatorName = creatingUserName;
        var tenant = _mapper.Map<Tenant>(tenantDto); 
        tenant = _tenantManagerService.CreateTenant(tenant);//<-- Screenshot made here
        return _mapper.Map<TenantDto>(tenant);
    }

After the first call to mapper I made a screenshot of my debugger window. As you can see the tenantDto instance contains data in the Address object but the tenantobject contains its own data correctly mapped but the nested Address object has only null values! What am I doing wrong here??

EDIT - additional information

calling mapperConfig.AssertConfigurationIsValid(); returns one error:

The following property on Bedisoco.BedInventory.Sys.Models.Entities.Role cannot be mapped: Roles Add a custom mapping expression, ignore, add a custom resolver, or modify the destination type Bedisoco.BedInventory.Sys.Models.Entities.Role.

The Role object is somewhere inside one of the Lists, I think the User object inside the List<AppUser> collection contains itself a list of Role objects. It is not even implemented completely.

Am I wrong assuming that Automapper ignores such things silently??

enter image description here

Upvotes: 3

Views: 2569

Answers (1)

ThommyB
ThommyB

Reputation: 1546

Ok solved it, was my own problem.

Most of my value objects contain a constructor with all fields and a private setter. Private setters are NO problem with Automapper if configured correctly (cfg.ShouldMapProperty = p => p.SetMethod.IsPrivate || p.GetMethod.IsAssembly;).

But VS or ReSharper suggested to make auto properties 'get-only'. This refactoring pleases VS but NOT Automapper!

Upvotes: 3

Related Questions