【发布时间】:2022-01-12 20:01:28
【问题描述】:
我创建了一个具有两种模型的 .Net Core 5 API:
- 实体(由 Entity Framework Core 使用)
- DTO(请求和响应的数据传输对象,将实体中的“{Property}Id”属性替换为 DTO 中的“{Property}Code”)
我有一个服务负责将实体类型映射到在 ConfigureServices 中作为单例添加的 Dtos 类型:
services.AddSingleton(typeof(IEntityDtoMappingProvider), typeof(EntityDtoMappingProvider));
EntityDtoMappingProvider服务有一个方法,该方法通过该接口描述的反射返回一个程序集的实体和Dtos之间的映射:
public interface IEntityDtoMappingProvider
{
Dictionary<Type,Type> GetEntityDtoMapping(Assembly assembly);
}
我有一个 AutoMapper 配置文件,需要映射的实体和 DTO,由第一个服务 IEntityDtoMappingProvider 返回:
public class EntitiesToDtosProfile : Profile
{
public EntitiesToDtosProfile(Dictionary<Type,Type> mapping)
{
if (mapping == null || mapping.Count == 0)
{
throw new ArgumentException( $"Empty mapping argument passed to {nameof(EntitiesToDtosProfile)} profile", nameof(mapping));
}
foreach(var item in mapping)
{
// Create AutoMapper mapping both ways based on those types
CreateMap(item.Key, item.Value); // Entity-DTO
CreateMap(item.Value, item.Key); // DTO-Entity
}
}
}
我需要在 ConfigureServices 方法的 Startup.cs 中创建 AutoMapper 配置文件:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddSingleton(typeof(IEntityDtoMappingProvider), typeof(EntityDtoMappingProvider));
// Note: Using services.BuildServiceProvider() is a bad practice because an additional copy of singleton services being created
using (var serviceProvider = services.BuildServiceProvider())
{
var mappingService = serviceProvider.GetRequiredService<IEntityDtoMappingProvider>();
var mappings = mappingService.GetEntityDtoMapping(typeof(Workflow).Assembly);
// Add AutoMapper IMapper to services
var mappingConfig = new MapperConfiguration(mc =>
{
mc.AddProfile(new EntitiesToDtosProfile(mappings));
});
var mapper = mappingConfig.CreateMapper();
services.AddSingleton(mapper);
// Here I should call other IServiceCollection extensions like:
// Database-related services: GenericRepository<TEntity, TDbContext> : IGenericRepository<TEntity>
services.AddDatabaseGenericRepositories<ApplicationDbContext>(mappings, Log.Logger);
// Mapping-related services: MappingHelper<TEntity, TDto> : IMappingHelper<TEntity, TDto>
services.AddMappingHelpers(mappings, Log.Logger);
// ...
}
// ...
}
正如我在代码中所说,使用 services.BuildServiceProvider() 是一种不好的做法,因为正在创建的单例服务的附加副本会创建第二个容器,这可能会创建撕裂的单例并导致跨多个容器引用对象图。 Microsoft .Net Core 5 documentation backing those statements.
请回答我应该如何使用 IEntityDtoMappingProvider 在 CreateServices 中创建类型为 Dictionary
- 我使用 IServiceCollection 的扩展方法通过反射创建了许多服务需要在 ConfigureServices 中进行 Entity-DTO 映射
- 我不能使用具有 Dictionary
类型属性的 IOptions,因为不应在 ConfigureServices 中使用 IOptions:"由于服务注册的顺序,可能存在不一致的选项状态。”来源:IOptions Microsoft Documentation. - 我查看了alotofquestions(有些可能有点无关),但都使用 services.BuildServiceProvider() 或 IOptions 解决了他们的问题 这不行。
【问题讨论】:
-
如果您只是注册
IEntityDtoMappingProvider以便使用它来构建您的映射组件,那么也许您不应该注册它。 -
好点,我只用它来创建一个 AutoMapper 配置文件 (EntitiesToDtosProfile) 并通过映射循环的反射创建大量服务。我可能会丢失接口并只创建实例,而根本不注册它。您可以创建它作为答案,如果没有更好的结果,我会接受它。
-
完成。有时最简单的解决方案是最好的。
标签: c# dependency-injection asp.net-core-5.0