`WebApplicationBuilder.Environment`, `WebApplication.Environment`, and DI-resolved `IHostEnvironment` represent different environment objects
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 290
Description
### Is there an existing issue for this?
- [x] I have searched the existing issues
### Describe the bug
When using `WebApplication.CreateBuilder(args)`, the environment object exposed by:
- `builder.Environment`
- `app.Environment`
- `app.Services.GetRequiredService()`
does not appear to be a single consistent runtime environment object.
In the minimal repro below, mutating:
```csharp
builder.Environment.ApplicationName = "manual-override";
```
updates `builder.Environment.ApplicationName` and `app.Environment.ApplicationName`, but the `IHostEnvironment` resolved from DI after `Build()` still returns the original application name.
This is surprising and appears inconsistent:
- `builder.Environment` is one object
- `app.Environment` is the same object instance as `builder.Environment`
- `app.Services.GetRequiredService()` is a different object instance
`ApplicationName` is only the easiest visible symptom. The deeper issue is that the framework surfaces what looks like "the application environment" through multiple APIs, but those APIs are not backed by one shared object.
### Expected Behavior
One of the following should be true:
1. `builder.Environment`, `app.Environment`, and DI-resolved `IHostEnvironment` should represent the same underlying runtime environment object.
2. Or the framework should clearly document that these are distinct environment objects with potentially different state, and mutations to one do not affect the others.
Today the application can observe two different environment instances through normal framework APIs without any obvious indication that they are distinct.
### Steps To Reproduce
```csharp
using System.Runtime.CompilerServices;
using Microsoft.Extensions.Hosting;
const string ManualApplicationName = "manual-override";
var builder = WebApplication.CreateBuilder(args);
Console.WriteLine(
"[diag] builder.Environment before set: ApplicationName={0}, Hash={1}",
builder.Environment.ApplicationName,
RuntimeHelpers.GetHashCode(builder.Environment));
builder.Environment.ApplicationName = ManualApplicationName;
Console.WriteLine(
"[diag] builder.Environment after set: ApplicationName={0}, Hash={1}",
builder.Environment.ApplicationName,
RuntimeHelpers.GetHashCode(builder.Environment));
var app = builder.Build();
var resolvedHostEnvironment = app.Services.GetRequiredService();
Console.WriteLine(
"[diag] app.Environment after build: ApplicationName={0}, Hash={1}",
app.Environment.ApplicationName,
RuntimeHelpers.GetHashCode(app.Environment));
Console.WriteLine(
"[diag] app.Services IHostEnvironment: ApplicationName={0}, Hash={1}",
resolvedHostEnvironment.ApplicationName,
RuntimeHelpers.GetHashCode(resolvedHostEnvironment));
app.Run();
```
Example output:
```text
[diag] builder.Environment before set: ApplicationName=application-name-repro, Hash=59941933
[diag] builder.Environment after set: ApplicationName=manual-override, Hash=59941933
[diag] app.Environment after build: ApplicationName=manual-override, Hash=59941933
[diag] app.Services IHostEnvironment: ApplicationName=application-name-repro, Hash=57434139
```
This shows:
- `builder.Environment` and `app.Environment` share the same hash / instance
- the DI-resolved `IHostEnvironment` is a different object
- the two environment objects can diverge in observable state
### Exceptions (if any)
_No response_
### .NET Version
10.0.203
### Anything else?
_No response_
Contributor guide
Research direction
Start with the WebApplication.CreateBuilder(args) repro and inspect how builder.Environment, app.Environment, and the DI-resolved IHostEnvironment are created and exposed during Build(). Compare the observable instances and state, then determine whether the intended result is shared state or documentation of distinct objects; done requires an agreed behavior and regression coverage.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 42/100