Home > Software design >  Test .NET6 minimal API with AutoMapper
Test .NET6 minimal API with AutoMapper

Time:01-22

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);
});
  •  Tags:  
  • Related