We left Russia. We are against aggression and war with Ukraine. It is a tragedy for our nations, it is a nightmare

Serialization of classes that inherit from abstract classes

I’ve simplified my actual code to the following:

public class AbstractExample : AbstractExampleBase<ExampleViewModel>
{
    public override void Execute(Guid entityId)
    {
        Debug.WriteLine("Executed!");
    }
}

public abstract class AbstractExampleBase<T> : IExecutor where T : IExampleViewModel
{
    public abstract void Execute(Guid entityId);
}

public interface IExecutor
{
    void Execute(Guid entityId);
}

public interface IExampleViewModel
{
    Guid EntityId { get; set; }
}

public class ExampleViewModel : IExampleViewModel
{
    public Guid EntityId { get; set; }
}

Then I try to enqueue the job:

var abstractExample = new AbstractExample();
BackgroundJob.Enqueue(() => abstractExample.Execute(Guid.NewGuid()));

The dashboard shows my job as:

using ;

AbstractExampleBase abstractExampleBase = Activate<AbstractExampleBase<ExampleViewModel>>();
abstractExampleBase.Execute(
    FromJson<Guid>("\"699e0a1a-b3db-449c-bc9f-8e20da052a28\""));

The job errors and ninject throws an ActivationException with the message:

Ninject.ActivationException: Error activating AbstractExampleBase{ExampleViewModel}
No matching bindings are available, and the type is not self-bindable.

It seems to me that the problem is the serialized version of the job is trying to activate the base class, which is abstract, instead of instantiating the instance’s actual class, which is not abstract.

Is there a way I can get it to instantiate the appropriate class, rather than the (abstract) base class?

Though I’d still love for it to work with the default BackgroundJob.Enqueue, it does appear I found a more verbose work-around.

        var entityId = Guid.NewGuid();
        var abstractExample = new AbstractExample();

        var type = abstractExample.GetType();
        var method = type.GetMethod("Execute");
        var job = new Job(type, method, new[] { entityId.ToString() });

        var client = new BackgroundJobClient();
        client.Create(job, new EnqueuedState());

If you were to want a recurring job, rather than a one-time instantly executing one, you’d use RecurringJobManager.AddOrUpdate instead of BackgroundJobClient.Create.

2 Likes

There is an overload of Enqueue that takes in a generic type parameter. I think this will make it queue your job correctly.

BackgroundJob.Enqueue<AbstractExample>(example => example.Execute(Guid.NewGuid()));
2 Likes

Works like a charm, thanks!