如何确定ASP.NET Core中承载DI类的BackgroundService具体类型
解决方案
方案1:为每个后台服务注册专属服务实例(最简单适配NopCommerce 4.4场景)
NopCommerce 4.4基于.NET 6开发,原生支持Keyed Service特性,你可以给每个BackgroundService对应的依赖注册带唯一标识的实现,在后台服务构造时注入对应实例即可:
- 首先定义所有后台服务的唯一标识,枚举类型即可:
public enum BackgroundServiceType { StoreAJob, StoreBJob, StoreCJob }
- 注册依赖时使用Keyed注册绑定标识,以依赖接口
IStoreDataService为例:
// 注册每个店铺对应的专属实例 builder.Services.AddKeyedScoped<IStoreDataService, StoreDataService>(BackgroundServiceType.StoreAJob, (sp, key) => { var service = new StoreDataService(); // 直接给当前实例绑定所属宿主服务标识 service.HostServiceType = (BackgroundServiceType)key; return service; }); // 其余店铺的依赖按相同规则依次注册
- 对应BackgroundService构造时用
FromKeyedServices特性注入匹配实例:
public class StoreABackgroundService : BackgroundService { private readonly IStoreDataService _storeDataService; public StoreABackgroundService([FromKeyedServices(BackgroundServiceType.StoreAJob)] IStoreDataService storeDataService) { _storeDataService = storeDataService; } // 后续业务逻辑直接调用即可,注入的实例已经明确所属宿主 }
该方案逻辑简单,无需修改依赖层核心代码,也不会和前台请求的注入逻辑产生冲突。
方案2:用AsyncLocal上下文动态传递宿主标识(适合依赖动态解析的场景)
如果依赖是在后台服务执行过程中通过子Scope动态解析的,不是构造函数直接注入的,可以用AsyncLocal绑定异步执行上下文传递标识:
- 定义全局静态上下文类:
public static class BackgroundServiceContext { private static readonly AsyncLocal<BackgroundServiceType> _currentService = new(); public static BackgroundServiceType? CurrentService { get => _currentService.Value; set => _currentService.Value = value; } }
- 在每个BackgroundService的执行入口设置上下文标识:
protected override async Task ExecuteAsync(CancellationToken stoppingToken) { // 进入业务逻辑前先设置当前服务标识 BackgroundServiceContext.CurrentService = BackgroundServiceType.StoreAJob; while (!stoppingToken.IsCancellationRequested) { // 业务逻辑,不管是直接使用构造注入的依赖,还是新开Scope解析的依赖,都可以读取BackgroundServiceContext.CurrentService拿到所属宿主 await Task.Delay(1000, stoppingToken); } }
AsyncLocal和异步执行链绑定,不会出现不同后台服务上下文串扰的问题。
方案3:用工厂模式创建依赖实例(兼容低版本.NET的备选方案)
如果不想依赖Keyed Service特性,也可以自行实现工厂生成对应服务实例:
- 定义工厂接口:
public interface IStoreDataServiceFactory { IStoreDataService Create(BackgroundServiceType serviceType); }
- 实现工厂逻辑:
public class StoreDataServiceFactory : IStoreDataServiceFactory { private readonly IServiceProvider _serviceProvider; public StoreDataServiceFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public IStoreDataService Create(BackgroundServiceType serviceType) { var service = ActivatorUtilities.CreateInstance<StoreDataService>(_serviceProvider); service.HostServiceType = serviceType; return service; } }
- 在BackgroundService中注入工厂创建匹配实例:
public class StoreABackgroundService : BackgroundService { private readonly IStoreDataService _storeDataService; public StoreABackgroundService(IStoreDataServiceFactory factory) { _storeDataService = factory.Create(BackgroundServiceType.StoreAJob); } }
内容的提问来源于stack exchange,提问作者Terry Mitchell
相关产品推荐
相关产品推荐

