Skip to content

[Breaking change]: IStartupValidator is obsolete #56348

Closed

Description

@ViveliDuCh

Description

Starting in .NET 11 RC 1, Microsoft.Extensions.Options.IStartupValidator is obsolete. Referencing or implementing the interface produces warning SYSLIB0066 with the message Implement IAsyncStartupValidator instead.

The API remains available and functional for compatibility; this change is an obsoletion, not an API removal. The design was approved in dotnet/runtime#131906 and implemented by dotnet/runtime#131197. The change is contained in the .NET 11 RC 1 runtime tag.

Version

.NET 11 RC 1

Previous behavior

Custom startup validators could implement and register IStartupValidator without a compiler warning:

public sealed class StartupValidator : IStartupValidator
{
    public void Validate()
    {
        ValidateConfiguration();
    }
}

services.AddSingleton<IStartupValidator, StartupValidator>();

New behavior

Referencing or implementing IStartupValidator produces warning SYSLIB0066. The interface is retained for compatibility, and existing runtime behavior remains available to legacy implementations.

New custom startup validators should implement the independent asynchronous contract IAsyncStartupValidator. A custom validator should be registered only under the startup contract it is intended to provide; it shouldn't be registered under both IStartupValidator and IAsyncStartupValidator.

Applications that only call OptionsBuilder<TOptions>.ValidateOnStart() generally don't implement either startup-validator interface directly and normally require no migration for this warning.

Type of breaking change

  • Binary incompatible: Existing binaries might encounter a breaking change in behavior, such as failure to load or execute, and if so, require recompilation.
  • Source incompatible: When recompiled using the new SDK or component or to target the new runtime, existing source code might require source changes to compile successfully.
  • Behavioral change: Existing binaries might behave differently at run time.

Reason for change

Host startup already has an asynchronous entry point through IHost.StartAsync. New startup validators should therefore use the asynchronous startup-validation contract.

Keeping IAsyncStartupValidator independent from IStartupValidator avoids forcing asynchronous implementations to provide an unused synchronous Validate method, avoids encouraging sync-over-async code, and makes ValidateAsync the single complete contract for new custom startup validators. IStartupValidator remains available to preserve compatibility with existing synchronous implementations.

Recommended action

Replace custom IStartupValidator implementations and registrations with IAsyncStartupValidator:

public sealed class StartupValidator : IAsyncStartupValidator
{
    public Task ValidateAsync(
        CancellationToken cancellationToken = default)
    {
        ValidateConfiguration();
        return Task.CompletedTask;
    }
}

services.AddSingleton<IAsyncStartupValidator, StartupValidator>();

For genuinely asynchronous validation, await the asynchronous operation and forward cancellation:

public sealed class StartupValidator : IAsyncStartupValidator
{
    public async Task ValidateAsync(
        CancellationToken cancellationToken = default)
    {
        string state = await File.ReadAllTextAsync(
            "startup-state.txt",
            cancellationToken);

        if (string.IsNullOrWhiteSpace(state))
        {
            throw new InvalidOperationException(
                "The startup state is invalid.");
        }
    }
}

services.AddSingleton<IAsyncStartupValidator, StartupValidator>();

Don't register the same custom implementation under both startup contracts. Existing uses of .ValidateOnStart() that don't directly implement IStartupValidator normally don't need to change.

Feature area

Extensions

Affected APIs

  • Microsoft.Extensions.Options.IStartupValidator

Required diagnostic and compatibility documentation

  • Add docs/fundamentals/syslib-diagnostics/syslib0066.md.
    • State that IStartupValidator is obsolete but retained for compatibility.
    • Explain migration to IAsyncStartupValidator and the custom registration guidance.
    • Include standard warning-suppression guidance.
  • Add SYSLIB0066 to docs/fundamentals/syslib-diagnostics/obsoletions-overview.md.
  • Add SYSLIB0066 to docs/navigate/tools-diagnostics/toc.yml.
  • Add or update .NET 11 Extensions compatibility coverage for this obsoletion and index it from the .NET 11 compatibility overview and TOC.
  • Cross-link the compatibility article and SYSLIB0066 diagnostic article.

The existing article created through dotnet/docs#55794 and dotnet/docs#55901 covers a different change from the same runtime PR: synchronous access to async-validated options now throws instead of silently skipping validation. It doesn't document the IStartupValidator obsoletion or provide a SYSLIB0066 landing page.

Note

This issue was drafted with assistance from GitHub Copilot.


Associated WorkItem - 638746

Activity

  1. moved this from 🔖 Ready to 🏗 In progress in dotnet/docs October 2026 Sprint projecton Oct 13, 2026
  2. added
    📌 seQUESTeredIdentifies that an issue has been imported into Quest.
    and removed
    🗺️ reQUESTTriggers an issue to be imported into Quest.
    on Oct 14, 2026
  3. added
    🗺️ mapQUESTOnly used as a way to mark an issue as updated for quest. RepoMan should instantly remove it.
    on Oct 15, 2026
  4. moved this from 🏗 In progress to 👀 In review in dotnet/docs October 2026 Sprint projecton Oct 15, 2026
  5. removed
    🗺️ mapQUESTOnly used as a way to mark an issue as updated for quest. RepoMan should instantly remove it.
    on Oct 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

📌 seQUESTeredIdentifies that an issue has been imported into Quest.breaking-changeIndicates a .NET Core breaking change

Type

No type

Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions