Simple Injector CrossWiring使用困惑与问题咨询
你的场景完全可行,Simple Injector专门设计了与Microsoft.Extensions.DependencyInjection(MSDI)的集成方案,用于封装类库的高级DI功能(装饰器、条件注册等)给原生DI用户使用。你遇到的两个问题本质是双向配置不完整和服务注册可见性缺失,以下是针对性解决方案:
问题1:IServiceProvider无法解析Simple Injector注册的App
原因
App仅注册在Simple Injector容器中,MSDI的ServiceProvider对该类型完全不知情,自然无法解析。只有服务被注册到IServiceCollection后,MSDI才能识别并处理。
解决方案
在ConfigureServices中,将App注册到MSDI,但委托Simple Injector容器创建实例:
.ConfigureServices((hostBuilderContext, services) => { container.RegisterSingleton<App>(); services.AddSingleton<ISaySomethingService, SaySomethingService>(); services.AddSimpleInjector(container); // 新增:把Simple Injector中的App桥接到MSDI services.AddSingleton<App>(sp => sp.GetRequiredService<Container>().GetInstance<App>()); })
修改后,调用host.Services.GetRequiredService<App>()时,MSDI会委托Simple Injector创建实例,同时依赖链(如App依赖的ISaySomethingService)可通过跨接线正常解析。
问题2:添加options.AddLogging()后跨接线服务无法获取ILogger
原因
错误信息显示MSDI无法解析ILogger,核心问题:
- MSDI默认仅注册泛型日志接口
ILogger<T>,而非非泛型ILogger - 你的
SaySomethingService构造函数依赖的是ILogger,而非推荐的ILogger<SaySomethingService> - 启用Simple Injector的
AddLogging()后,跨接线服务仍由MSDI创建,但MSDI中无ILogger注册
解决方案
有两种可选方式:
方式1:改用泛型日志接口(推荐)
修改SaySomethingService的构造函数依赖为ILogger<SaySomethingService>:
public class SaySomethingService : ISaySomethingService { private readonly ILogger<SaySomethingService> _logger; public SaySomethingService(ILogger<SaySomethingService> logger) { _logger = logger; } // 其他业务代码 }
这是MSDI日志系统的标准用法,无需额外配置。
方式2:注册非泛型ILogger(兼容旧代码)
若必须保留非泛型ILogger依赖,在ConfigureServices中添加:
services.AddSingleton<ILogger>(sp => sp.GetRequiredService<ILoggerFactory>().CreateLogger("Default"));
这样MSDI就能解析非泛型ILogger,跨接线服务可正常创建。
类库封装适配方案(核心需求落地)
针对「类库用Simple Injector实现高级DI功能,让原生DI开发者无感知调用」的场景,正确的封装方式如下:
1. 类库中编写扩展方法,封装Simple Injector逻辑
public static class MyLibraryServiceCollectionExtensions { public static IServiceCollection AddMyLibrary(this IServiceCollection services) { // 创建并配置Simple Injector容器 var container = new Container { Options = { DefaultScopedLifestyle = new AsyncScopedLifestyle() } }; // 注册类库内部服务(含装饰器、条件注册等) container.RegisterSingleton<App>(); // 示例:添加装饰器 // container.RegisterDecorator<ISaySomethingService, LoggingSaySomethingDecorator>(); // 集成MSDI并自动处理跨接线 services.AddSimpleInjector(container, options => { options.AddLogging(); options.CrossWireServices = true; // 自动跨接线MSDI服务到Simple Injector }); // 将类库对外服务桥接到MSDI,让原生DI可直接解析 services.AddSingleton<App>(sp => sp.GetRequiredService<Container>().GetInstance<App>()); // 其他对外服务同理注册 // 验证Simple Injector配置(开发环境建议启用) container.Verify(); return services; } }
2. 主应用调用方式(开发者无需关心Simple Injector)
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; var host = Host.CreateDefaultBuilder(args) .ConfigureServices(services => { // 开发者只需调用类库扩展方法 services.AddMyLibrary(); // 开发者仍可正常注册自己的MSDI服务 services.AddSingleton<ISaySomethingService, SaySomethingService>(); }) .Build(); // 直接通过IServiceProvider解析类库服务 var app = host.Services.GetRequiredService<App>(); await app.Run();
关键注意事项
- 双向可见性:类库对外暴露的服务必须同时注册到MSDI(委托Simple Injector创建),否则原生DI无法解析。
- 跨接线时机:使用Simple Injector的官方集成扩展
AddSimpleInjector自动处理跨接线,避免手动操作的时机问题。 - 日志兼容:优先使用
ILogger<T>,减少额外配置成本。
内容的提问来源于stack exchange,提问作者Stephen York

