Ivan-Mark Debono
Ivan-Mark Debono

Reputation: 16330

How to use Automapper with Autofac

I've upgraded to the latest version of AutoMapper (9.0) and I've changed the static configuration to:

public static IMapper RegisterAutoMapper()
{
    var config = new MapperConfiguration(cfg =>
    {
        cfg.CreateMap<MyModel MyDto>;
        //etc...
   });
  
   var mapper = config.CreateMapper();
   return mapper;
}

Using the previous static API I used to do the following in Global.asax:

protected void Application_Start()
{
    GlobalConfiguration.Configure(WebApiConfig.Register);
    AutoMapping.Map();
}

WebApiConfig.Register registers the routes and also Autofac

How do I register AutoMapper with Autofac because currently I'm getting compiler errors on such lines:

var myDto = Mapper.Map<MyModel>(model);

And the compiler error:

An object reference is required for the non-static field, method, or property 'Mapper.Map(object)'

Upvotes: 14

Views: 15718

Answers (4)

alsami
alsami

Reputation: 9835

There is also a nuget-package that does all of that for you.

All you need to do is to call an extension method on the ContainerBuilder and pass in the assemblies, that should be scanned for AutoMapper types.

var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterAutoMapper(typeof(MvcApplication).Assembly);
// more registrations here

You can find it here. You can find an official example in the AutoMapper docs as well.

Edit: There are samples for ASP.NET Core and Console-Applications here.

Upvotes: 9

carloswm85
carloswm85

Reputation: 2416

This is an implmentation I applied to a Web API 2 project, in NET Framework 4.7.2, but despite how old it may look, you can use it too.

Initialization

Notice second line. That's were you'll initialize the Autofact static class.

// Global.asax
protected void Application_Start()
{
  AreaRegistration.RegisterAllAreas();
  AutofacConfig.RegisterComponents(); // IoC, AUTOFAC
  GlobalConfiguration.Configure(WebApiConfig.Register);
  FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
  RouteConfig.RegisterRoutes(RouteTable.Routes);
  BundleConfig.RegisterBundles(BundleTable.Bundles);
}

Autofact Configuration

  • This is the whole configuration file for Autofac. It is a static class.
  • Notice the #region MAPPING
// AutofacConfig.cs
public static class AutofacConfig
{
  public static void RegisterComponents()
  {
    var builder = new ContainerBuilder();

    // Get your HttpConfiguration.
    var config = GlobalConfiguration.Configuration;

    // Register your Web API controllers.
    builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

    // OPTIONAL: Register the Autofac filter provider.
    builder.RegisterWebApiFilterProvider(config);

    // OPTIONAL: Register the Autofac model binder provider.
    builder.RegisterWebApiModelBinderProvider();

    #region MAPPING

    // 1 - Mapper configuration is done here
    // Notice the AutoMapperProfile instantiation
    var mapperConfiguration = new MapperConfiguration(cfg => { cfg.AddProfile(new AutoMapperProfile()); });

    // 2 - After configuring the mapper, you create it
    var mapper = mapperConfiguration.CreateMapper();

    // 3 - Register that instance of the mapper, which implements IMapper interface
    builder.RegisterInstance<IMapper>(mapper);

    // 4 - Now you register the TestMapper that you'll inject somewehre in your code, let's say, in a controller
    // Register as many mappers as you need
        
    builder.Register(c => new TestMapper(c.Resolve<IMapper>())).As<ITestMapper>();

    #endregion

    // Set the dependency resolver to be Autofac.
    var container = builder.Build();
    config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
  }
}

Automapper Profile

  • As you can see, this class extends Profile from AutoMapper namespace.
  • Here you will create all the mapping you may need. This is the actual configuration for AutoMapperProfile we did above.
  • This is the file you call from AutofacConfig.cs
// AutoMapperProfile.cs
public class AutoMapperProfile : Profile
{
    public AutoMapperProfile()
    {
        CreateMap<Test, TestDto>()
            .ForMember(destination => destination.Floating, options => options.MapFrom(source => source.flotante))
            .ForMember(dto => dto.Integer, opt => opt.MapFrom(src => src.entero))
            ;
        
        // Test is a model/entity from the DB
        // TestDto is a class I use as a Data Transfer Object
    }
}

TestMapper

  • Here's where you inject the mapper into TestMapper.
  • ITestMapper is your custom definition.
// TestMapper.cs
public class TestMapper : ITestMapper
{
    IMapper _mapper;

    public TestMapper(IMapper mapper)
    {
        _mapper = mapper;
    }

    public TestDto GetTestItem(Test test)
    {
        return _mapper.Map<TestDto>(test);
    }

    // You may add additional implementation here.
}

Use Example

  • Now you can inject TestMapper as ITestMapper wherever you may need it.
  • Notice this is an ApiController inheritor.
// TestController.cs
[RoutePrefix("api/test")]
public class TestController : ApiController
{
    private ITestMapper _testMapper;

    public TestController(, ITestMapper testMapper)
    {
        _testMapper = testMapper;
    }

    [HttpGet]
    [Route("GetTestItem/{id:int}")]
    // GET api/<controller>/GetTestItem/5
    public Prueba GetTestItem(int id)
    {
        var itemDb = _testRepository.GetTestItem(id); // it could be a service
        var itemDto = _testMapper.GetTestItem(itemDb)

        // Return the mapped object
        return itemDto;
    }
}

Upvotes: 3

andyb952
andyb952

Reputation: 2008

Here's one I made earlier:

public class YourAutofacModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        //Also register any custom type converter/value resolvers
        builder.RegisterType<CustomValueResolver>().AsSelf();
        builder.RegisterType<CustomTypeConverter>().AsSelf();

        builder.Register(context => new MapperConfiguration(cfg =>
        {
            cfg.CreateMap<MyModel MyDto>;
            //etc...
        })).AsSelf().SingleInstance();

        builder.Register(c =>
        {
            //This resolves a new context that can be used later.
            var context = c.Resolve<IComponentContext>();
            var config = context.Resolve<MapperConfiguration>();
            return config.CreateMapper(context.Resolve);
        })
        .As<IMapper>()
        .InstancePerLifetimeScope();
    }
}

In the global.asax.cs

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        var builder = new ContainerBuilder();

        builder.RegisterModule<MyAutofacModule>();
        // Register anything else needed

        var container = builder.Build();

        // MVC resolver
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

        // API Resolver
        GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
    }
}

Then all you need to do is inject IMapper

Upvotes: 16

Isaac McClure
Isaac McClure

Reputation: 29

While I'm not familiar with Autofac myself, here is a recent article that descibes how to set up injection for automapper with Autofac.

Goodluck!

Upvotes: 0

Related Questions