Search code examples
c#.net.net-corehangfireabp-framework

Hangfire Backgroundjob Enqueue via deserilaziation object problem


Normally i can enqueue hangfire jobs without problem. I'am trying to enqueue jobs dynamically getting object/argument from database. I am generating parameters via deserilization, invoicationdata is being generated incorrect (as object). (I am using ABP framework but i do not think this problem is related with ABP.)

job Enqueue:

public class JobExecuter
{
    private readonly IBackgroundJobInboxRepository backgroundJobInboxRepository;
    private readonly IJsonSerializer jsonSerializer;
    private readonly IBackgroundJobManager backgroundJobManager;
    public JobExecuter(
        IBackgroundJobInboxRepository backgroundJobInboxRepository,
        IJsonSerializer jsonSerializer,
        IBackgroundJobManager backgroundJobManager)
    {
        this.backgroundJobInboxRepository = backgroundJobInboxRepository;
        this.jsonSerializer = jsonSerializer;
        this.backgroundJobManager = backgroundJobManager;
    }
    public async Task ExecuteAsync()
        {
            var item = await backgroundJobInboxRepository.FirstOrDefault();
            var type = Type.GetType(item.AssemblyName);
            var obj = jsonSerializer.Deserialize(type, item.Arguments, false);
            await backgroundJobManager.EnqueueAsync(obj);
        }
}

item.AssemblyName :

MyAssembly.BackgroundJobs.MyClass, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

concrete class:

public class HangfireBackgroundJobManager : IBackgroundJobManager, ITransientDependency
{
    public virtual Task<string> EnqueueAsync<TArgs>(TArgs args, BackgroundJobPriority priority = BackgroundJobPriority.Normal,
        TimeSpan? delay = null)
    {
        return Task.FromResult(BackgroundJob.Enqueue<HangfireJobExecutionAdapter<TArgs>>(adapter => adapter.ExecuteAsync(args)));
    }
}   

my invocationdata:

{"Type":"Volo.Abp.BackgroundJobs.Hangfire.HangfireJobExecutionAdapter`1[[System.Object, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], Volo.Abp.BackgroundJobs.HangFire, Version=5.3.3.0, Culture=neutral, PublicKeyToken=null","Method":"ExecuteAsync","ParameterTypes":"["System.Object, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e"]","Arguments":"["{\"CurrentDate\":\"2022-09-15T00:00:00+03:00\",\"DateInterval\":-5,\"ProjectId\":11}"]"}

invocationdata that should be:

{"Type":"Volo.Abp.BackgroundJobs.Hangfire.HangfireJobExecutionAdapter`1[[MyAssembly.BackgroundJobs.MyClass, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], Volo.Abp.BackgroundJobs.HangFire, Version=5.3.3.0, Culture=neutral, PublicKeyToken=null","Method":"ExecuteAsync","ParameterTypes":"["MyAssembly.BackgroundJobs.MyClass, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"]","Arguments":"["{\"CurrentDate\":\"2022-09-15T00:00:00+03:00\",\"DateInterval\":-5,\"ProjectId\":11}"]"}

Additional info: You can access real HangfireBackgroundJobManager class.


Solution

  • I solved it using these methods

    dynamic DynamicCast(object entity, Type to)
    {
       var openCast = this.GetType().GetMethod("Cast", BindingFlags.Static | BindingFlags.NonPublic);
       var closeCast = openCast.MakeGenericMethod(to);
       return closeCast.Invoke(this, new[] { entity });
    }
    static T Cast<T>(object entity) where T : class
    {
       return entity as T;
    }
    public async Task ExecuteAsync()
    {
       var item = await backgroundJobInboxRepository.FirstOrDefault();
       var type = Type.GetType(item.AssemblyName);
       var obj2 = jsonSerializer.Deserialize(type, item.Arguments, false);
       var obj = DynamicCast(obj2, type); // ADDED
       await backgroundJobManager.EnqueueAsync(obj);
    }