Skip to content

csharp: a hosted service that derives from BackgroundService through its own base class is not an entry point #1432

Closed

Description

@swapnilpaliwal-sd

Symptom

A hosted service that derives from BackgroundService through its own abstract base class is not an entry point. impact on its ExecuteAsync prints no entry point: line and ends "the change is local", and entry_points has no row for it. A worker that derives from BackgroundService directly, in the same file, is a lifecycle entry point. Measured on 0.1.3 at 0df257c; the MCP axiomcode_impact tool prints the same.

Reproduction

Workers.csproj (Microsoft.NET.Sdk.Worker, net8.0, implicit usings on), Program.cs:

using App.Workers;

var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddSingleton<OrderStore>();
builder.Services.AddHostedService<OrderWorker>();
builder.Services.AddHostedService<WidgetWorker>();
builder.Build().Run();

Workers.cs:

namespace App.Workers;

public sealed class OrderStore { public void Save() { } public void Ship() { } }

public abstract class WorkerBase : BackgroundService { }

public sealed class WidgetWorker(OrderStore store) : WorkerBase
{
    protected override Task ExecuteAsync(CancellationToken ct) { store.Save(); return Task.CompletedTask; }
}

public sealed class OrderWorker(OrderStore store) : BackgroundService
{
    protected override Task ExecuteAsync(CancellationToken ct) { store.Ship(); return Task.CompletedTask; }
}

After axiomcode index, entry_points holds main and one lifecycle row, OrderWorker.ExecuteAsync (line 14). impact WidgetWorker.ExecuteAsync (line 9) prints no entry point: line, and OrderStore.Save is not in entry_reachable. A class declared : IHostedLifecycleService alone (that interface extends IHostedService) gets no lifecycle row either.

Root cause

graph/csharp/engine/framework-behavior/entry-points.dl:33-34 matches cs_hosted_base against heritage_slot("client", t, ...) of the method's own type only, so a base named in an ancestor's heritage list, or a library interface that extends IHostedService, never matches.

Expected

WidgetWorker.ExecuteAsync is a lifecycle entry point, as OrderWorker.ExecuteAsync is.

Activity

  1. swapnilpaliwal-sd commented on Sep 28, 2026

    @swapnilpaliwal-sd
    ContributorAuthor

    Fixed by #1620.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcsharpC#engineResolution / call-graph engine rules

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions