Skip to content

HostApplicationBuilder in .NET 10 Violates SOLID Principles and Diverges from Established Hosting Semantics for IHostApplicationBuilder interface. #122700

@simkin2004

Description

@simkin2004

Description

Summary
In .NET 10, HostApplicationBuilder constructs the host, logging pipeline, DI container, and partial configuration immediately upon instantiation, rather than deferring construction until Build() is called. This behavior diverges from the established hosting semantics used in ASP.NET Core and in .NET 6–9 console/worker applications.

This change breaks the expected guarantees of the Builder pattern, violates multiple SOLID principles, and causes observable regressions in logging provider behavior, configuration ordering, and DI extensibility.

Reproduction
csharp
var builder = Host.CreateApplicationBuilder(args);

// Add configuration AFTER builder creation
builder.Configuration.AddJsonFile("mysettings.json");

// Add a custom logging provider that depends on merged configuration
builder.Logging.AddProvider(new MyConfigAwareProvider(builder.Configuration));

// Add Serilog
builder.Host.UseSerilog();

// Build and run
var host = builder.Build();
host.Run();
Observed behavior
Only the default Console/Debug/Trace providers are registered.

Custom providers added after builder creation are ignored or constructed with incomplete configuration.

Serilog replaces the logging pipeline after the host has already been constructed.

Provider ordering becomes brittle and unpredictable.

Expected behavior (based on .NET 6–9 and ASP.NET Core)
Configuration is fully merged before logging is constructed.

Logging providers added during builder configuration are honored.

The host is not constructed until Build() is called.

Provider ordering is deterministic and consistent with ASP.NET Core’s hosting lifecycle.

Impact
This change breaks:

Custom logging providers

Providers that depend on merged configuration

Serilog/NLog/OpenTelemetry integration patterns

Extension libraries that assume deferred host construction

Consistency between console apps and ASP.NET Core apps

The mental model developers have relied on since .NET Core 1.0

✅ Architectural Analysis (SOLID Violations)

  1. Single Responsibility Principle (SRP)
    HostApplicationBuilder now performs multiple responsibilities:

Constructs the host

Constructs logging

Constructs DI

Constructs configuration

This contradicts the purpose of a builder, which should only collect configuration until Build() is invoked.

  1. Open/Closed Principle (OCP)
    Because the host is constructed early:

Logging providers added later are ignored or overwritten

Configuration added later is not applied to logging

DI services added later cannot influence early‑constructed components

The system is no longer open for extension.

  1. Liskov Substitution Principle (LSP)
    HostApplicationBuilder and WebApplicationBuilder share conceptual interfaces but now have different lifecycle semantics:

ASP.NET Core defers construction until Build()

HostApplicationBuilder constructs immediately

This breaks substitutability and violates the expectations of libraries built on the hosting abstractions.

  1. Interface Segregation Principle (ISP)
    The hosting interfaces imply:

Deferred construction

Order‑independent configuration

Predictable initialization

But the implementation performs eager construction, making the interface contract misleading.

  1. Dependency Inversion Principle (DIP)
    High‑level components (logging, configuration, DI) now depend on the low‑level detail of when the builder is instantiated. Initialization order becomes fragile and error‑prone.

✅ Why This Is a Regression
From .NET Core 1.0 through .NET 9.0:

The host was not constructed until Build()

Logging was not constructed until configuration was finalized

DI was not constructed until all services were registered

Provider ordering was deterministic

Console apps and ASP.NET Core apps shared the same hosting semantics

.NET 10 breaks these guarantees without changing the interfaces or documentation that describe them.

Reproduction Steps

Reproduction
csharp
var builder = Host.CreateApplicationBuilder(args);

// Add configuration AFTER builder creation
builder.Configuration.AddJsonFile("mysettings.json");

// Add a custom logging provider that depends on merged configuration
builder.Logging.AddProvider(new MyConfigAwareProvider(builder.Configuration));

// Add Serilog
builder.Host.UseSerilog();

// Build and run
var host = builder.Build();
host.Run();
Observed behavior
Only the default Console/Debug/Trace providers are registered.

Expected behavior

All requested providers are registered.

Actual behavior

Only the default Console/Debug/Trace providers are registered.

Regression?

✅ Why This Is a Regression
From .NET Core 1.0 through .NET 9.0:

The host was not constructed until Build()

Logging was not constructed until configuration was finalized

DI was not constructed until all services were registered

Provider ordering was deterministic

Console apps and ASP.NET Core apps shared the same hosting semantics

.NET 10 breaks these guarantees without changing the interfaces or documentation that describe them.

Known Workarounds

No response

Configuration

.NET 10; works as expected with .NET 8.0.22 and .NET 9.0.11

Other information

✅ Requested Resolution
✅ Option A: Restore deferred construction
Ensure that host, logging, DI, and configuration are not constructed until Build() is called.

✅ Option B: Provide an explicit “eager build” API
If early construction is required for performance reasons, expose it as an opt‑in API rather than the default behavior.

✅ Option C: Document the new lifecycle explicitly
If the new behavior is intentional, update documentation to reflect:

Early construction

Logging provider limitations

Configuration ordering constraints

Divergence from ASP.NET Core hosting semantics

✅ Option D (requested): Add a second HostApplicationBuilder with ASP.NET‑style semantics
Introduce a new builder type (e.g., DeferredHostApplicationBuilder) that:

Restores the deferred‑construction model

Matches ASP.NET Core’s hosting lifecycle

Preserves compatibility with .NET 6–9 patterns

Allows console/worker apps to use the same semantics as web apps

This would allow both models to coexist without breaking existing code or forcing developers into the eager‑construction pipeline.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions