Scheduled job not running with dependency injection for my custom service injected

Vote:
 

Hi,

I am facing an issue with scheduled job, that its not able to start automatically. I am getting below error:

UnableToStart Exception has been thrown by the target of an invocation. [Activation error occurred while trying to get instance of type ILogisticProductsService, key ""]

I have a sercvice injected into scheduled job constructor. The job works fine if I manually trigger the job. 

code snipest:

public class AgrodeskSendLogisticProductsJob : ScheduledJobBase
    {
        private readonly ILogisticProductsService _logisticProductsService;

        public AgrodeskSendLogisticProductsJob()
        {
            _logisticProductsService = ServiceLocator.Current.GetInstance<ILogisticProductsService>();
        }
        public AgrodeskSendLogisticProductsJob(ILogisticProductsService logisticProductsService)
        {
            _logisticProductsService = logisticProductsService;
        }
        private static IUserImpersonation UserImpersonation
        {
            get { return ServiceLocator.Current.GetInstance<IUserImpersonation>(); }
        }

        public override string Execute()
        {
            PrincipalInfo.CurrentPrincipal = UserImpersonation.CreatePrincipal("saam.farmer@lm2.com");
            _logisticProductsService.SendProducts();

            return "OK";
        }

    }

The dependancies are resolved in dependancy resolver.

 container.For<ILogisticProductsService>().Use<LogisticProductsService>();

anyone could you help whats wrong with this approach?

#275959
Mar 09, 2022 11:44
Vote:
 

The use of service locator is concerning me! 😊 Why don't you just switch to DI?

public class AgrodeskSendLogisticProductsJob : ScheduledJobBase
{
	private readonly ILogisticProductsService _logisticProductsService;
	private readonly IUserImpersonation _userImpersonation;

	public AgrodeskSendLogisticProductsJob(ILogisticProductsService logisticProductsService, IUserImpersonation userImpersonation)
	{
		_logisticProductsService = logisticProductsService;
		_userImpersonation = userImpersonation;
	}

	public override string Execute()
	{
		PrincipalInfo.CurrentPrincipal = _userImpersonation.CreatePrincipal("saam.farmer@lm2.com");
		_logisticProductsService.SendProducts();

		return "OK";
	}
}

I'm thinking that your issue is potentially stemming from that fact that you have 2 constructors, I'm wondering if different one's are hit when it's a manual vs scheduled run. Although that stil doesn't really change things if you're registering the service correctly in the service container--which it looks like you are.

#275960
Mar 09, 2022 12:12
Vote:
 

Hello Jake,

Thank you for response.

Actually I did have only one constructor earlier with DI. but It started giveing error to have a default constructor in scheduledjob.

error was "The scheduled job of type 'Gro.ScheduledJob.AgrodeskSendLogisticProductsJob' cannot be created. It must either be registered in the IOC container or have a default constructor."

Thats the reason I created one default constructor with having servilocator.

#275962
Mar 09, 2022 13:19
Vote:
 

What version of the CMS are you using? If it's > 10.3 then jobs support DI: https://blog.tech-fellow.net/2016/12/28/scheduled-jobs-updates/

What happens if you remove your additional constructor then (and align your handling of dependencies):

public class AgrodeskSendLogisticProductsJob : ScheduledJobBase
{
	private readonly ILogisticProductsService _logisticProductsService;
	private readonly IUserImpersonation _userImpersonation;

	public AgrodeskSendLogisticProductsJob()
	{
		_logisticProductsService = ServiceLocator.Current.GetInstance<ILogisticProductsService>();
		_userImpersonation = ServiceLocator.Current.GetInstance<IUserImpersonation>();
	}
}

If you're still getting an exception I'd be interested to know whether the IUserImpersonation is resolving.

#275963
Mar 09, 2022 13:28
Vote:
 

My CMS version 11.20. 

I have already tried removing additional constructor and gettting instance through ServiceLocator. But the result is same.

I was under impression that it is not working because I am not impersonating an user with admin credentials. that the reason I added impersonation to impersonate and admin user account. But no luck with it.

#276044
Mar 10, 2022 7:01
Ted - Mar 10, 2022 8:10
Sounds like perhaps something is going wrong in the concrete implementation of ILogisticProductsService?
Vote:
 

Hi again,

Sorry if I wasn't clear--but I think Ted is on to something. I think you need to try narrowing down the problem and ruling things out.

  1. Are you using ILogisticProductsService elsewhere? If not, then how does the constructor look for it?
  2. What about if you try to resolve a standard Optimizely CMS service in the constructor, like IContentLoader, does that work? (i.e. remove all uses of ILogisticProductsService)

Based on your last response I think you should also remove usages of IUserImpersonation.

#276047
Edited, Mar 10, 2022 9:43
Vote:
 
public LogisticProductsService(FormDataRepository formDataRepository, IFormRepository formRepository, IEmailService client, IContentRepository contentRepository,
           SiteDefinitionRepository siteDefinitionRepository)
        {
            _formDataRepository = formDataRepository;
            _formRepository = formRepository;
            _client = client;
            _contentRepository = contentRepository;
            _siteDefinitionRepository = siteDefinitionRepository;
        }

This how my service constructor is defined for logistic service.

I tried with a default constructor. and creating instances for all those injected services using Servicelocator. But then it faild to create instance of IEmailService with same error.

It looks like it is failing to create instance only for customer services.

#276048
Mar 10, 2022 10:29
Vote:
 

Ok, well now we're getting somewhere.

Is IEmailService registered correctly? Or does it have a dependency that is not registered correctly? I'm pretty sure that's got to be your problem.

#276050
Mar 10, 2022 10:32
Vote:
 

Could you get the full log? It seems that one of the dependency could not be resolved down the line. and given that you can run it manually, it might have something with the account

#276060
Mar 10, 2022 17:03
Vote:
 

You mentioned that the job works if you trigger it manually. One big difference when running a job manually vs automatically is the presence of the HttpContext. Does IEmailService depend on the HttpContext?

If so, you need to refactor the IEmailService into something that can run without the HttpContext.

#276848
Mar 22, 2022 11:17
Vote:
 

I also experienced the error "The scheduled job of type 'XZXZ' cannot be created. It must either be registered in the IOC container or have a default constructor.". In my case it was one of the injected dependencies that threw an exception in its constructor when it was trying to access Azure Keyvault. The failure was due to AK no longer accepting clients using TLS 1.0. A server configuration issue, in other words. 

#310773
Oct 13, 2023 9:34
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.