Pascal
Pascal

Reputation: 12885

Exception when I try to combine Autofac with AutoMapper`s IMappingEngine

Thats my DI and Automapper setup:

[RoutePrefix("api/productdetails")]
public class ProductController : ApiController
{
    private readonly IProductRepository _repository;
    private readonly IMappingEngine _mappingEngine;

    public ProductController(IProductRepository repository, IMappingEngine mappingEngine)
    {
        _repository = repository;
        _mappingEngine = mappingEngine;
    }
}

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        GlobalConfiguration.Configure(WebApiConfig.Register);

        //WebApiConfig.Register(GlobalConfiguration.Configuration);          
        RouteConfig.RegisterRoutes(RouteTable.Routes);          
    }
}


public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes();
        config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", new { id = RouteParameter.Optional });

        // Filter
        config.Filters.Add(new ActionExceptionFilter());
        config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler());


        // DI
        // Register services
        var builder = new ContainerBuilder();
        builder.RegisterType<ProductRepository>().As<IProductRepository>().InstancePerRequest();
        builder.RegisterType<MappingEngine>().As<IMappingEngine>();

        // AutoMapper
        RegisterAutoMapper(builder);

        // FluentValidation

        // do that finally!
        // This is need that AutoFac works with controller type injection
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
        var container = builder.Build();
        config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
    }

    private static void RegisterAutoMapper(ContainerBuilder builder)
    {
        var profiles =
            AppDomain.CurrentDomain.GetAssemblies()
                .SelectMany(GetLoadableTypes)
                .Where(t => t != typeof (Profile) && typeof (Profile).IsAssignableFrom(t));
        foreach (var profile in profiles)
        {
            Mapper.Configuration.AddProfile((Profile) Activator.CreateInstance(profile));
        }

    }

    private static IEnumerable<Type> GetLoadableTypes(Assembly assembly)
    {
        try
        {
            return assembly.GetTypes();
        }
        catch (ReflectionTypeLoadException e)
        {
            return e.Types.Where(t => t != null);
        }
    }
}

Thats the exception I get when I go to a certain route:

None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'AutoMapper.MappingEngine' can be invoked with the available services and parameters:
Cannot resolve parameter 'AutoMapper.IConfigurationProvider configurationProvider' of constructor 'Void .ctor(AutoMapper.IConfigurationProvider)'.
Cannot resolve parameter 'AutoMapper.IConfigurationProvider configurationProvider' of constructor 'Void .ctor(AutoMapper.IConfigurationProvider, AutoMapper.Internal.IDictionary`2[AutoMapper.Impl.TypePair,AutoMapper.IObjectMapper], System.Func`2[System.Type,System.Object])'.

QUESTION

What is wrong with my code?

Upvotes: 1

Views: 1383

Answers (1)

Cyril Durand
Cyril Durand

Reputation: 16187

The error come from this line :

builder.RegisterType<MappingEngine>().As<IMappingEngine>();

This line tell Autofac to instanciate a MappingEngine when you need a IMappingEngine. If you look at the available constructor of MappingEngine you will see that Autofac can't use any of them because it can't inject required parameters.

Here are the available constructor of MappingEngine

public MappingEngine(IConfigurationProvider configurationProvider)
public MappingEngine(IConfigurationProvider configurationProvider, 
                     IDictionary<TypePair, IObjectMapper> objectMapperCache, 
                     Func<Type, object> serviceCtor)

One of the solution to fix this issue is to tell Autofac how to create your MappingEngine you can do it by using a delegate registration.

builder.Register(c => new MappingEngine(...)).As<IMappingEngine>();

You can also register a IConfigurationProvider by doing so, Autofac will be able to automatically find the good constructor.

The easiest way to fix this issue is to register a IConfigurationProvider in Autofac

builder.Register(c => new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers))
       .As<IConfigurationProvider>()
       .SingleInstance();
builder.RegisterType<MappingEngine>()
       .As<IMappingEngine>();

You can also find further information here : AutoMapper, Autofac, Web API, and Per-Request Dependency Lifetime Scopes

Upvotes: 2

Related Questions