diff --git a/README.md b/README.md index f3480d0..8ad4dda 100644 --- a/README.md +++ b/README.md @@ -1,99 +1,25 @@ # WhyConfig.NET -**Why did my .NET app get this configuration value?** WhyConfig.NET shows every provider that supplied a key, in precedence order, and marks the provider that won. +See which .NET configuration source set a value, and which values it replaced. -```text -Database:Host +![Animated demo of whyconfig explaining Database:Host](assets/whyconfig-demo.gif) -appsettings.json - db.production.com - overridden +## Try it -appsettings.Development.json - localhost - overridden - -Environment Variables - db.docker - WINNER - -Effective value: db.docker -``` - -The project has two entry points: - -- **WhyConfig.Core** inspects an application's actual `IConfigurationRoot`. Use it when you need the exact provider chain, including custom providers. -- **whyconfig** is a CLI for investigating a project outside the running app. It rebuilds the common .NET application configuration layers from the files and environment available to the CLI. - -## Quick start - -Requires the .NET 10 SDK. From this repository: +Requires the .NET 10 SDK. From this repository, run: ```bash dotnet run --project src/WhyConfig.Cli -- explain Database:Host --project path/to/YourApp --environment Development ``` -The project path may be a directory or a `.csproj` file. If omitted, it defaults to the current directory. For a shell command named `whyconfig`, build and install the local tool package: - -```bash -dotnet pack src/WhyConfig.Cli -c Release -o artifacts -dotnet tool install WhyConfig.NET --tool-path .tools --add-source artifacts -``` - -Then run `.tools/whyconfig explain Database:Host --project path/to/YourApp` on macOS/Linux, or `.tools\whyconfig.exe explain Database:Host --project path\to\YourApp` on Windows. - -## CLI options +The CLI checks the project's `appsettings` files, Development User Secrets, and current environment variables. Run `dotnet run --project src/WhyConfig.Cli -- --help` for options. -```text -whyconfig explain [options] - ---project Project to inspect ---environment Environment to use ---secrets-id Explicit User Secrets ID ---app-arg Application argument; repeatable ---show-secrets Show values for keys that look sensitive ---json Emit machine-readable JSON -``` - -For example, if the application was launched with an argument that overrides `Api:Url`: - -```bash -whyconfig explain Api:Url --project ./MyApp --environment Development --app-arg Api:Url=http://localhost:5000 -``` - -The CLI reads `appsettings.json`, then `appsettings.{Environment}.json`, then User Secrets in `Development` when it can find a `UserSecretsId`, then its own process environment variables, then any `--app-arg` values. `--secrets-id` supplies the ID directly if it is not declared in the selected `.csproj`. If no environment is supplied, the CLI uses `DOTNET_ENVIRONMENT`, then `ASPNETCORE_ENVIRONMENT`, then `Production`. Supply `--environment` when the application's environment is different or uncertain. - -Exit code `0` means the key was found, `1` means no provider supplied it, and `2` means the command or input was invalid. - -## Inspect the running application's configuration - -Reference `src/WhyConfig.Core/WhyConfig.Core.csproj` from your application, then call the library with the actual root: +For the exact configuration of a running app, use `WhyConfig.Core` with its `IConfigurationRoot`: ```csharp using WhyConfig.Core; var builder = WebApplication.CreateBuilder(args); -var explanation = ConfigExplainer.Explain(builder.Configuration, "Database:Host"); - -Console.WriteLine($"Winner: {explanation.Winner?.Provider}"); -Console.WriteLine($"Effective value: {explanation.EffectiveValue}"); -foreach (var source in explanation.Sources) -{ - Console.WriteLine($"{source.Provider}: {source.Value} ({(source.IsWinner ? "winner" : "overridden")})"); -} -``` - -`IConfigurationRoot.Providers` contains the registered providers in order; later providers take precedence when they contain the same key. The library calls each provider's `TryGet` and reads the effective value from the root. This follows the [Microsoft configuration documentation](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-10.0). - -## Accuracy and sensitive values - -The CLI reconstructs a **common default** configuration setup. It cannot discover custom providers, application-specific registration order, launch arguments that were not supplied through `--app-arg`, or environment variables inside a different process or container. For an exact answer about a running app, call `WhyConfig.Core` with that app's `IConfigurationRoot`. - -The CLI masks values for keys with names such as `Password`, `Token`, `Secret`, `ApiKey`, and `ConnectionString` unless `--show-secrets` is set. This is a naming heuristic; other keys may still contain sensitive data. The library returns raw values to its caller. - -## Development - -```bash -dotnet test WhyConfig.slnx -c Release -dotnet pack src/WhyConfig.Cli -c Release -o artifacts +var result = ConfigExplainer.Explain(builder.Configuration, "Database:Host"); +Console.WriteLine($"{result.Winner?.Provider}: {result.EffectiveValue}"); ``` diff --git a/assets/whyconfig-demo.gif b/assets/whyconfig-demo.gif new file mode 100644 index 0000000..df00c34 Binary files /dev/null and b/assets/whyconfig-demo.gif differ diff --git a/src/WhyConfig.Cli/WhyConfig.Cli.csproj b/src/WhyConfig.Cli/WhyConfig.Cli.csproj index 9ecfd03..cc6033d 100644 --- a/src/WhyConfig.Cli/WhyConfig.Cli.csproj +++ b/src/WhyConfig.Cli/WhyConfig.Cli.csproj @@ -25,6 +25,7 @@ +