JesperGJensen
JesperGJensen

Reputation: 423

AutoMapper with MVC 5: Missing type map configuration or unsupported mapping

I have been unable to get AutoMapper to work in my MVC5 setup. The same code works fine in a UnitTest, but not when in a Web context. I am hoping the collective powers of the Internet can assist here.

I create my Map inside my Global.asax

protected void Application_Start()
{
    ...
    AutoMapperWebConfiguration.Configure();
}

public static class AutoMapperWebConfiguration
{
    public static void Configure()
    {
        Mapper.Initialize(cfg =>
        {
            cfg.AddProfile(new WebProfile());
        });
    }
}

public class WebProfile : Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<Repository.Model.Item, MVC5.Models.Vare>()
            .ForMember(i => i.Navn, opt => opt.MapFrom(c => c.Varenavn))
            .ForMember(i => i.Nummer, opt => opt.MapFrom(c => c.Varenummer))
            .ForMember(i => i.Leverandør, opt => opt.MapFrom(c => c.Leverandør))
            .ForMember(i => i.Indkøbsaktiv, opt => opt.MapFrom(c => c.Indkøbsaktiv))

            .Ignore(record => record.Salgspris)
            .Ignore(record => record.Lager);
    }
}

I am using the Ignore Extension from https://stackoverflow.com/a/16808867/61963

I try to get Items from my Repository and then Map them before returning inside my View.

List<Item> varer = repo.Search(søgning.VareNavn);
List<Vare> output = varer.Select(x => Mapper.Map<Repository.Model.Item, MVC5.Models.Vare>(x)).ToList();
søgning.Varer = output;
//Display Result
return View(søgning);

When i attempt to use this functionality, i get this reply in my Browser

Missing type map configuration or unsupported mapping.

Mapping types:
Item -> Vare
Repository.Model.Item -> MVC5.Models.Vare

Destination path:
Vare

Source value:
Repository.Model.Item

I believe i have added the correct Mapping, but for some reason AutoMapper disagrees. The same code works when run from a UnitTest.

[ClassInitialize]
public static void ClassInitialize(TestContext context)
{
    MVC5.AutoMapperWebConfiguration.Configure();
}

[TestMethod]
public void Automapper_Item_to_Vare()
{
    // Assemble
    Mapper.AssertConfigurationIsValid();

    Repository.Model.Item item = new Repository.Model.Item()
    {
        Indkøbsaktiv = true,
        Leverandør = "Leverandør 1",
        Varenavn = "Lampe",
        Varenummer = "1234567890"
    };

    // Act
    MVC5.Models.Vare vare = Mapper.Map<MVC5.Models.Vare>(item);

    // Assert
    Assert.AreEqual(item.Indkøbsaktiv, vare.Indkøbsaktiv);
    Assert.AreEqual(item.Leverandør, vare.Leverandør);
    Assert.AreEqual(item.Varenavn, vare.Navn);
    Assert.AreEqual(item.Varenummer, vare.Nummer);
}

    [TestMethod]
    public void Automapper_ItemList_to_VareList()
    {
        // Assemble
        Mapper.AssertConfigurationIsValid();
        List<Repository.Model.Item> items = new List<Repository.Model.Item>()
        {
            new Repository.Model.Item()
            {
                Indkøbsaktiv = true,
                Leverandør = "Leverandør 1",
                Varenavn = "Lampe",
                Varenummer = "1234567890"
            },
            new Repository.Model.Item()
            {
                Indkøbsaktiv = true,
                Leverandør = "Leverandør 2",
                Varenavn = "Hammer",
                Varenummer = "9876543210"
            }
        };

        // Act
        List<MVC5.Models.Vare> varer = items.Select(x => Mapper.Map<MVC5.Models.Vare>(x)).ToList();

        // Assert
        Assert.AreEqual(2, varer.Count);
        Assert.AreEqual(items[0].Indkøbsaktiv, varer[0].Indkøbsaktiv);
        Assert.AreEqual(items[0].Leverandør, varer[0].Leverandør);
        Assert.AreEqual(items[0].Varenavn, varer[0].Navn);
        Assert.AreEqual(items[0].Varenummer, varer[0].Nummer);
    }

Upvotes: 0

Views: 2532

Answers (2)

JesperGJensen
JesperGJensen

Reputation: 423

I have managed to get my code into a working condition. I am unable to fully explain my situation, because the solution does not explain why my Test cases where working.

My initialization code had two calls to Mapper.Initialize() This caused my needed mapping to dissapear. Both my main Configure method and my RepositoryProfile class had initialize.

public static class AutoMapperWebConfiguration
{
    public static void Configure()
    {
        Mapper.Initialize(cfg =>
        {
            cfg.AddProfile(new WebProfile());
            cfg.AddProfile(new RepositoryProfile());
        });

        Mapper.AssertConfigurationIsValid();
    }
}

public class WebProfile : Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<Repository.Model.Item, MVC5.Models.Vare>()
            .ForMember(i => i.Navn, opt => opt.MapFrom(c => c.Varenavn))
            .ForMember(i => i.Nummer, opt => opt.MapFrom(c => c.Varenummer))
            .ForMember(i => i.Leverandør, opt => opt.MapFrom(c => c.Leverandør))
            .ForMember(i => i.Indkøbsaktiv, opt => opt.MapFrom(c => c.Indkøbsaktiv))

            .Ignore(record => record.Salgspris)
            .Ignore(record => record.Lager)
            .Ignore(record => record.Antal);            
    }
}

public class RepositoryProfile : Profile
{
    protected override void Configure()
    {
        Mapper.Initialize(
            cfg => cfg.CreateMap<CacheInfo, Item>()
                .ForMember(i => i.Varenavn, opt => opt.MapFrom(c => c.VareNavn))
                .ForMember(i => i.Varenummer, opt => opt.MapFrom(c => c.VareNummer))
                .ForMember(i => i.Leverandør, opt => opt.MapFrom(c => c.Leverandør))
                .ForMember(i => i.Indkøbsaktiv, opt => opt.ResolveUsing<IndkobsaktivResolver>())
        );

Upvotes: 0

Max Kimambo
Max Kimambo

Reputation: 416

I have had a similar experience with automapper before, the problem was that I had other areas of the application registering mappings, which was overwriting the mappings created on app_start.

It is therefore recommended to centralize your mapping registration in one place. Technically what you are describing is caused by the missing mapping configuration, which could be caused by overwritten mappings or your config not being read at app startup.

Upvotes: 1

Related Questions