jamesmh / coravel

Near-zero config .NET library that makes advanced application features like Task Scheduling, Caching, Queuing, Event Broadcasting, and more a breeze!
https://docs.coravel.net/Installation/
MIT License
3.83k stars 252 forks source link

ScheduleWithParams not working with DI #315

Closed umerkle closed 1 year ago

umerkle commented 1 year ago

Hi!

I tried to use 'ScheduleWithParams' but got somehow in conflict with DI.

The constructor of my IInvocable looks like this: public LdapBaseWorkerNovell(IServiceProvider serviceProvider, DaprClient daprClient, IOptions<HistorySettings> historySettings, SingleWorkerConfigSetting workerConfig)

All of the arguments should be injected by DI, except the last one 'SingleWorkerConfigSetting workerConfig'.

I schedule like this: scheduler.ScheduleWithParams<LdapGroupReadWorkerNovell>(jobConfig).Cron(cron).PreventOverlapping(jobConfig.WorkerClass);

But when i start my app, i get the following error:

System.AggregateException: Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: Ldap.Adapter.Backend.Service.Jobs.LdapPersonReadWorkerNovell Lifetime: Transient ImplementationType: Ldap.Adapter.Backend.Service.Jobs.LdapPersonReadWorkerNovell': Unable to resolve service for type 'Ldap.Adapter.Backend.Service.Application.Options.SingleWorkerConfigSetting' while attempting to activate 'Ldap.Adapter.Backend.Service.Jobs.LdapPersonReadWorkerNovell'.) (Error while validating the service descriptor 'ServiceType: Ldap.Adapter.Backend.Service.Jobs.LdapGroupReadWorkerNovell Lifetime: Transient ImplementationType: Ldap.Adapter.Backend.Service.Jobs.LdapGroupReadWorkerNovell': Unable to resolve service for type 'Ldap.Adapter.Backend.Service.Application.Options.SingleWorkerConfigSetting' while attempting to activate 'Ldap.Adapter.Backend.Service.Jobs.LdapGroupReadWorkerNovell'.) ---> System.InvalidOperationException: Error while validating the service descriptor 'ServiceType: Ldap.Adapter.Backend.Service.Jobs.LdapPersonReadWorkerNovell Lifetime: Transient ImplementationType: Ldap.Adapter.Backend.Service.Jobs.LdapPersonReadWorkerNovell': Unable to resolve service for type 'Ldap.Adapter.Backend.Service.Application.Options.SingleWorkerConfigSetting' while attempting to activate 'Ldap.Adapter.Backend.Service.Jobs.LdapPersonReadWorkerNovell'. ---> System.InvalidOperationException: Unable to resolve service for type 'Ldap.Adapter.Backend.Service.Application.Options.SingleWorkerConfigSetting' while attempting to activate 'Ldap.Adapter.Backend.Service.Jobs.LdapPersonReadWorkerNovell'. at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(ServiceDescriptor serviceDescriptor, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceProvider.ValidateService(ServiceDescriptor descriptor) --- End of inner exception stack trace --- at Microsoft.Extensions.DependencyInjection.ServiceProvider.ValidateService(ServiceDescriptor descriptor) at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection1 serviceDescriptors, ServiceProviderOptions options) --- End of inner exception stack trace --- at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection1 serviceDescriptors, ServiceProviderOptions options) at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services, ServiceProviderOptions options) at Microsoft.Extensions.DependencyInjection.DefaultServiceProviderFactory.CreateServiceProvider(IServiceCollection containerBuilder) at Microsoft.Extensions.Hosting.Internal.ServiceFactoryAdapter1.CreateServiceProvider(Object containerBuilder) at Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider() at Microsoft.Extensions.Hosting.HostBuilder.Build() at Microsoft.AspNetCore.Builder.WebApplicationBuilder.Build() at Program.

$(String[] args) in C:\GIT\gis\microservices\ldap.adapter\Ldap.Adapter.Backend.Service\Program.cs:line 52 ---> (Inner Exception #1) System.InvalidOperationException: Error while validating the service descriptor 'ServiceType: Ldap.Adapter.Backend.Service.Jobs.LdapGroupReadWorkerNovell Lifetime: Transient ImplementationType: Ldap.Adapter.Backend.Service.Jobs.LdapGroupReadWorkerNovell': Unable to resolve service for type 'Ldap.Adapter.Backend.Service.Application.Options.SingleWorkerConfigSetting' while attempting to activate 'Ldap.Adapter.Backend.Service.Jobs.LdapGroupReadWorkerNovell'. ---> System.InvalidOperationException: Unable to resolve service for type 'Ldap.Adapter.Backend.Service.Application.Options.SingleWorkerConfigSetting' while attempting to activate 'Ldap.Adapter.Backend.Service.Jobs.LdapGroupReadWorkerNovell'. at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(ServiceDescriptor serviceDescriptor, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceProvider.ValidateService(ServiceDescriptor descriptor) --- End of inner exception stack trace --- at Microsoft.Extensions.DependencyInjection.ServiceProvider.ValidateService(ServiceDescriptor descriptor) at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection1 serviceDescriptors, ServiceProviderOptions options)

umerkle commented 1 year ago

Investigated a bit in Coravel's code and i think the problem is, that ScheduledEvent is created with just the additional parameter list. The GetInvocable of ScheduledEvent then tries to get an instance with ActivatorUtilities.CreateInstance. As i understand that method, if you provide it a list of parameters, it tries to find a constructor with exactly that list of parameters. But since Coravel is giving it just the additional parameters and not also the parameters from to be resolved from DI, it seems it is not finding a suitable constructor. What do you think?

umerkle commented 1 year ago

OK, i think i found the root cause.

I added the Invocables also as Transient to the DI. Then it was not possible for DI to create them without the additional parameters. But since that is not really needed, i removed that and now it works like a charm :-)

jamesmh commented 1 year ago

Glad you could solve this. I think the original issue was that the type you were passing into the ScheduleWithParams method - which was LdapGroupReadWorkerNovell - was not the same type as the one in the constructor arguments - which was SingleWorkerConfigSetting.

So doing something like scheduler.ScheduleWithParams<SingleWorkerConfigSetting>... might have fixed it too.

👍