Apply *.runtimeconfig.dev.json to CoreCLR apps - #12268
Open
jonathanpeppers wants to merge 2 commits into
Open
Conversation
Context: dotnet/sdk#53715 Port of #12249 to `main`. Starting with `11.0.100-preview.7.26376.106`, the .NET SDK emits a `<App>.runtimeconfig.dev.json` file for `Debug` builds containing the Hot Reload feature switches: { "runtimeOptions": { "configProperties": { "System.Reflection.Metadata.MetadataUpdater.IsSupported": true, "System.StartupHookProvider.IsSupported": true } } } `hostfxr` layers this file on top of `*.runtimeconfig.json` at startup, but .NET for Android does not use `hostfxr`: it bakes the runtime properties into the application at build time. So the file was simply ignored, and the switches never reached the app. Do the same layering at build time for CoreCLR: read the dev file after `*.runtimeconfig.json` in `RuntimePropertiesParser`, so its `configProperties` win. This matches what Blazor WebAssembly does in dotnet/runtime#130825. This does not conflict with the switches we set ourselves. `$(StartupHookSupport)` is only set to `false` when `'$(Optimize)' == 'true'`, and the SDK only generates the dev file for `Debug` builds, so the two are disjoint in practice. We never set `$(MetadataUpdaterSupport)`. Mono is unchanged: it reads runtime properties from the `rc.bin` blob produced by `RuntimeConfigParserTask`, which only accepts a single input file. Teaching that task about multiple files requires a change in dotnet/runtime. While here, add both `runtimeconfig` files to `_GetGeneratePackageManagerJavaInputs`. Neither was an input before, so editing them would not trigger a rebuild. `main` is still on an SDK that sets `$(GenerateRuntimeConfigDevFile)` to `false` for `net6.0`+, so the new `RuntimeConfigDevJsonIsApplied` device test writes the dev file and sets `$(ProjectRuntimeConfigDevFilePath)` itself. Both can be dropped once we pick up the newer SDK, at which point the `BuildTest.DotNetBuild` assertion for `*.runtimeconfig.dev.json` from #12249 can be added too. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b158ad70-1e5e-44cd-a1f2-60353f3bb560
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the CoreCLR build pipeline to apply *.runtimeconfig.dev.json at build time (since .NET for Android doesn’t use hostfxr), ensuring Debug-only Hot Reload feature switches flow into the baked runtime properties.
Changes:
- Layer
*.runtimeconfig.dev.jsonconfigPropertiesover*.runtimeconfig.jsoninRuntimePropertiesParser(dev file wins). - Plumb
$(ProjectRuntimeConfigDevFilePath)intoGenerateNativeApplicationConfigSourcesand include both runtimeconfig files as incremental inputs for_GeneratePackageManagerJava. - Add unit coverage for the parser merge behavior and a device integration test proving the switches reach the running app.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs | Adds a device test validating the dev runtimeconfig switches are observed at runtime for CoreCLR Debug builds. |
| src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets | Adds both runtimeconfig files as _GeneratePackageManagerJava inputs and passes the dev path into the native app config generation task. |
| src/Xamarin.Android.Build.Tasks/Utilities/RuntimePropertiesParser.cs | Implements merge logic to layer *.runtimeconfig.dev.json configProperties over the base runtimeconfig at build time. |
| src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/RuntimePropertiesParserTests.cs | Introduces unit tests for parsing and precedence rules between base and dev runtimeconfig files. |
| src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeApplicationConfigSources.cs | Plumbs the dev runtimeconfig path into RuntimePropertiesParser.ParseConfig(...) for CoreCLR builds. |
`AddConfigProperties (..., required: true)` used `GetProperty
("configProperties")`, which throws `KeyNotFoundException` when the file
omits the key. A project that sets no feature switches produces exactly
that shape, and it would have prevented `*.runtimeconfig.dev.json` from
being applied even though it carries the Hot Reload switches.
Drop the `required` flag and always use `TryGetProperty()`, treating a
missing `runtimeOptions` or `configProperties` in either file as "no
properties". This is also what `hostfxr` does.
Not reachable today: `Microsoft.Android.Sdk.CoreCLR.targets` adds four
`@(RuntimeHostConfigurationOption)` items unconditionally, so a CoreCLR
app always has a non-empty `configProperties`. Fix it anyway so the
merge does not depend on that.
Add `ConfigWithoutConfigPropertiesStillGetsDevProperties` to cover it.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b158ad70-1e5e-44cd-a1f2-60353f3bb560
jonathanpeppers
enabled auto-merge (squash)
July 30, 2026 20:52
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context: dotnet/sdk#53715
Port of #12249 (which targets
release/11.0.1xx-preview7) tomain.Starting with
11.0.100-preview.7.26376.106, the .NET SDK emits a<App>.runtimeconfig.dev.jsonfile forDebugbuilds containing the Hot Reload feature switches:{ "runtimeOptions": { "configProperties": { "System.Reflection.Metadata.MetadataUpdater.IsSupported": true, "System.StartupHookProvider.IsSupported": true } } }hostfxrlayers this file on top of*.runtimeconfig.jsonat startup, but .NET for Android does not usehostfxr: it bakes the runtime properties into the application at build time. So the file was simply ignored, and the switches never reached the app.Do the same layering at build time for CoreCLR: read the dev file after
*.runtimeconfig.jsoninRuntimePropertiesParser, so itsconfigPropertieswin. This matches what Blazor WebAssembly does in dotnet/runtime#130825.This does not conflict with the switches we set ourselves.
$(StartupHookSupport)is only set tofalsewhen'$(Optimize)' == 'true', and the SDK only generates the dev file forDebugbuilds, so the two are disjoint in practice. We never set$(MetadataUpdaterSupport).Mono is unchanged: it reads runtime properties from the
rc.binblob produced byRuntimeConfigParserTask, which only accepts a single input file. Teaching that task about multiple files requires a change in dotnet/runtime.While here, add both
runtimeconfigfiles to_GetGeneratePackageManagerJavaInputs. Neither was an input before, so editing them would not trigger a rebuild.Differences from #12249
The SDK
maincurrently builds against does not yet emit the dev file.Microsoft.NET.Sdk.targetsturns it off for every modern TFM:That condition is "6.0 or newer", so it applies to our
net11.0-androidprojects. With$(GenerateRuntimeConfigDevFile)false the SDK neither writes the file nor gives$(ProjectRuntimeConfigDevFilePath)a default. dotnet/sdk#53715 is what flips this back on. Two adjustments follow:RuntimeConfigDevJsonIsApplieddevice test writes the dev file and sets$(ProjectRuntimeConfigDevFilePath)itself. Both can be dropped oncemainpicks up the newer SDK.expectedFiles.Add ($"{proj.ProjectName}.runtimeconfig.dev.json")assertion that [release/11.0.1xx-preview7] Update dependencies from dotnet/dotnet #12249 adds toBuildTest.DotNetBuildis not ported, since it would fail on the current SDK. It should be added whenmaingets the newer SDK.Additional fix beyond #12249
AddConfigPropertiesoriginally usedGetProperty ("configProperties")for the base file, which throwsKeyNotFoundExceptionwhen the key is absent. Both files now useTryGetProperty, matchinghostfxr. Covered by the newConfigWithoutConfigPropertiesStillGetsDevPropertiestest.