abpframework/abp · critical · AbpException

Could not find 'DoWork' method on type '{workerType.FullName

Error message

Could not find 'DoWork' method on type '{workerType.FullName}'.

What it means

Thrown by AbpTickerQPeriodicBackgroundWorkerInvoker when reflecting over a PeriodicBackgroundWorkerBase subclass and the non-public instance method 'DoWork' cannot be found. ABP compiles a delegate to this protected method to drive the worker's periodic execution. The method is part of the ABP base class contract; its absence indicates a version mismatch or an incorrectly overridden worker.

Source

Thrown at framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQPeriodicBackgroundWorkerInvoker.cs:47

                if (method == null)
                {
                    throw new AbpException($"Could not find 'DoWorkAsync' method on type '{workerType.FullName}'.");
                }

                var instanceParam = Expression.Parameter(typeof(AsyncPeriodicBackgroundWorkerBase), "worker");
                var contextParam = Expression.Parameter(typeof(PeriodicBackgroundWorkerContext), "context");
                var call = Expression.Call(Expression.Convert(instanceParam, workerType), method, contextParam);
                var lambda = Expression.Lambda<Func<AsyncPeriodicBackgroundWorkerBase, PeriodicBackgroundWorkerContext, Task>>(call, instanceParam, contextParam);
                _doWorkAsyncDelegate = lambda.Compile();
                break;
            }
            case PeriodicBackgroundWorkerBase:
            {
                var workerType = worker.GetType();
                var method = workerType.GetMethod("DoWork", BindingFlags.Instance | BindingFlags.NonPublic);
                if (method == null)
                {
                    throw new AbpException($"Could not find 'DoWork' method on type '{workerType.FullName}'.");
                }

                var instanceParam = Expression.Parameter(typeof(PeriodicBackgroundWorkerBase), "worker");
                var contextParam = Expression.Parameter(typeof(PeriodicBackgroundWorkerContext), "context");
                var call = Expression.Call(Expression.Convert(instanceParam, workerType), method, contextParam);
                var lambda = Expression.Lambda<Action<PeriodicBackgroundWorkerBase, PeriodicBackgroundWorkerContext>>(call, instanceParam, contextParam);
                _doWorkDelegate = lambda.Compile();
                break;
            }
        }
    }

    public virtual async Task DoWorkAsync(TickerFunctionContext context, CancellationToken cancellationToken = default)
    {
        var workerContext = new PeriodicBackgroundWorkerContext(ServiceProvider);
        switch (Worker)
        {
            case AsyncPeriodicBackgroundWorkerBase asyncPeriodicBackgroundWorker:

View on GitHub (pinned to 7ed43b1931)

Solutions

  1. Align all ABP package versions so PeriodicBackgroundWorkerBase.DoWork exists with the expected signature and accessibility.
  2. If overriding, use 'protected override void DoWork(PeriodicBackgroundWorkerContext workerContext)' exactly.
  3. Prefer AsyncPeriodicBackgroundWorkerBase over the synchronous base for new workers, as it is the recommended base class.

Example fix

// before — wrong signature/access
public class MyWorker : PeriodicBackgroundWorkerBase
{
    private void DoWork() { ... } // wrong
}

// after
public class MyWorker : PeriodicBackgroundWorkerBase
{
    Period = 60000;
    protected override void DoWork(PeriodicBackgroundWorkerContext workerContext) { ... }
}
Defensive patterns

Strategy: validation

Validate before calling

var method = worker.GetType().GetMethod("DoWork", BindingFlags.Instance | BindingFlags.NonPublic);
if (method == null)
{
    throw new InvalidOperationException($"Worker {worker.GetType().FullName} is missing DoWork; check ABP package versions and method signature.");
}

Type guard

static bool HasDoWork(Type workerType) => workerType.GetMethod("DoWork", BindingFlags.Instance | BindingFlags.NonPublic) != null;

Prevention

When it happens

Trigger: Registering a worker derived from the synchronous PeriodicBackgroundWorkerBase whose DoWork(PeriodicBackgroundWorkerContext) method is not resolvable via BindingFlags.Instance | BindingFlags.NonPublic. Happens when the ABP packages are version-inconsistent or a subclass shadowed the method incorrectly.

Common situations: Mixing ABP package versions where the base class no longer declares DoWork as protected. Overriding DoWork but changing its access modifier (e.g. making it private or renaming it). A weaving/proxy layer that altered method metadata.

Related errors


AI-assisted analysis of abpframework/abp@7ed43b1931 (2026-08-13). Data as JSON: /api/errors/1aacc71337006438. Report an issue: GitHub.