.NET Core 2.0无控制器获取单例服务及AutoMapper注入问题
1. 无需控制器获取Singleton服务的方法
当然有!不过得根据你的使用场景选合适的方式,这里给你两种常见方案:
方案一:构造函数注入(推荐)
这是.NET Core依赖注入的最佳实践——不管是不是控制器,只要你的类由DI容器管理(比如注册为服务),就能直接通过构造函数注入Singleton服务。比如你有个自定义工具类:
public class MyBusinessService { private readonly IMapper _mapper; // 构造函数直接注入Singleton的IMapper public MyBusinessService(IMapper mapper) { _mapper = mapper; } public void ProcessData() { // 直接使用注入的_mapper } }
然后在Startup.cs里注册这个服务:
services.AddSingleton<MyBusinessService>();
DI容器会自动把Singleton的IMapper注入到MyBusinessService里,全程不需要控制器参与。
方案二:从IServiceProvider直接获取(仅特殊场景用)
如果你的类不是DI容器管理的(比如静态类、手动实例化的类),可以通过IServiceProvider拿Singleton服务,但这种方式不推荐——会让代码耦合度变高,不好测试。
比如在Startup的Configure方法里,你能直接拿到IServiceProvider:
public void Configure(IApplicationBuilder app, IServiceProvider serviceProvider) { // 获取Singleton的IMapper var mapper = serviceProvider.GetRequiredService<IMapper>(); // 在这里用mapper做初始化等操作 }
要是需要在其他地方用,也可以在Startup里把IServiceProvider存为静态属性(注意内存泄漏风险,谨慎使用):
public static IServiceProvider ServiceProvider { get; private set; } public void Configure(IApplicationBuilder app, IServiceProvider serviceProvider) { ServiceProvider = serviceProvider; }
之后在其他地方就能这么用:
var mapper = Startup.ServiceProvider.GetRequiredService<IMapper>();
2. 在ApplicationService基类中以属性形式获取AutoMapper单例
既然你已经在Startup里注册了Singleton的IMapper,最优雅的方式是基类构造函数注入,把IMapper赋值给受保护属性,这样所有子类都能直接用,完全符合依赖注入原则,还不用静态属性。
实现步骤:
- 改造ApplicationService基类,添加构造函数注入并定义属性:
public abstract class ApplicationService { // 受保护属性,子类可直接访问 protected IMapper Mapper { get; } protected ApplicationService(IMapper mapper) { Mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); } }
- 子类TaskAppService继承时,只需在构造函数里把IMapper传给基类:
public class TaskAppService : ApplicationService { // 子类有自己的依赖也可以一起注入 public TaskAppService(IMapper mapper, ITaskRepository taskRepo) : base(mapper) { // 处理子类自己的依赖 } public async Task<TaskDto> GetTaskAsync(int id) { var task = await taskRepo.GetByIdAsync(id); // 直接用基类的Mapper属性 return Mapper.Map<TaskDto>(task); } }
这样所有继承ApplicationService的子类都能直接用Mapper属性,不用每个子类单独注入IMapper,还避开了静态属性的各种坑。
如果实在想用属性注入(比如不想写构造函数),得引入第三方DI容器(比如Autofac)——因为.NET Core原生DI不支持属性注入。不过还是更推荐构造注入,它更清晰,也更容易测试和维护。
内容的提问来源于stack exchange,提问作者alan zhang

