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.
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.