MapsterMapper / Mapster

A fast, fun and stimulating object to object Mapper
MIT License
4.29k stars 327 forks source link

Error: TypeAdapter.Adapt was already called, please clone or create new TypeAdapterConfig #570

Open Lilium-Candidum opened 1 year ago

Lilium-Candidum commented 1 year ago

Hi,

I get the same error message as #228 . I configure the TypeAdapterConfig once per class/dto mapping in my Startup and use it through my code per x.Adapt()

It's like

TypeAdapterConfig<model1, dto1>.NewConfig().TwoWays();
TypeAdapterConfig<model2, dto2>.NewConfig().TwoWays();

and so on...

Most of the times it works, but sometimes I get this strange error as @gudufy. Am I doing something wrong? How do I fix this?

Thank you.

rachelpetitto commented 1 year ago

We have a potentially related issue.

For us it is specifically (and only) during integration test runs and only for dotnet 7 projects.

In our case the issue is also transient. It does not happen all the time, but when it does happen, it causes all the integration tests to fail due to app startup failing.

When running integration tests locally, we cannot replicate the issue, no matter how many times we run the tests.

We are currently using the following workaround in case it helps anyone.

try
{
    // setup code here . . . (includes two way mappings in case that matters)
}
catch (InvalidOperationException e)
{
    // sometimes we get this error when running integration tests in circleci
    if (e.Message == null || !e.Message.Contains("TypeAdapter.Adapt was already called, please clone or create new TypeAdapterConfig"))
    {
        throw;
    }
}
MykolaKushnarenko commented 1 year ago

@rachelpetitto I've run into the same trouble during unit tests using xUnit. I was able to reproduce it by running tests in parallel. In the documentation, it's said "Configuration should be set only once and reuse for mapping.". Following this logic, I found a problem in my code. I ran the configuration once per test in parallel which is not good. In my case, the solution was to use Fixtures. Hope it will help someone :)

ccamejo24 commented 11 months ago

Hello @Lilium-Candidum, we have had a similar problem in the integration tests and not even with fixture it worked for us.

After studying the problem for a while we have found that it is because the error is because TypeAdapterConfig.GlobalSettings is a static object and the configuration that we make is maintained until the execution of the program ends and for each of our test/fixture classes it is I was trying to register the dependencies and everything but when Mappster used a static class the previous configuration was maintained.

Solution: before registering the typeAdapterConfig we clear the RuleMap.

Example:

public static IServiceCollection AddMapper(this IServiceCollection services)
    {        
        var typeAdapterConfig = TypeAdapterConfig.GlobalSettings;
        typeAdapterConfig.RuleMap.Clear();
        typeAdapterConfig.Scan(typeof(ProductRequestMapper).Assembly);

        return services;
    }