AutoMapper / AutoMapper.Collection

AutoMapper support for updating existing collections by equivalency
MIT License
245 stars 59 forks source link

DI cycles forever when calling AddCollectionMappers() twice #173

Closed tedchirvasiu closed 1 year ago

tedchirvasiu commented 2 years ago

Description

I encountered the following weird behaviour which causes the app to hang when trying to resolve an IMapper dependency. No error is thrown, it just seems to run into an infinite loop somewhere internally. So, according to https://github.com/AutoMapper/AutoMapper.Extensions.Microsoft.DependencyInjection/issues/132 AutoMapper follows the Options Pattern and allows AddAutoMapper to be called multiple times. Consider we have two projects, ProjectA and ProjectB. ProjectA references ProjectB. Both use AutoMapper.Collection and call the following code in their DI registration:

...services.AddAutoMapper(
    (cfg) => {
        cfg.AddCollectionMappers();
    },
    Assembly.GetExecutingAssembly()
);

Assume there exists a service called SomeService in ProjectB which requires an IMapper

public class SomeService {

    IMapper Mapper { get; set; }

    public SomeService(IMapper mapper) {
        Mapper = mapper;
    }
}

This setup works fine and the application runs normally. Now consider we add two classes of the form:

public class SomeEntity {
    public virtual ICollection<string> Elements { get; set; }
}
public class SomeDto {
    public List<string> Elements { get; set; }
}

With a mapping profile containing the following configuration:

public class SomeMappingProfile : Profile {

    public SomeMappingProfile() {

        CreateMap<SomeEntity, SomeDto>();

    }
}

Now the application will hang forever when trying to resolve SomeService, specifically when trying to resolve IMapper. It's somewhere internally but not sure where. Here's the weird part: commenting either the AddCollectionMappers() in ProjectA or in ProjectB will resolve the issue. It hangs only when AddCollectionMappers() is called twice or more (even in succession in the same project).

Example repo

https://github.com/tedchirvasiu/AutoMapper.Collection.AddCollectionMappersBug

Versions

AutoMapper: 12.0.0 AutoMapper.Collection: 9.0.0

tedchirvasiu commented 2 years ago

I updated the issue and simplified the example, it seems to hang whenever there's a collection mapping, even of the same underlying type, and AddCollectionMappers is called more than once (from different assemblies or from the same assembly).

lbargaoanu commented 2 years ago

A PR is welcome.

tedchirvasiu commented 2 years ago

A PR is welcome.

Of course, but right now I am not familiar at all with the codebase and it will take a while before I can properly look into it. At the moment I thought I'd at least document the issue. I thought a quick fix would be adding a flag in https://github.com/AutoMapper/AutoMapper.Collection/blob/2d8097b7d509d1d556fe693e6c6f045c191a6894/src/AutoMapper.Collection/EquivalencyExpression/EquivalentExpressions.cs#L16 to check if AddCollectionMappers() has already been called, but I doubt that's the right solution. Not sure if AutoMapper.Collection does assembly scanning and adding it seems to take effect globally, not on a per assembly basis (which I'm not sure whether it's right or wrong).