0

I'm starting to use AutoMapper (latest version from Nuget) into my project (WebApi2, framework 4.5.1) and using SimpleInjector (latest version from Nuget).

My problem is that I don't know how to configure SimpleInjector to inject IMappingEngine into my models by constructor.

Right now I'm getting the error: Unmapped properties: MappingEngine

I'm using the IMappingEngine interface.

I have a AutoMapperProfile class with all the Mapper.CreateMap<>

Example of AutoMapperConfig

public class WebApiAutomapperProfile : Profile { /// <summary> /// The configure. /// </summary> protected override void Configure() { this.CreateMap<Entity, EntityModel>(); } } 

The reason the models are receiving an IMappingEngine is that some mappings attributes have other mapping inside.

In Global.asax (method Application_Start()) I'm calling:

 GlobalConfiguration.Configure(WebApiConfig.Register); webApiContainer = new Container(); webApiContainer.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle(); IocConfig.RegisterIoc(GlobalConfiguration.Configuration, webApiContainer); 

IocConfig.cs

public static class IocConfig { public static void RegisterIoc(HttpConfiguration config, Container container) { InstallDependencies(container); RegisterDependencyResolver(container); } private static void InstallDependencies(Container container) { new ServiceInstallerSimpleInjector().Install(container); } private static void RegisterDependencyResolver(Container container) { GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container); } 

ServiceInstallerSimpleInjector

public class ServiceInstallerSimpleInjector : IServiceInstallerSimpleInjector { // Automapper registrations container.Register(typeof(ITypeMapFactory), typeof(TypeMapFactory), Lifestyle.Scoped); container.RegisterCollection<IObjectMapper>(MapperRegistry.Mappers); var configurationRegistration = Lifestyle.Scoped.CreateRegistration<ConfigurationStore>(container); container.AddRegistration(typeof(IConfiguration), configurationRegistration); container.AddRegistration(typeof(IConfigurationProvider), configurationRegistration); // The initialization runs all the map creation once so it is then done when you come to do your mapping. // You can create a map whenever you want, but this will slow your code down as the mapping creation involves reflection. Mapper.Initialize(config => { config.ConstructServicesUsing(container.GetInstance); config.AddProfile(new WebApiAutomapperProfile()); config.AddGlobalIgnore("Errors"); config.AddGlobalIgnore("IsModelValid"); config.AddGlobalIgnore("BaseValidator"); config.AddGlobalIgnore("AuditInformation"); }); container.RegisterSingleton<IMappingEngine>(Mapper.Engine); Mapper.AssertConfigurationIsValid(); container.RegisterWebApiControllers(GlobalConfiguration.Configuration); container.Verify(); } 

Then each Controller receives a IMappingEngine in the constructor and uses:

MappingEngine.Map<> 

Models class sample

public class EntityModel : BaseModel.BaseModel<EntityModel > { public EntityModel(IMappingEngine mappingEngine) : base(mappingEngine) { } } 

BaseModel

public abstract class BaseModel<T> : IBaseModel where T : class { public IMappingEngine MappingEngine { get; set; } protected BaseModel(IMappingEngine mappingEngine) { this.MappingEngine = mappingEngine; } } 

The error message says:

Type needs to have a constructor with 0 args or only optional args\r\nParameter name: type Mapping types: Entity -> EntityModel Model.Entity -> WebApi.Models.EntityModel Destination path: EntityModel Source value: System.Data.Entity.DynamicProxies.Entity_1D417730D5BE3DEAF6292D57AB49B32FA18136A1DCF74193E8716EC6EE4DC62B 

The problem is that IMappingEngine mappingEngine is not being injected into the Model's constructor. The problem is how to make it work.

The error is thrown when I'm trying to do a .Map

return this.MappingEngine.Map<Entity,EntityModel>(this.EntityRepository.AllMaterialized().FirstOrDefault()); 

And this is the Stacktrace

 at WebApi.Controllers.Api.EntityController.Get() in c:\Users\Guillermo\Downloads\Backend\WebApi\Controllers\Api\EntityController.cs:line 108 at lambda_method(Closure , Object , Object[] ) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken) 

Anything missing or wrong?

Thanks in advance! Guillermo.

8
  • 1
    Hi Guillermo. Problaby your problem is tied only to Automapper and SimpleInjector, WebApi is beside. You must try the following in order to help you easily: 1. Prepare a unit test demostrating the problem. 2. Try to replace Automapper (e.g. with Value Injecter valueinjecter.codeplex.com in order to determine if is a mapping problem). 3. Try to replace SimpleInjector (e.g. with Windsor). This might provide some light in your darkness. Commented Nov 18, 2015 at 21:57
  • Are you grtting any exception? If so, please post the complete exception with inner exceptions and stack trace. Commented Nov 18, 2015 at 22:12
  • Hi @Apocatastasis, changing the IoC container is not an option for me as I'm doing a "plugin system" to a bigger one already using it. I know it's a mapping problem. The problem is that IMappingEngine mappingEngine is not being injected into the Model's constructor. The problem is how to make it work. Added error description to the question above. Commented Nov 19, 2015 at 2:14
  • @Steven the error message is this: Type needs to have a constructor with 0 args or only optional args\r\nParameter name: type The problem is that IMappingEngine mappingEngine is not being injected into the Model's constructor. That's why the message says so, there is only one constructor for the Model with parameter. Added error description to the question above. Commented Nov 19, 2015 at 2:14
  • You misinterpreted @Apocatastasis comment. He doesn't advice you to move away from Simple Injector, he merely advices you to devide and conquer to pin point the problem. Build a minimal reproducible example. If you switch containers in that setup, and the problem goes away, you know the problem is in the DI configuration. Commented Nov 19, 2015 at 7:20

1 Answer 1

1

Since your EntityController is resolved correctly by Simple Injector, and it depends on IMapperEngine you can rest assure that the mapper engine is injected correctly. What might be happening is that the registered Mapper.Engine is not correctly initialized at that point, but I'm just guessing about this. An Automapper expert should be able to see what's going wrong here.

The core of your problem however is that you try to do dependency injection into domain entities. Take a look at this article from Jimmy Bogard (the creator of Automapper) who explains why this is a bad idea.

Once you stop requiring service dependencies during the initialization of your entities, this problem will go away completely.

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

3 Comments

hmm...those are Dto classes, not domain classes, not sure if it's the same case...will read that article anyways...thx
@polonskyg: For DTOs the same thing holds, but I would say the argument is even stronger. While entities can make use of services (when applying Domain-Driven Design), DTOs should contain no logic at all (they are called Data transfer objects for a reason), so injecting dependencies into them is a real big no-no.
I gave it another thought and I think you're right, Why having an IMappingEngine inside what's being Mapped? That's a now, Controller will be responsible of converting Entities to Dtos and the one receiving the IMappingEngine. Thx!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.