简体   繁体   中英

Cannot resolve scoped service 'Services.Contracts.IHandler`1[Services.ProcessFile]' from root provider

I am creating handlers for 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;
      }
    }

In my startup.cs class I am registering all of them:

services.AddHostedService<QueuedHostedService<ProcessFile>>();
 services.AddSingleton<IBackgroundTaskQueue<ProcessFile>, BackgroundTaskQueue<ProcessFile>>();
 services.AddScoped<IImportService, ImportService>();
 services.AddScoped<IHandler<ProcessFile>, FileProcessor>();

Finally in one of the services I add item to the queue:


    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));
      }


    }

Seems like I am injecting all of the needed services but I am getting this error:

  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)

Could someone help me figure out what I am missing here?

You are creating a new scope, but you aren't resolving the services from it. Instead you are resolving services from the original service provider. You need to resolve from the scope's ServiceProvider instead:

using(var scp = _serviceProvider.CreateScope()) {
   var handler = scp.ServiceProvider.GetRequiredService<IHandler<T>>();
   await handler.Handle(workItem, cancellationToken);
} 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM