Skip to content

Sample Applications

The samples/ tree is a set of worked examples that exercise Indago end-to-end. Three reusable libraries declare services in different registration styles; hosts consume all three and assert — in process — that Indago discovered exactly the expected service set, then publish under a zero-warning Native AOT guardrail.

You can read the selector expressions below to understand how scanning resolves without running anything — that is the whole point of a compile-time provider.

Each library is a plain class library that references Indago. Collectively they cover interface-matching and attribute-based registration, three lifetimes, and one opt-out type.

LibraryStyleLifetime(s)Notable
Indago.Samples.Cataloginterface-matchingSingletonIXxxServiceXxxService
Indago.Samples.Notificationsattribute ([ServiceRegistration])Transient (AsSelf)generic + non-generic attribute
Indago.Samples.Diagnosticsinterface-matchingScopedone [ExcludeFromSampleScan] opt-out

A host calls provider.Scan(services, selector) once per library. Each selector is hashed at the call site and resolved by the source generator at build time into concrete registrations — there is no runtime reflection.

1. Interface-matching, Singleton (Catalog)

Section titled “1. Interface-matching, Singleton (Catalog)”
provider.Scan(
services,
z => z.FromAssemblyOf<IProductService>()
.AddClasses(f => f.InExactNamespaceOf<IProductService>())
.AsMatchingInterface()
.WithSingletonLifetime()
);

AsMatchingInterface() registers ProductService as IProductService, CategoryService as ICategoryService, and so on.

2. Attribute-based, Transient as-self (Notifications)

Section titled “2. Attribute-based, Transient as-self (Notifications)”
provider.Scan(
services,
z => z.FromAssemblyOf<NotificationDispatcher>()
.AddClasses(f => f.WithAttribute<ServiceRegistrationAttribute>())
.AsSelf()
.WithTransientLifetime()
);

Only types carrying [ServiceRegistration] are registered, each as its own concrete type.

3. Interface-matching with an opt-out, Scoped (Diagnostics)

Section titled “3. Interface-matching with an opt-out, Scoped (Diagnostics)”
provider.Scan(
services,
z => z.FromAssemblyOf<IHealthCheck>()
.AddClasses(f => f.WithoutAttribute<ExcludeFromSampleScanAttribute>())
.AsMatchingInterface()
.WithScopedLifetime()
);

WithoutAttribute<ExcludeFromSampleScanAttribute>() is why the opt-out type never appears in the discovered set — the host asserts its absence.

HostKindProves
Indago.Samples.Consoleconsolediscovery via IndagoProvider.Instance; exits non-zero on mismatch
Indago.Samples.WebASP.NET minimal APIfail-fast at startup on mismatch; /services endpoint lists discovery

Both hosts hold a hard-coded expected service set and compare it to what Indago discovered, failing the process (and therefore the CI smoke test) on any mismatch. Both are published under the zero-warning Native AOT policy as discrete, named pipeline steps.