Home > Software engineering >  Expression body should be of type 'MethodCallExpression'
Expression body should be of type 'MethodCallExpression'

Time:05-16

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();
}
  • Related