It seems like Hangfire is unable to deserialize my original Scheduler
object with all its state, whose Execute method I am calling in BackgroundJob.Enqueue()
as shown below:
Scheduler = new FileInFileOut
{
FileIn = new FileInput()
{
FileName = "SampleInput.txt",
DirectoryPath = @"C:\Users\LENOVO\Desktop\iRule",
FileFormat = new System.Collections.Generic.Dictionary<string, string>
{
{"X", "ParseInt(input.Substring(0, 2))"},
{"Y", "ParseInt(input.Substring(3, 2))"},
{"Z", "ParseInt(input.Substring(6, 2))"},
}
},
FileOut = new FileOutput()
{
FileName = "SampleOutput.txt",
DirectoryPath = @"C:\Users\LENOVO\Desktop\iRule"
},
Trigger = new FireAndForgetTrigger()
};
BackgroundJob.Enqueue(() => Scheduler.Execute());
The Scheduler is of type IScheduler as shown below:
public interface IScheduler
{
IEntityBaseDef EntityItemBase { get; set; }
ITrigger Trigger { get; set; }
RuleApp RuleApp { get; set; }
Type JobType { get; set; }
void Execute();
}
[Serializable()]
[DataContract()]
public abstract class Scheduler : EntityModel, IScheduler
{
public abstract void Execute();
}
[Serializable()]
[DataContract()]
public class FileInFileOut : Scheduler, IFileInFileOut
{
private FileInput _fileIn;
public FileInput FileIn
{
get { return _fileIn; }
set { SetProperty(ref _fileIn, value); }
}
private FileOutput _fileOut;
public FileOutput FileOut
{
get { return _fileOut; }
set { SetProperty(ref _fileOut, value); }
}
public override void Execute()
{
// ERROR on below line, FileIn object is null
var directoryInfo = new DirectoryInfo(FileIn.DirectoryPath);
var files = directoryInfo.GetFiles();
if (FileIn.SearchSubDirectories)
{
var directories = directoryInfo.GetDirectories().Flatten(x => x.GetDirectories());
}
}
}
My Current Scheduler Publishing Logic:
public void Publish()
{
if (Scheduler != null)
{
var trigger = Scheduler.Trigger;
if (trigger is IFireAndForgetTrigger)
{
BackgroundJob.Enqueue(() => Scheduler.Execute());
}
else if (trigger is IDelayedTrigger)
{
var delayedTrigger = (IDelayedTrigger)trigger;
BackgroundJob.Schedule(() => Scheduler.Execute(), delayedTrigger.Delay);
}
}
}
Is it some kind of deserialization issue? How to identify and correct this issue?
Hangfire does not attempt to store the state of the FileInFileOut object when the Enqueue method is called. It recreates the FileInFileOut object on the worker using a parameterless constructor (or one with parameters using a IOC activator) and then calls the method from your Enqueue expression. This results in the null reference (FileIn / FileOut not set).
You could modify your FileInFileOut method to pass the FileIn and FileOut objects to the Execute method (using a more functional programming approach). This may break other parts of your program so it's probably more appropraite to create a second wrapper class that instantiates the FileInFileOut object for you like:
public class FileInFileOutTasks
{
public FileInFileOutTasks()
{
}
public void RunExecute(FileIn fileIn, FileOut, fileout)
{
var scheduler = new FileInFileOut { FileIn = fileIn, FileOut = fileOut };
scheduler.Execute();
}
}
You would then call:
BackgroundJob.Enqueue<FileInFileOutTasks>(x => x.RunExecute(fileIn, fileOut));
and not even create the FileInFileOut object in your code if you didn't want to (just the FileIn / FileOut objects to be passed to the wrapper).
来源:https://stackoverflow.com/questions/44590115/object-getting-null-seems-like-deserialization-issue-in-hangfire