Skip to content

*.runtimeconfig.dev.json is ignored: Debug-only configProperties (Hot Reload switches) don't reach the runtime #26330

Description

@rolfbjarne

Apple platform

iOS, macOS, Mac Catalyst, tvOS

Framework version

net10.0-, net11.0-

Affected platform version

.NET 10 / .NET 11 (all current)

Description

.NET for iOS/tvOS/macOS/Mac Catalyst bakes the runtimeOptions.configProperties from *.runtimeconfig.json into the app at build time and hands them to the runtime directly (xamarin_bridge_vm_initialize, via the _CreateRuntimeConfiguration target in dotnet/targets/Xamarin.Shared.Sdk.targets). Because we do not go through hostfxr, the companion *.runtimeconfig.dev.json file is never merged on top of *.runtimeconfig.json.

Normally hostfxr layers *.runtimeconfig.dev.json over *.runtimeconfig.json at startup. The .NET SDK writes certain Debug-only switches (e.g. Hot Reload) into the dev file only, for example:

  • System.StartupHookProvider.IsSupported
  • System.Reflection.Metadata.MetadataUpdater.IsSupported

Since we bypass hostfxr, these switches never reach the runtime in our apps.

Root cause: the _CreateRuntimeConfiguration target invokes the shared RuntimeConfigParserTask (from dotnet/runtime, src/tasks/MonoTargetsTasks/RuntimeConfigParser) with a single RuntimeConfigFile input. That task reads only runtimeOptions.configProperties from the one file and has no notion of the dev file, so the dev values are dropped.

This is the same class of bug that dotnet/android fixed in dotnet/android#12249 (they have their own parser, RuntimePropertiesParser.cs, and layered the dev file's configProperties on top, with dev values winning — matching hostfxr).

Steps to Reproduce

  1. Create a Debug build of an iOS/macOS/etc. app.
  2. Set System.StartupHookProvider.IsSupported / MetadataUpdater.IsSupported expectations, or simply read them at runtime:
    AppContext.TryGetSwitch ("System.StartupHookProvider.IsSupported", out var startupHook);
    AppContext.TryGetSwitch ("System.Reflection.Metadata.MetadataUpdater.IsSupported", out var metadataUpdater);
  3. Observe that the switches written by the SDK into *.runtimeconfig.dev.json are not reflected at runtime (they don't get baked into runtimeconfig.bin).

Did you find any workaround?

Not a clean one. Setting the properties in the project so they land in *.runtimeconfig.json (rather than the dev file) would work around it, but that changes Release behavior too.

Relevant log output

No response

Fix direction

The proper fix is to merge the configProperties from $(ProjectRuntimeConfigDevFilePath) on top of those from $(ProjectRuntimeConfigFilePath) before/while producing runtimeconfig.bin, with dev values winning (matching hostfxr). Since we use the shared RuntimeConfigParserTask, the cleanest option is either:

  1. an upstream change to RuntimeConfigParserTask to accept an optional dev-file input (benefits wasm and the other Mono-based mobile workloads too), or
  2. a macios-local merge step that produces a merged runtimeconfig.json fed into the existing task.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugIf an issue is a bug or a pull request a bug fixcopilot

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions