Message: System.InvalidOperationException : Mapper not initialized. Call Initialize with appropriate configuration. If you are trying to use mapper instances through a container or otherwise, make sure you do not have any calls to the static Mapper.Map methods, and if you're using ProjectTo or UseAsDataSource extension methods, make sure you pass in the appropriate IConfigurationProvider instance.
Define a mapping profile (ApplicationMappingProfile.cs)
public class ApplicationMappingProfile : Profile
{
public ApplicationMappingProfile()
{
CreateMap<User, UserListDto>();
CreateMap<Permission, PermissionListDto>();
// add auto mapper mapping configurations here
}
}
Register automapper services (ApplicationServiceCollectionExtensions.cs)
public static class ApplicationServiceCollectionExtensions
{
public static IServiceCollection AddKodkodApplication(this IServiceCollection services)
{
services.AddAutoMapper();
//todo: add conventional registrar
services.AddTransient<IUserAppService, UserAppService>();
services.AddTransient<IPermissionAppService, PermissionAppService>();
return services;
}
}
Create a test server to run Startup.cs (ApiTestBase.cs)
public class ApiTestBase : TestBase
{
protected static HttpClient Client;
public ApiTestBase()
{
//if this is true, Automapper is throwing exception
ServiceCollectionExtensions.UseStaticRegistration = false;
Client = GetTestServer();
}
private static HttpClient GetTestServer()
{
if (Client != null)
{
return Client;
}
var server = new TestServer(
new WebHostBuilder()
.UseStartup<Startup>()
.ConfigureAppConfiguration(config =>
{
config.SetBasePath(Path.GetFullPath(@"../../.."));
config.AddJsonFile("appsettings.json", false);
})
);
return server.CreateClient();
}
}
And test (AccountTests.cs).
public class AccountTests : ApiTestBase
{
[Fact]
public async Task TestAuthorizedAccessAsync()
{
var responseLogin = await LoginAsTestUserAsync();
var responseContent = await responseLogin.Content.ReadAsAsync<OkObjectResult>();
var responseJson = JObject.Parse(responseContent.Value.ToString());
var token = (string)responseJson["token"];
var requestMessage = new HttpRequestMessage(HttpMethod.Get, "/api/test/GetUsers/");
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
var responseGetUsers = await Client.SendAsync(requestMessage);
Assert.Equal(HttpStatusCode.OK, responseGetUsers.StatusCode);
var users = await responseGetUsers.Content.ReadAsAsync<PagedList<UserListDto>>();
Assert.True(users.Items.Count > 0);
}
}
This test method calling /api/test/GetUsers/
method that is using an appservice (PermissionAppService.cs). This app service return a dto that is mapped from entity with using automapper. So exception is occuring here.
When I removed following line:
ServiceCollectionExtensions.UseStaticRegistration = false;
Then I am getting following error:
Message: System.InvalidOperationException : Mapper already initialized. You must call Initialize once per application domain/process.
This error occuring, because there are more than one classes that are inherited from ApiTestBase class. If I run only TestAuthorizedAccessAsync method, It runs with no issue.
The question can be a bit complicated, sorry for this :) feel free to ask where you don't understand.
PROJECT SOURCE
It works when I run web api project that uses appServices
if I added following lines to TestBase constructor, only one test is failing and others passed.
public TestBase()
{
lock (ThisLock)
{
Mapper.Reset();
Client = GetTestServer();
}
....
TestBase.cs
public class TestBase
{
private static Dictionary<string, string> _testUserFormData;
protected readonly IMapper Mapper;
protected readonly KodkodDbContext KodkodInMemoryContext;
protected readonly ClaimsPrincipal ContextUser;
protected readonly HttpClient Client;
protected async Task<HttpResponseMessage> LoginAsTestUserAsync()
{
return await Client.PostAsync("/api/account/login",
_testUserFormData.ToStringContent(Encoding.UTF8, "application/json"));
}
public TestBase()
{
// disable automapper static registration
ServiceCollectionExtensions.UseStaticRegistration = false;
// Initialize mapper
Mapper = new Mapper(
new MapperConfiguration(
configure => { configure.AddProfile<ApplicationMappingProfile>(); }
)
);
Client = GetTestServer();
_testUserFormData = new Dictionary<string, string>
{
{"email", "[email protected]"},
{"username", "testuser"},
{"password", "123qwe"}
};
KodkodInMemoryContext = GetInitializedDbContext();
ContextUser = GetContextUser();
}
...
UserApplicationServiceTests.cs
public class UserApplicationServiceTests : ApplicationTestBase
{
private readonly IUserAppService _userAppService;
public UserApplicationServiceTests()
{
var userRepository = new Repository<User>(KodkodInMemoryContext);
_userAppService = new UserAppService(userRepository, Mapper);
}
...
TO avoid this error:
Message: System.InvalidOperationException : Mapper already initialized. You must call Initialize once per application domain/process.
You need to call Mapper.Reset()
before executing each test:
The static Mapper.Initialize is intended to be called only once. To reset the static mapping configuration
Reset should not be used in production code. It is intended to support testing scenarios only.
You can call it at the beginning of the unit test but I recommend to do it in your unit test class default constrcutor like below:
public AccountTests()
{
Mapper.Reset();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With