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.
// 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()
{
}
}
In the past, when running multiple xunit test files, each test call a centralized static automapper initialize() method, all the test runs.
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.
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?
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
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.
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.