如何让AutoMapper映射对象列表时复用自定义转换器实例
问题原因
默认调用services.AddAutoMapper(assemblies)进行AutoMapper服务注册时,程序集扫描到的自定义ITypeConverter、IValueResolver等映射组件,会被默认注册为**瞬态(Transient)**生命周期。在映射集合类型时,每个元素的转换逻辑都会单独触发一次转换器的服务解析,因此每次都会生成新的转换器实例。
解决方案
根据你当前的代码场景(转换器依赖Scoped生命周期的ISomeService),最适配的方案是显式指定自定义转换器的DI生命周期,让AutoMapper从DI容器解析转换器时遵循你指定的生命周期规则,实现实例复用。
方案1:显式注册转换器为Scoped生命周期(推荐,适配当前场景)
在ConfigureServices方法中,在AddAutoMapper调用后追加自定义转换器的Scoped生命周期注册即可,AutoMapper不会覆盖你手动指定的服务生命周期:
services.AddScoped<ISomeService, SomeService>(); services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); // 追加这行,指定转换器为Scoped生命周期 services.AddScoped<FromToTypeConverter>();
配置后,在同一个DI作用域(例如ASP.NET Core的单个HTTP请求)内,所有映射操作都会复用同一个FromToTypeConverter实例,和你注入的ISomeService生命周期完全匹配,不会出现依赖逃逸问题。
方案2:直接传入转换器实例(仅适合无Scoped依赖的场景)
如果你的转换器没有Scoped依赖,也可以在映射配置时直接传入已经实例化好的转换器对象,AutoMapper会全局复用这一个实例:
// 注意:需要自行手动提供构造函数所需的所有依赖 var converter = new FromToTypeConverter(loggerInstance, someServiceInstance); CreateMap<From, To>().ConvertUsing(converter);
注意:该方式注册的转换器是全局单例的,如果持有Scoped生命周期的服务,会出现依赖被异常持有、对象已释放访问错误、跨请求状态污染等问题,不要在当前依赖Scoped服务的场景下使用。
注意事项
- 不要将持有Scoped依赖的转换器注册为Singleton生命周期,否则会产生Captive Dependency(长生命周期对象持有短生命周期对象)问题,引发服务异常。
- 显式注册转换器时,生命周期必须大于等于其依赖服务的生命周期,你当前场景下Scoped是最优选择。
内容的提问来源于stack exchange,提问作者Jom
相关产品推荐
相关产品推荐

