Automapper: xUnit failed in AutoMapper 6.2.x due to an error: Mapper already initialized. You must call Initialize once per application domain/process

Created on 18 Apr 2018  路  14Comments  路  Source: AutoMapper/AutoMapper

Summary

I have xunit tests that each of the test cs file has a constructor that will perform an automapper initialization. In Automapper version 6.1.x, all the tests passed properly. Once upgraded to 6.2.x, now it throws an error that the mapper is already initialized. So I wonder if there is a change in the Mapper.Initialize() behavior.

I noticed that there is a new Mapper.Reset() method, I have tried calling the reset method before the Initialize() method, but still having the same result.

At the moment I'm rolling back to version 6.1.1. It seems like I might have to figure out how to just call the Mapper.Initialize() one time throughout the entire xunit test run, I think they have some sort of share Text Fixture in xunit so I'll look into that.

I'm not sure what's the resolution is, I don't expect the behavior to change, just writing this up so if someone having the same issue with xunit like me. I'll keep this posted if I found some workaround.

Source Codes (for xUnit project)

// AutoMapperConfig.cs
public static class AutoMapperConfig
    {
        // Centralize automapper initialize
        public static void Initialize()
        {
            AutoMapper.Mapper.Initialize(cfg => { });
        }
    }

// TestArea1.cs
public class TestArea1
    {
        public TestArea1()
        {
            AutoMapperConfig.Initialize();
        }
        [Fact]
        public void Test1()
        {

        }
    }

// TestArea2.cs
public class TestArea2
    {
        public TestArea2()
        {
            AutoMapperConfig.Initialize();
        }

        [Fact]
        public void Test1()
        {

        }
    }

Version: 6.2.2

Expected behavior

In the past, when running multiple xunit test files, each test call a centralized static automapper initialize() method, all the test runs.

Actual behavior

Now when running multiple xunit tests files, first test file passed, but second and so on failed due to an error System.InvalidOperationException : Mapper already initialized. You must call Initialize once per application domain/process.

Steps to reproduce

AutoMapper_6_2_x_Issue.zip

  • I attached a code sample project above
  • Open in visual studio 2017
  • In test Explorer, run all tests
  • One pass, one failed due to mapper already initialized
  • Now if you swap Automapper back to version 6.1.x, it works fine

Most helpful comment

Thanks @jbogard , I couldn't figure out how to apply Lazy in my scenario because I'm using static automapper. However, I got the code modified ant it shouldn't have to reset/initialize every time. Thanks for the suggestion.

public static class AutoMapperConfig
    {
        private static object _thisLock = new object();
        private static bool _initialized = false;
        // Centralize automapper initialize
        public static void Initialize()
        {
            // This will ensure one thread can access to this static initialize call
            // and ensure the mapper is reseted before initialized
            lock (_thisLock)
            {
                if (!_initialized)
                {
                    AutoMapper.Mapper.Initialize(cfg => { });
                    _initialized = true;
                }
            }
        }
    }

All 14 comments

You should call Initialize once, use Reset or switch to the object based API.

You should call Initialize once, use Reset or switch to the object based API.

In the sample code, I have tried adding the Reset() method before calling the initialize(), but it's still throwing an error. Do you mind elaborate more on the object base API?

See here, here and here. But other than that, I think this is better suited for StackOverflow.

Since calling the AutoMapper.Mapper.Reset() doesn't work in my above scenario code example, it is because when running xUnit, somehow it's constructing each of the test files in separate threads, so both threads can still call the Initialize() again after the reset() function.

I know this issue is closed, but here is the current solution for my above example code for future reference.

public static class AutoMapperConfig
{
    public static object thisLock = new object();
    // Centralize automapper initialize
    public static void Initialize()
    {
        // This will ensure one thread can access to this static initialize call
        // and ensure the mapper is reseted before initialized
        lock (thisLock)
        {
            AutoMapper.Mapper.Reset();
            AutoMapper.Mapper.Initialize(cfg => { });
        }
    }
}

You can also use Lazy<T> to initialize only once, then you won't need to reset/initialize every single time.

Thanks @jbogard , I couldn't figure out how to apply Lazy in my scenario because I'm using static automapper. However, I got the code modified ant it shouldn't have to reset/initialize every time. Thanks for the suggestion.

public static class AutoMapperConfig
    {
        private static object _thisLock = new object();
        private static bool _initialized = false;
        // Centralize automapper initialize
        public static void Initialize()
        {
            // This will ensure one thread can access to this static initialize call
            // and ensure the mapper is reseted before initialized
            lock (_thisLock)
            {
                if (!_initialized)
                {
                    AutoMapper.Mapper.Initialize(cfg => { });
                    _initialized = true;
                }
            }
        }
    }

You can make the Test class Disposable and call the Mapper.Reset() on the Dispose event . That worked for me :)

@Fjsmoreira I tried doing this on my XUnit class and my IFixture. Can you explain better what you mean?

here is my source code without the disposing stuff. https://github.com/AutoMapper/AutoMapper.Extensions.Microsoft.DependencyInjection/issues/55

@jbogard (https://github.com/AutoMapper/AutoMapper/issues/2607#issuecomment-382828962)

How to use Lazy to initialize AutoMapper configuration?

It's works for me:

public class MyTestClass :  IDisposable
{
      public MyTestClass ()
      {
          Mapper.Initialize(cfg =>
          {
              cfg.AddProfiles(new[] { "My.Assembly.Scan" });
          });
      }

      public void Dispose()
      {
         Mapper.Reset();
      }

        ...

@igorgomeslima Did you update recently? He fixed 90% of these issues.

@VictorioBerra Yes! I am using the last version!

Looks lasted AutoMapper(8.0.0 version) fixed this problem, and no logger need Mapp.Reset() for now.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings