System.NullReferenceException: Object reference not set to an instance of an object.
swidz opened this issue · 2 comments
I get the NullReferenceException if the job is not added using .AddQuartzJob<ExecutionWorkerJobsMonitorJob>()
The error is as follows:
Job DEFAULT.ExecutionWorkerJobsMonitorJob threw an exception.
Quartz.SchedulerException: Job threw an unhandled exception.
---> System.NullReferenceException: Object reference not set to an instance of an object.
at Quartz.Core.JobRunShell.Run(CancellationToken cancellationToken)
--- End of inner exception stack trace --- [See nested exception: System.NullReferenceException: Object reference not set to an instance of an object.
at Quartz.Core.JobRunShell.Run(CancellationToken cancellationToken)]
The AddSilkierQuartz method is called with assembly list.
The job is properly decorated with SilkierQuartzAttribute
I expect the job to be discovered and triggered every 10 seconds
I can see the job with trigger but every time they fire I get the Object reference not set to an instance of an object.
error.
I am using Microsoft SQLite as store
.Net 7, with EFCore
SilkierQuartz 5.0.356
If I add .AddQuartzJob() to register the job in services collection then the error does not happen.
please find parts of the code below:
public class Startup
{
private readonly IConfiguration _configuration;
private readonly IWebHostEnvironment _environment;
public Startup(IConfiguration config, IWebHostEnvironment environment)
{
_configuration = config;
_environment = environment;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.AddFeatureManagement(_configuration);
services.AddLocalization(options =>
{
options.ResourcesPath = "Resources";
});
services.AddLazyCache();
services.AddSerialization();
services.AddDatabase(_configuration);
services.AddApplicationLayer(_configuration);
services.AddApplicationServices(_configuration);
services
.AddMvc()
.AddJsonOptions(o =>
{
o.JsonSerializerOptions.PropertyNamingPolicy = null;
o.JsonSerializerOptions.DictionaryKeyPolicy = null;
});
services.AddFluentValidationAutoValidation();
services.AddValidatorsFromAssemblies(
AssemblyHelper.GetAssemblies());
services.AddBackgroundWorker(_configuration);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime appLifetime)
{
app.UseExceptionHandling(env);
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseSilkierQuartz();
app.UseEndpoints();
}
}
internal static IServiceCollection AddBackgroundWorker(this IServiceCollection services, IConfiguration config)
{
var quartzConfiguration = config.GetSection("Quartz");
var referencedAssemblies = AssemblyHelper
.GetAssembliesFromExecutionFolder(
Assembly.GetExecutingAssembly());
services.AddSilkierQuartz(options =>
{
options.EnableEditor = false;
options.VirtualPathRoot = "/quartz";
options.UseLocalTime = true;
options.DefaultDateFormat = "yyyy-MM-dd";
options.DefaultTimeFormat = "HH:mm:ss";
options.CronExpressionOptions = new CronExpressionDescriptor.Options()
{
DayOfWeekStartIndexZero = false, //Quartz uses 1-7 as the range
Use24HourTimeFormat = true
};
},
authenticationOptions =>
{
authenticationOptions.AccessRequirement = SilkierQuartzAuthenticationOptions.SimpleAccessRequirement.AllowAnonymous;
},
stdSchedulerFactoryOptions =>
{
stdSchedulerFactoryOptions.Add(quartzConfiguration
.Get<Dictionary<string, string>>()
.ToNameValueCollection());
},
() => referencedAssemblies
);
return services;
}
My appsettings.json part related to Quartz
"Quartz": {
"quartz.scheduler.instanceName": "Scheduler",
"quartz.scheduler.instanceId": "AUTO",
"quartz.threadPool.type": "Quartz.Simpl.SimpleThreadPool, Quartz",
"quartz.threadPool.threadCount": "10",
"quartz.serializer.type": "json",
"quartz.jobStore.clustered": false,
"quartz.jobStore.useProperties": false,
"quartz.jobStore.type": "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz",
"quartz.jobStore.driverDelegateType": "Quartz.Impl.AdoJobStore.SQLiteDelegate, Quartz",
"quartz.jobStore.tablePrefix": "QRTZ_",
"quartz.jobStore.dataSource": "default",
"quartz.dataSource.default.provider": "SQLite-Microsoft",
"quartz.dataSource.default.connectionString": "DataSource=C:\\datamigration\\db\\Datamigration.db",
"quartz.plugin.recentHistory.storeType": "Quartz.Plugins.RecentHistory.Impl.InProcExecutionHistoryStore, Quartz.Plugins.RecentHistory",
"quartz.plugin.recentHistory.type": "Quartz.Plugins.RecentHistory.ExecutionHistoryPlugin, Quartz.Plugins.RecentHistory"
},
[SilkierQuartz(10, "Data migration job monitor", "Executes data migration jobs taking care of dependencies", TriggerGroup = "SilkierQuartz")]
[DisallowConcurrentExecution]
[PersistJobDataAfterExecution]
public class ExecutionWorkerJobsMonitorJob : IJob
{
private readonly ILogger<ExecutionWorkerJobsMonitorJob> _logger;
private readonly IDatamigrationDbContext _ctx;
private readonly ISchedulerFactory _schedulerFactory;
public ExecutionWorkerJobsMonitorJob(
ISchedulerFactory schedulerFactory,
ILogger<ExecutionWorkerJobsMonitorJob> logger,
IDatamigrationDbContext ctx)
{
_schedulerFactory = schedulerFactory ?? throw new ArgumentNullException(nameof(schedulerFactory));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_ctx = ctx ?? throw new ArgumentNullException(nameof(ctx));
}
public async Task Execute(IJobExecutionContext context)
{
_logger.LogDebug("ExecutionWorkerJobsMonitorJob executed");
ArgumentNullException.ThrowIfNull(context, nameof(context));
var scheduler = await _schedulerFactory.GetScheduler(context.CancellationToken);
}
}
UPDATE:
It is important to mention that ExecutionWorkerJobsMonitorJob
is defined in an external assembly.
When I define a job in the same assembly as the quartz host the job runs without problems.
I was trying to do the same on example project but cannot reproduce - external assembly jobs run without problems
Need to check if db storage has anything to do about it.
UPDATE2:
I changed the example project to use persistent storage on SQLServer
I get the same System.NullReferenceException: Object reference not set to an instance of an object.
It seems the issue is related to using job store with persistence, external assembly and autodiscover using SilkierQuartzAttribute
Working example: https://github.com/swidz/SilkierQuartz
Job that returns NullReferenceException
is called HelloJobAutoExt
in TestJobs
assembly (project)
Started a discussion on Quartz.Net discussion group Help needed - System.NullReferenceException: Object reference not set to an instance of an object
For posterity,
I have found the solution. The issue was how assembly list was loaded that was passed to services.AddSilkierQuartz
To create that list, I used a helper method that internally used System.Reflection.Assembly.Load(assemblyName)
or System.Reflection.Assembly.LoadFile(assemblyPath)
but instead it should use
System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromAssemblyName(assemblyName)
or
System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath)
.
References:
About System.Runtime.Loader.AssemblyLoadContext
Regards,
Sebastian