无法解析来自根提供商的作用域服务 'Services.Contracts.IHandler`1[Services.ProcessFile]'
Cannot resolve scoped service 'Services.Contracts.IHandler`1[Services.ProcessFile]' from root provider
我正在为网络核心后台队列工作者创建处理程序。
// Generic class, reused for different handlers
public class QueuedHostedService < T >: BackgroundService {
private readonly ILogger _logger;
private readonly IServiceProvider _serviceProvider;
public QueuedHostedService(IServiceProvider serviceProvider, IBackgroundTaskQueue < T > taskQueue, ILoggerFactory loggerFactory) {
_serviceProvider = serviceProvider;
TaskQueue = taskQueue;
_logger = loggerFactory.CreateLogger < QueuedHostedService < T >> ();
}
public IBackgroundTaskQueue < T > TaskQueue {
get;
}
protected override async Task ExecuteAsync(CancellationToken cancellationToken) {
while (!cancellationToken.IsCancellationRequested) {
T workItem = await TaskQueue.DequeueAsync(cancellationToken);
try {
using(var scp = _serviceProvider.CreateScope()) {
var handler = _serviceProvider.GetRequiredService < IHandler < T >> ();
await handler.Handle(workItem, cancellationToken);
}
} catch (Exception ex) {}
}
}
}
// Generic queue class
public class BackgroundTaskQueue < T >: IBackgroundTaskQueue < T > {
private ConcurrentQueue < T > _workItems = new ConcurrentQueue < T > ();
private SemaphoreSlim _signal = new SemaphoreSlim(0);
public void QueueBackgroundWorkItem(T workItem) {
if (workItem == null) {
throw new ArgumentNullException(nameof(workItem));
}
_workItems.Enqueue(workItem);
_signal.Release();
}
public async Task < T > DequeueAsync(CancellationToken cancellationToken) {
await _signal.WaitAsync(cancellationToken);
_workItems.TryDequeue(out
var workItem);
return workItem;
}
}
// handler interface
public interface IHandler < T > {
Task Handle(T message, CancellationToken token);
}
//Handler
public class FileProcessor: IHandler < ProcessFile >
{
public IServiceProvider Services {
get;
}
public FileProcessor(IServiceProvider services) {
Services = services;
}
public async Task Handle(ProcessFile fileToProcess, CancellationToken token) {
// do the processing logic
}
}
public class ProcessFile {
public string TempFilePath {
get;
set;
}
public FileFormatType FileFormat {
get;
set;
}
public IFormFile File {
get;
set;
}
public Type Type {
get;
set;
}
public int UserId {
get;
set;
}
public ProcessFile(string tempFilePath, FileFormatType fileFormat, IFormFile file,
Type type, int userId) {
TempFilePath = tempFilePath;
FileFormat = fileFormat;
File = file;
Type = type;
UserId = userId;
}
}
在我的 startup.cs class 中,我正在注册所有这些:
services.AddHostedService<QueuedHostedService<ProcessFile>>();
services.AddSingleton<IBackgroundTaskQueue<ProcessFile>, BackgroundTaskQueue<ProcessFile>>();
services.AddScoped<IImportService, ImportService>();
services.AddScoped<IHandler<ProcessFile>, FileProcessor>();
最后,在其中一项服务中,我将项目添加到队列中:
public class ImportService: BaseService, IImportService {
private readonly IFileProcessingService _scopedProcessingService;
private readonly ConfigurationSettings _configurationSettings;
public IBackgroundTaskQueue < ProcessFile > Queue {
get;
}
private
const string AZURE_BLOB_CONTAINER = "blobcontainer";
public IServiceProvider Services {
get;
}
public ImportService(IServiceProvider services, IBackgroundTaskQueue < ProcessFile > queue): base(services) {
Services = services;
_configurationSettings = services.GetService < ConfigurationSettings > ();
_scopedProcessingService = services.GetProcessingService();
Queue = queue;
}
// ---- Main file
public async Task ImportFile(string filePath, long fileSize, int userId, FileFormatType fileFormat, string delimiter, string dateFormat) {
await _scopedProcessingService.ImportFile(filePath, fileSize, userId, fileFormat, dataHeadersMap, delimiter, dateFormat);
}
public async Task UploadToBlobStorage(IFormFile file, int userId, TransactionalDataFileType type) {
//....
ProcessFile(tempFilePath, fileFormat, file, type, userId);
}
private void ProcessFile(string tempFilePath, FileFormatType fileFormat, IFormFile file, Type type, int userId) {
Queue.QueueBackgroundWorkItem(new ProcessFile(tempFilePath, fileFormat, file, type, userId));
}
}
似乎我正在注入所有需要的服务,但我收到了这个错误:
Error occurred executing workItem.
System.InvalidOperationException: Cannot resolve scoped service 'Services.Services.Contracts.IHandler1[Services.Services.ProcessFile]' from root provider.
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(Type serviceType, IServiceScope scope, IServiceScope rootScope)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.Microsoft.Extensions.DependencyInjection.ServiceLookup.IServiceProviderEngineCallback.OnResolve(Type serviceType, IServiceScope scope)
有人可以帮我弄清楚我在这里遗漏了什么吗?
您正在创建一个新范围,但您没有从中解析服务。相反,您正在解析来自 原始 服务提供商的服务。您需要从范围的 ServiceProvider
中解析:
using(var scp = _serviceProvider.CreateScope()) {
var handler = scp.ServiceProvider.GetRequiredService<IHandler<T>>();
await handler.Handle(workItem, cancellationToken);
}
我正在为网络核心后台队列工作者创建处理程序。
// Generic class, reused for different handlers
public class QueuedHostedService < T >: BackgroundService {
private readonly ILogger _logger;
private readonly IServiceProvider _serviceProvider;
public QueuedHostedService(IServiceProvider serviceProvider, IBackgroundTaskQueue < T > taskQueue, ILoggerFactory loggerFactory) {
_serviceProvider = serviceProvider;
TaskQueue = taskQueue;
_logger = loggerFactory.CreateLogger < QueuedHostedService < T >> ();
}
public IBackgroundTaskQueue < T > TaskQueue {
get;
}
protected override async Task ExecuteAsync(CancellationToken cancellationToken) {
while (!cancellationToken.IsCancellationRequested) {
T workItem = await TaskQueue.DequeueAsync(cancellationToken);
try {
using(var scp = _serviceProvider.CreateScope()) {
var handler = _serviceProvider.GetRequiredService < IHandler < T >> ();
await handler.Handle(workItem, cancellationToken);
}
} catch (Exception ex) {}
}
}
}
// Generic queue class
public class BackgroundTaskQueue < T >: IBackgroundTaskQueue < T > {
private ConcurrentQueue < T > _workItems = new ConcurrentQueue < T > ();
private SemaphoreSlim _signal = new SemaphoreSlim(0);
public void QueueBackgroundWorkItem(T workItem) {
if (workItem == null) {
throw new ArgumentNullException(nameof(workItem));
}
_workItems.Enqueue(workItem);
_signal.Release();
}
public async Task < T > DequeueAsync(CancellationToken cancellationToken) {
await _signal.WaitAsync(cancellationToken);
_workItems.TryDequeue(out
var workItem);
return workItem;
}
}
// handler interface
public interface IHandler < T > {
Task Handle(T message, CancellationToken token);
}
//Handler
public class FileProcessor: IHandler < ProcessFile >
{
public IServiceProvider Services {
get;
}
public FileProcessor(IServiceProvider services) {
Services = services;
}
public async Task Handle(ProcessFile fileToProcess, CancellationToken token) {
// do the processing logic
}
}
public class ProcessFile {
public string TempFilePath {
get;
set;
}
public FileFormatType FileFormat {
get;
set;
}
public IFormFile File {
get;
set;
}
public Type Type {
get;
set;
}
public int UserId {
get;
set;
}
public ProcessFile(string tempFilePath, FileFormatType fileFormat, IFormFile file,
Type type, int userId) {
TempFilePath = tempFilePath;
FileFormat = fileFormat;
File = file;
Type = type;
UserId = userId;
}
}
在我的 startup.cs class 中,我正在注册所有这些:
services.AddHostedService<QueuedHostedService<ProcessFile>>();
services.AddSingleton<IBackgroundTaskQueue<ProcessFile>, BackgroundTaskQueue<ProcessFile>>();
services.AddScoped<IImportService, ImportService>();
services.AddScoped<IHandler<ProcessFile>, FileProcessor>();
最后,在其中一项服务中,我将项目添加到队列中:
public class ImportService: BaseService, IImportService {
private readonly IFileProcessingService _scopedProcessingService;
private readonly ConfigurationSettings _configurationSettings;
public IBackgroundTaskQueue < ProcessFile > Queue {
get;
}
private
const string AZURE_BLOB_CONTAINER = "blobcontainer";
public IServiceProvider Services {
get;
}
public ImportService(IServiceProvider services, IBackgroundTaskQueue < ProcessFile > queue): base(services) {
Services = services;
_configurationSettings = services.GetService < ConfigurationSettings > ();
_scopedProcessingService = services.GetProcessingService();
Queue = queue;
}
// ---- Main file
public async Task ImportFile(string filePath, long fileSize, int userId, FileFormatType fileFormat, string delimiter, string dateFormat) {
await _scopedProcessingService.ImportFile(filePath, fileSize, userId, fileFormat, dataHeadersMap, delimiter, dateFormat);
}
public async Task UploadToBlobStorage(IFormFile file, int userId, TransactionalDataFileType type) {
//....
ProcessFile(tempFilePath, fileFormat, file, type, userId);
}
private void ProcessFile(string tempFilePath, FileFormatType fileFormat, IFormFile file, Type type, int userId) {
Queue.QueueBackgroundWorkItem(new ProcessFile(tempFilePath, fileFormat, file, type, userId));
}
}
似乎我正在注入所有需要的服务,但我收到了这个错误:
Error occurred executing workItem.
System.InvalidOperationException: Cannot resolve scoped service 'Services.Services.Contracts.IHandler1[Services.Services.ProcessFile]' from root provider.
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(Type serviceType, IServiceScope scope, IServiceScope rootScope)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.Microsoft.Extensions.DependencyInjection.ServiceLookup.IServiceProviderEngineCallback.OnResolve(Type serviceType, IServiceScope scope)
有人可以帮我弄清楚我在这里遗漏了什么吗?
您正在创建一个新范围,但您没有从中解析服务。相反,您正在解析来自 原始 服务提供商的服务。您需要从范围的 ServiceProvider
中解析:
using(var scp = _serviceProvider.CreateScope()) {
var handler = scp.ServiceProvider.GetRequiredService<IHandler<T>>();
await handler.Handle(workItem, cancellationToken);
}