Dynamically Enqueue Jobs from Names (strings) at Runtime

We have been using Hangfire in prod for many years without any hiccups. Love it!

We now face migrating an oldish ETL with its own complex custom job scheduler based on job tables. It was quite well done. We require jobs groups and dependencies. We want to refactor partially to use Hangfire for two main reasons:

  1. Want to have external visibility UI
  2. Job Controlability (eg, rerun)

Now, as far as I know, one cannot create a new job (from non-Hangfire database) like the following:
BackgroundJob.Enqueue("[MethodNameToRun]", “[Arguments]”)

With a string for method and arguments. Please correct me if this is not the case. I considered reflection, but found inviable.

I have created a POC that does the above by using SQL (stored proc) to insert rows directly into the Hangfire tables in a tran. With moderate testing, it seems to work very well. Other than the obvious awkwardness of the solution - can anyone think of reasons not to do this? Is there a better way?

Follow Up

I did end up finding multiple ways of solving this. What I ended up doing was what suggested by another user - using Invoke/Relection. I had avoided this approach mainly because I did not want “InvokeMethod” to show in the Hangfire UI, but this was solved so here is the working solution if anyone needs has a similar requirement. The DisplayName attribute was what makes it look pretty in the Hangfire UI.

    [DisplayName("{2} (Job#{0}) => {1}-{2}")]
    public void InvokeJob(long jobId, string assemblyName, string className, string methodName)
    {
        Type job = Type.GetType($"{className}, {assemblyName}");
        Object classInstance = ActivatorUtilities.CreateInstance(serviceProvider, job);
        MethodInfo method = job.GetMethod(methodName);

        object[] jobParameters = GetJobParameters(jobId); // generated from rows in db table
        method.Invoke(classInstance, jobParameters);
    }

This is Enqueued or Scheduled by calling:
BackgroundJob.Enqueue(() => InvokeJob(job.Id, job.CsAssembly, job.CsType, job.CsMethod));

Note, I did get the database method to work equally well (used EF7 with a transaction), but decided not to use it because it felt too hacky.