1

I'm using Automapper in my MVC 5 app to auto map my Entity Framework entities. Some of the mappings need to be looked up, so I need to inject them in the AutoMapperConfig. I use PerRequestLifetimeManager. To do the injection I've setup Unity in Appliction_BeginRequest the following lines:

Mapper.Initialize(cfg => cfg.ConstructServicesUsing(type => UnityConfig.GetConfiguredContainer().Resolve(type)));
var UnityContainer = UnityConfig.GetConfiguredContainer();
UnityContainer.Resolve<AutoMapperConfig>().MapAutoMapper();

But strangely after a few requests (hit F5 several times) the app breaks on Mapper.AssertConfigurationIsValid(); with the error message:

AutoMapper.AutoMapperConfigurationException was unhandled by user code HResult=-2146233088 Message= 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 ======================================================================= IssueDTO -> Issue (Destination member list) Improveize.Classes.DTO.IssueDTO -> Improveize.Classes.Persistent.Issue (Destination member list) ----------------------------------------------------------------------- CreatedBy

But the member mentioned (CreatedBy) is mapped correctly in my code. FYI: the specific mapping makes use of a repository to lookup the data.

The relevant part of the AutoMapperConfig mapping that seems to generate the issue:

Mapper.CreateMap<IssueDTO, Issue>()
    .ForMember(dest => dest.CreatedBy,
               opt => opt.MapFrom(
               src => _UserRepository.Get(u => u.UserID == src.CreatedByID).FirstOrDefault()));

So I thought this would have anything to do, that Automapper is initialized too often (every request) so I've put the Mapper.Initialize..... line in Application_Start. But strangly (at least to me) I get the following error message when I want so save the data of a partial view through an Ajax call to the webapi part of the app.

The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.

It breaks on the following lines in my DBContext when I want to set the EntityState to Modified:

public new virtual DbEntityEntry Entry(object obj)
{
    return base.Entry(obj);
}

So apperantly the mapping resolved by a repository gets another DBContext. (if I ignore the properties that need a lookup, 'everything' works fine)

So it is Obvious that I'm doing something wrong, but I do not know what. The questions that arise:

  • where to put Mapper.Initialize(cfg => cfg.ConstructServicesUsing(type => UnityConfig.GetConfiguredContainer().Resolve(type))); ?? In which class to put in in?
  • can the context issue have anything to do with the web app is using MVC 5 and Webapi 2.0? Do they generate different dbcontext? And how can I avoid this.
  • where is the AutoMapper error coming from (it looks like the wrong message to me)? And how to solve

EDIT to answer the questions of Gert Arnold:

  • DbEntityEntry method breaks my DBContext
  • it breaks when I want to set the EntityState to Modified, called in the update action of the repository
  • Since I use PerRequestLifeTimeManager I assume the lifetime of _UserRepository.Get to be the lifespan of the request. I'm doing nothing explicitly to dispose the context nor the repository.
3
  • Application_Start is the right place. The rest is hard to tell without more details. What is the lifespan of _UserRepository.Get? Where does this Entry method run? Where is it called? Commented Feb 2, 2014 at 18:46
  • Hi Gert, I've updated my post with the answers to your questions. Commented Feb 2, 2014 at 20:04
  • More than likely, _UserRepository.Get() creates a new DbContext, so the row returned from this call uses a different DbContext than what you are assigning it to. It's hard to tell, though, since you don't include any of that code... Commented Feb 2, 2014 at 21:58

1 Answer 1

2

1) Mapper.AssertConfigurationIsValid(); is meant to be used in unit tests, not in production code.

2) Also this

Mapper.CreateMap<IssueDTO, Issue>()
    .ForMember(dest => dest.CreatedBy,
       opt => opt.MapFrom(
       src => _UserRepository.Get(u => u.UserID ==src.CreatedByID).FirstOrDefault()));

is scary usage of Automapper. I never could imagine it could be abused this way. Violation of SRP in it's worst! Your mapping code does mapping AND does database lookup? mixing responsibilities here. Therefore you are going into lot of complexity with injecting Automapper configuration and other strange issues. Don't do it, keep it simple.

Let your controllers (or QueryHandlers) query database for entities and mapper just do it's job by mapping DB objects into view models.

Sign up to request clarification or add additional context in comments.

2 Comments

1)I'll remove it from my productioncode. 2) For mapping a DTO to Entity I need a database lookup. I thought AutoMapper could centralize this mapping and reduce #lines. Is it perhaps a better idea to create manually a mapper class for each mapping? To repeat the mappings in each controller looks like writing the same code multiple times to me.
reducing number of lines by increasing complexity - not good. No need for a mapper class per mapping - many mappings can live in one class. You don't need to repeat the mapping in each controller. You can define public User CreatedBy {get; set;} in your entities next to CreatedByID. And tell EF to load this User whenever you load entities by .Include(a => a.CreatedBy).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.