Reputation: 423
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
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
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