Generate a MethodCallExpression to pass to HangFire Enqueue

I am writing a wrapper around enqueueing jobs, as all methods to be called must have a userId, and a jobId.
So I can keep track of jobs created seperately.

I encapsulated Enqueueing jobs like this:

public Job LaunchJob(string description, Action<string, Guid> action)
    {
        Guid jobId = Guid.NewGuid();
        string hangfireId = BackgroundJob.Enqueue(( ) => action(Manager.UserId, jobId)); //this line fails at runtime
        Job job = new Job { JobId = jobId, HangfireId = hangfireId, Description = description };
        Manager.Context.Jobs.Add(job);
        return job;
    }

This compiles fine, but during runtime I get:

Expression body should be of type MethodCallExpression

How do I convert the action into a form that Enqueue can process?

My own research shows that Enqueue expects a Expression<Action>, but how to create that from Action<string,Guid> ?

(I expect that I am lacking Expression<Action<>> insights)

You cannot use pure lambda expressions to enqueue work. Hangfire needs to serialize data about the classes that will actually implement the method, as well as the parameters you are passing to your method.

BackgroundJob.Enqueue<Worker>(w => w.DoWork(DateTime.Now, JobParam1));

You need to specify the type, like “Worker”, then in the lambda expression you can call suitable methods, passing the parameters required as necessary.

This allows you to externalise the “processor” from the application enqueing items. The enqueuer can fire-and-forget, but in order for the “processor” to understand the queued task, it needs to know the type (so it can load it) and the parameters.

1 Like

I am closer to the solution thanks to the post above

I checked the documentation: http://www.nudoq.org/#!/Packages/HangFire.Core/HangFire/BackgroundJob/M/Enqueue(TJob)
http://docs.hangfire.io/en/latest/background-methods/passing-dependencies.html

JobMgr is the class that will accept the action. Without the need for parameter insertion I would call
BackgroundJob.Enqueue( () => db.JobMgr.ClearImported(“test”,Guid.NewGuid)));

Taking the pointers from above and documentation I end up with:

public void LaunchJobInline(string clearingImportedTransactions, Action<string, Guid> clearImported)
{
    string hangfireId = BackgroundJob.Enqueue<JobMgr>>(x => clearImported("test", Guid.NewGuid()));
}

This compiles, but brings the same error message:

Expression body should be of type MethodCallExpression

Old thread, but ran into the same issue.

In your example, you’re providing the generic type parameter, but then you’re not leveraging it in the lambda. Instead, you’re using the action parameter that is passed it. Hangfire won’t know what type the Action member is.

There’s a couple different ways to do this. Here’s the solution I landed on:

   public int Enqueue<T>(Expression<Action<T>> methodCall) {
        var enqueue = BackgroundJob.Enqueue(methodCall);
        var queueId = int.Parse(enqueue);
        return queueId;
    }

And then you can call it like this:

int hangfireJobId = _hangfireJobEnqueuer.Enqueue<IYourType>(x => x.Method(id));