Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

calling AddAutoMapper once per assembly instead of passing in multiple assemblies?

Tags:

c#

automapper

I have a multi layered project with a web API project and a library project. Both projects rely on AutoMapper (and AutoMapper extensions for Microsoft.Extensions.DependencyInjection). Based on this

https://docs.automapper.org/en/latest/Dependency-injection.html#asp-net-core

in the Startup file I'm setting up AutoMapper for all the layers

Assembly apiAssembly = Assembly.GetExecutingAssembly();
Assembly myLibraryAssembly = Assembly.Load("MyLibrary");

services.AddAutoMapper(apiAssembly, myLibraryAssembly);

As you can see here, the API project needs to know about all the referenced library projects by loading them via name. I would prefer a way that every project is able to register itself. Based on this sample code

https://github.com/jasontaylordev/CleanArchitecture/blob/master/src/Application/DependencyInjection.cs

I created such a file in my library project

public static class DependencyInjection
{
    public static IServiceCollection AddMyLibrary(this IServiceCollection services)
    {
        Assembly executingAssembly = Assembly.GetExecutingAssembly(); // MyLibrary assembly

        services.AddAutoMapper(executingAssembly);
        // ... setup other services

        return services;
    }
}

and in the API project I can now do this

Assembly executingAssembly = Assembly.GetExecutingAssembly();

services.AddAutoMapper(executingAssembly);
services.AddMyLibrary();

The code seems to work fine but AddAutoMapper will be called twice. Once for the API assembly and once for the library assembly. Should I stick to the first approach because AutoMapper should only be added once or is it fine to separate it?

like image 497
Question3r Avatar asked Jun 09 '20 08:06

Question3r


2 Answers

The accepted answer was correct at the time but it would appear that things have changed in the recent past.

The AutoMapper.Extensions.Microsoft.DependencyInjection package has been updated to allow the call to AddAutoMapper() multiple times.

See PR Use Microsoft.Extensions.Options to configure AutoMapper for details. You will need to update the package to version 8.0.0 or higher to use it.

like image 66
Chris.ZA Avatar answered Sep 18 '22 15:09

Chris.ZA


The code seems to work fine but AddAutoMapper will be called twice. Once for the API assembly and once for the library assembly. Should I stick to the first approach because AutoMapper should only be added once or is it fine to separate it?

You should stick to the first approach, because AddAutoMappper does nothing when called for the second, third etc. time, thus profiles and other AM related types from the assemblies passed to these calls won't be registered.

It can be seen in the beginning of the implementation of the private method which is called by all public AddAutoMapper overloads:

private static IServiceCollection AddAutoMapperClasses(IServiceCollection services, Action<IServiceProvider, IMapperConfigurationExpression> configAction, 
    IEnumerable<Assembly> assembliesToScan, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)
{
    // Just return if we've already added AutoMapper to avoid double-registration
    if (services.Any(sd => sd.ServiceType == typeof(IMapper)))
        return services;

followed by the actual registration code, which at the end registers IMapper.

Currently there is an open issue Allow usage of Options Pattern to configure AutoMapper #132 with exactly the same concerns as yours.

like image 28
Ivan Stoev Avatar answered Sep 18 '22 15:09

Ivan Stoev