无法从根提供者处解析作用域服务 "Services.Contracts.IHandler`1[Services.ProcessFile]"。

问题描述 投票:0回答:1

我正在为net core background queue worker创建处理程序。

    // 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 类中,我注册了所有的处理程序。

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)

谁能帮我找出我遗漏了什么?

c# .net asp.net-core backgroundworker service-provider
1个回答
1
投票

你正在创建一个新的作用域,但你并没有从它中解析服务。相反,你是在解析来自 原有 服务提供商。你需要从范围的 ServiceProvider 而不是。

using(var scp = _serviceProvider.CreateScope()) {
   var handler = scp.ServiceProvider.GetRequiredService<IHandler<T>>();
   await handler.Handle(workItem, cancellationToken);
} 
© www.soinside.com 2019 - 2024. All rights reserved.