I have a .NET6 project with minimal APIs. This is the code
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<ClientContext>(opt =>
opt.UseInMemoryDatabase("Clients"));
builder.Services
.AddTransient<IClientRepository,
ClientRepository>();
builder.Services
.AddAutoMapper(Assembly.GetEntryAssembly());
var app = builder.Build();
// Get the Automapper, we can share this too
var mapper = app.Services.GetService<IMapper>();
if (mapper == null)
{
throw new InvalidOperationException(
"Mapper not found");
}
app.MapPost("/clients",
async (ClientModel model,
IClientRepository repo) =>
{
try
{
var newClient = mapper.Map<Client>(model);
repo.Add(newClient);
if (await repo.SaveAll())
{
return Results.Created(
$"/clients/{newClient.Id}",
mapper.Map<ClientModel>(newClient));
}
}
catch (Exception ex)
{
logger.LogError(
"Failed while creating client: {ex}",
ex);
}
return Results.BadRequest(
"Failed to create client");
});
This code is working. I have a simple Profile for AutoMapper
public class ClientMappingProfile : Profile
{
public ClientMappingProfile()
{
CreateMap<Client, ClientModel>()
.ForMember(c => c.Address1, o => o.MapFrom(m => m.Address.Address1))
.ForMember(c => c.Address2, o => o.MapFrom(m => m.Address.Address2))
.ForMember(c => c.Address3, o => o.MapFrom(m => m.Address.Address3))
.ForMember(c => c.CityTown, o => o.MapFrom(m => m.Address.CityTown))
.ForMember(c => c.PostalCode, o => o.MapFrom(m => m.Address.PostalCode))
.ForMember(c => c.Country, o => o.MapFrom(m => m.Address.Country))
.ReverseMap();
}
}
I wrote a NUnit test and a xUnit test. In both cases, when I call the API I receive the error
Program: Error: Failed while creating client: AutoMapper.AutoMapperMappingException: Missing type map configuration or unsupported mapping.
Mapping types: ClientModel -> Client MinimalApis.Models.ClientModel -> MinimalApis.Data.Entities.Client at lambda_method92(Closure , Object , Client , ResolutionContext )
How can I use the Profile in the main project? The full source code is on GitHub.
CodePudding user response:
When you run your project normally, Assembly.GetEntryAssembly() will resolve to your project's assembly (the one that contains the Profile classes). When you launch your project via a unit test project, the entry point is actually that unit test.
That means that this code isn't actually finding the profiles because they're not in that assembly:
builder.Services
.AddAutoMapper(Assembly.GetEntryAssembly());
Normally what I do in this situation is to use typeof(someAssemblyInMyProject).Assembly. In this example I use Program but any class should work so long as its in the same project as the Profile classes:
builder.Services
.AddAutoMapper(typeof(Program).Assembly);
Now, no matter what the entry assembly is, you'll still find the right list of profiles.
CodePudding user response:
You can instantiate AutoMapper with a specific profile class using the code below:
var configuration = new MapperConfiguration(cfg => cfg.AddProfile(ClientMappingProfile));
var mapper = new Mapper(configuration);
To do this with dependency injection:
services.AddAutoMapper(config =>
{
config.AddProfile(ClientMappingProfile);
});
