I have a function -
public async Task DoWork(Frequency value) { // do work }
The idea here is to add this function as a recurring job to Hangfire.
Adding the job explicitly works, like this -
RecurringJob.AddOrUpdate("triggerId", () => DoWork(frequency), Cron.Daily())
However, if I want to create a function to add triggers
private void AddTrigger(string triggerId, Frequency frequency, Func<Frequency, Task> trigger)
{
RecurringJob.AddOrUpdate(triggerId, () => trigger(frequency), Cron.Daily());
}
I get an error Expression body should be of type 'MethodCallExpression'
When I debug it seems like they are the same type of objects. What am I missing here that is causing this error?
() => trigger(frequency) {Method = {System.Threading.Tasks.Task <<>m0>b__0()}} object {System.Func<System.Threading.Tasks.Task>}
() => DoWork(frequency) {Method = {System.Threading.Tasks.Task <<>m0>b__0()}} object {System.Func<System.Threading.Tasks.Task>}
CodePudding user response:
The RecurringJob.AddOrUpdate
overload you're calling accepts an Expression<Func<Task>>
. That's an expression tree representing a call that returns a task.
Unfortunately, RecurringJob.AddOrUpdate
requires that expression tree to represent a method call - it calls Job.FromExpression
, which eventually ends up in this code. Every Job
is eventually built from a MethodInfo
. Your lambda expression is an invocation via a parameter, so it doesn't work.
You could wrap the invocation in a method call, as below - I don't know if it will actually work though... you may find that you end up with a lot of jobs with a name of "Execute".
private void AddTrigger(string triggerId, Frequency frequency,
Func<Frequency, Task> trigger)
{
var wrapper = new TriggerWrapper(() => trigger(frequency));
RecurringJob.AddOrUpdate(triggerId, () => wrapper.Execute(), Cron.Daily());
}
private class TriggerWrapper
{
private Func<Task> func;
internal TriggerWrapper(Func<Task> func) => this.func = func;
public Task Execute() => func();
}