If I have strings of the class and function name, how could I add a job.
Example
normal would be
RecurringJob.AddOrUpdate(() => new MyClass().MyMethod(), "0 0 * * *");
I’d like to do something like
string myClassString = GetMyClassFromConfig();//value "MyNamespace.MyClass";
string myMethodString = GetMyMethodFromConfig();//value "MyMethod";
string myCronString = GetMyConrFromConfig();// value "0 0 * * *"
Type myType = Type.GetType(myClassString);
var myMethod = myType.GetMethod(myMethodString);
var myInstance = Expression.Parameter(myType,"instanceName");
RecurringJob.AddOrUpdate(Expression.Call(myInstance,myMethod), myCronString);
but this is throwing an error on the AddOrUpdate method call:
Could not create an instance of type System.Linq.Expressions.Expression. Type is an interface or abstract class and cannot be instantiated. Path ‘Type’, line 1, position 8.
I solved this with some kind help from stackoverflow.
I made a custom config file shaped like the following
<dashboard.hangfire>
<jobs>
<!-- google cron to see the format of cron strings -->
<!-- need full class type with namespace -->
<!-- job method that takes no parameter -->
<job classtype="Dashboard.Jobs.FullRefresh" methodname="Run" cronstring="0 6,18 * * *"></job>
<!-- job/function with parameters in method i.e. real call in c# should be RefreshOne.Run("param1",1) in the following sample -->
<!-- paramtype needs to be string or int or a change to a function in startup.cs is needed to support other types -->
<!--
<job classtype="Dashboard.Jobs.RefreshOne" methodname="Run" cronstring="0 0 * * *">
<parameters>
<parameter paramtype="string" paramvalue="param1"></parameter>
<parameter paramtype="int" paramvalue="1"></parameter>
</parameters>
</job>
-->
</jobs>
</dashboard.hangfire>
and then in startup.cs added the following
in the Configuration(IAppBuilder app) method:
Hangfire.GlobalConfiguration.Configuration.UseSqlServerStorage("hangfire-store", new SqlServerStorageOptions() { PrepareSchemaIfNecessary = true });
app.UseHangfireDashboard("/hangfire", new DashboardOptions() { AuthorizationFilters = new[] { new AllowAnonymousAuthorizationFilter() } });
app.UseHangfireServer();
this.SetupRecurringJobs();
along with the methods:
private void SetupRecurringJobs()
{
foreach (HangfireSettings.JobsElementCollection.JobElement job in HangfireSettings.Settings.Jobs)
{
Type myType = Type.GetType(job.ClassType);
var myMethod = myType.GetMethod(job.MethodName);
string myCron = job.CronString;
if (job.Parameters.Count > 0)
{
Expression[] myArguments = GetJobParameters(job.Parameters);
var myAction = Expression.Lambda<Action>(Expression.Call(Expression.New(myType), myMethod, myArguments));
RecurringJob.AddOrUpdate(myAction, myCron);
}
else
{
var myAction = Expression.Lambda<Action>(Expression.Call(Expression.New(myType), myMethod));
RecurringJob.AddOrUpdate(myAction, myCron);
}
}
}
private Expression[] GetJobParameters(HangfireSettings.ParametersElementCollection parameters)
{
int paramCount = parameters.Count;
Expression[] returnExpressions = new Expression[paramCount];
for (int i = 0; i < paramCount;i++)
{
returnExpressions[i] =
Expression.Constant(complexFunctionToFigureTypeFromString(parameters[i].ParamType,
parameters[i].ParamValue));
}
return returnExpressions;
}
private object complexFunctionToFigureTypeFromString(string paramType,string paramValue)
{
switch (paramType)
{
case "System.String":
case "string":
return paramValue;
case "int":
case "System.Int16":
case "System.Int32":
int obj32 = 0;
Int32.TryParse(paramValue, out obj32);
return obj32;
case "System.Int64":
Int64 obj64 = 0;
Int64.TryParse(paramValue, out obj64);
return obj64;
default:
return null;
}
}
HangfireSettings is a class based on
public sealed class HangfireSettings : ConfigurationSection
Thanks you for the extremely thorough answer - I really appreciate it.
I would never have gotten there by the looks of it!.
My configuration is a great deal simpler - as the my solution is wired up in a manner where the passed parameters are of a consistent type, and only one param is ever passed - but I am pretty sure that with the information passed, I can now get to where I need to be.