I've built a sample .NET 5 Web API application in VS2019, I had the default template (with WeatherForecastController
).
I've added Quartz.net (version 3.3.3) to project and in Startup
class I've added:
public void ConfigureServices(IServiceCollection services)
{
services.AddQuartz(q =>
{
q.UseMicrosoftDependencyInjectionJobFactory();
q.AddJobAndTrigger<HelloWorldJob>(Configuration);
});
// ASP.NET Core hosting
services.AddQuartzServer(options =>
{
// when shutting down we want jobs to complete gracefully
options.WaitForJobsToComplete = true;
});
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "QuartzTest", Version = "v1" });
});
}
and created a sample job.
The code for AddJobAndTrigger
is taken from https://andrewlock.net/using-quartz-net-with-asp-net-core-and-worker-services/
That part is working perfectly, but now I'd like to give the end-user the ability to trigger a specific job manually via rest API.
I've created a simple controller that should be able to trigger jobs manually by using:
scheduler.TriggerJob(new Jobkey("MarkAsSolutionReminderJob"));
(ref: Quartz.Net Trigger Scheduled Job On Demand)
Below is my controller:
[ApiController]
[Route("[controller]")]
public class QuartzController : ControllerBase
{
private readonly IScheduler _scheduler;
private readonly ILogger<WeatherForecastController> _logger;
public QuartzController(IScheduler scheduler, ILogger<WeatherForecastController> logger)
{
_scheduler = scheduler;
_logger = logger;
}
[HttpGet("Run")]
public async Task<OkObjectResult> Run(string jobName)
{
//check if a specific job exists
//if yes then run that job
await _scheduler.TriggerJob(new JobKey("HelloWorldJob"));
return Ok("OK");
}
}
but when I try to run it I get this error:
System.InvalidOperationException: Unable to resolve service for type 'Quartz.IScheduler' while attempting to activate 'QuartzTest.Controllers.QuartzController'. at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
at lambda_method10(Closure , IServiceProvider , Object[] ) at Microsoft.AspNetCore.Mvc.Controllers.ControllerActivatorProvider.<>c__DisplayClass4_0.b__0(ControllerContext controllerContext) at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.g__CreateController|0(ControllerContext controllerContext) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext) at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
How can I access the scheduler inside the controllers and ideally check if a specific job exists and what is their status (is it running)?
CodePudding user response:
I thought that
services.AddQuartz
will be enough.
AddQuartz
adds the scheduler factory, not the IScheduler
to the DI container.
Since getting the scheduler is done async, it would be difficult to set it up during startup.
refactor your code to instead depend on the factory and use that to get the scheduler
[ApiController]
[Route("[controller]")]
public class QuartzController : ControllerBase {
private readonly ISchedulerFactory factory;
private readonly ILogger<WeatherForecastController> _logger;
public QuartzController(ISchedulerFactory factory, ILogger<WeatherForecastController> logger) {
this.factory = factory;
_logger = logger;
}
[HttpGet("Run")]
public async Task<OkObjectResult> Run(string jobName) {
IScheduler scheduler = await factory.GetScheduler();
//...check if a specific job exists
//if yes then run that job
await scheduler.TriggerJob(new JobKey("HelloWorldJob"));
return Ok("OK");
}
}