使用 AutoMapper 测试 .NET6 最小 API
Test .NET6 minimal API with AutoMapper
我有一个包含最少 API 的 .NET6 项目。这是代码
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");
});
此代码有效。我有一个简单的 Profile
用于 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();
}
}
我写了一个 NUnit
测试和一个 xUnit
测试。在这两种情况下,当我调用 API 时,我收到错误
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 )
如何在主项目中使用配置文件?完整的源代码在 GitHub.
您可以使用以下代码实例化具有特定配置文件的 AutoMapper class:
var configuration = new MapperConfiguration(cfg => cfg.AddProfile(ClientMappingProfile));
var mapper = new Mapper(configuration);
要使用依赖注入来做到这一点:
services.AddAutoMapper(config =>
{
config.AddProfile(ClientMappingProfile);
});
当您 运行 您的项目正常时,Assembly.GetEntryAssembly()
将解析为您项目的程序集(包含 Profile
classes 的程序集)。当您通过单元测试项目启动项目时,入口点实际上是该单元测试。
这意味着此代码实际上并未找到配置文件,因为它们不在该程序集中:
builder.Services
.AddAutoMapper(Assembly.GetEntryAssembly());
通常我在这种情况下所做的是使用typeof(someAssemblyInMyProject).Assembly
。在这个例子中,我使用 Program
但任何 class 都应该可以工作,只要它与 Profile
classes:
在同一个项目中
builder.Services
.AddAutoMapper(typeof(Program).Assembly);
现在,无论入口程序集是什么,您仍然可以找到正确的配置文件列表。
我有一个包含最少 API 的 .NET6 项目。这是代码
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");
});
此代码有效。我有一个简单的 Profile
用于 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();
}
}
我写了一个 NUnit
测试和一个 xUnit
测试。在这两种情况下,当我调用 API 时,我收到错误
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 )
如何在主项目中使用配置文件?完整的源代码在 GitHub.
您可以使用以下代码实例化具有特定配置文件的 AutoMapper class:
var configuration = new MapperConfiguration(cfg => cfg.AddProfile(ClientMappingProfile));
var mapper = new Mapper(configuration);
要使用依赖注入来做到这一点:
services.AddAutoMapper(config =>
{
config.AddProfile(ClientMappingProfile);
});
当您 运行 您的项目正常时,Assembly.GetEntryAssembly()
将解析为您项目的程序集(包含 Profile
classes 的程序集)。当您通过单元测试项目启动项目时,入口点实际上是该单元测试。
这意味着此代码实际上并未找到配置文件,因为它们不在该程序集中:
builder.Services
.AddAutoMapper(Assembly.GetEntryAssembly());
通常我在这种情况下所做的是使用typeof(someAssemblyInMyProject).Assembly
。在这个例子中,我使用 Program
但任何 class 都应该可以工作,只要它与 Profile
classes:
builder.Services
.AddAutoMapper(typeof(Program).Assembly);
现在,无论入口程序集是什么,您仍然可以找到正确的配置文件列表。