Skip to content

Better support for non-standard $(Configuration) names #31918

Open

Description

@jonathanpeppers

Is your feature request related to a problem? Please describe.

.NET MAUI customers commonly create customer project configuration names, such as ReleaseProd, AdHoc, AppStore, etc.

Visual Studio gives a handy UI for creating configurations and setting properties based on them, and so customers use this to toggle values in their applications such as:

  • Service endpoint URLs: is it Dev or Prod? Using $(DefineConstants) and #if together.
  • iOS signing settings: is it a Release build for the App Store or Development/beta testing

The problem becomes once a custom configuration is made, customers have to somehow know lots of MSBuild properties to set. Starting with:

<!-- User-facing configuration-specific defaults -->
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols Condition=" '$(DebugSymbols)' == '' ">true</DebugSymbols>
<Optimize Condition=" '$(Optimize)' == '' ">false</Optimize>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<Optimize Condition=" '$(Optimize)' == '' ">true</Optimize>
</PropertyGroup>

At minimum, they would need to know to set $(DebugSymbol) and $(Optimize) appropriately.

Then for mobile, they would also need:

  • For Debug scenarios
    • $(UseInterpreter) set to true for Hot Reload
    • $(EmbedAssembliesIntoApk) set to false for Android "fast deployment" / sideloading
  • For Release scenarios on Android
    • $(PublishTrimmed)
    • $(RunAOTCompilation)
    • $(AndroidPackageFormat) set to aab to create Android "app bundles" for Google Play instead of an .apk
  • The settings required on iOS further complicates things
    • Debug builds need $(PublishTrimmed)
    • Trimmer settings like $(DebuggerSupport) are off for Release mode

There may be several more iOS properties I've left out here.

Describe the solution you'd like

A simple approach would be introduction of new properties like $(IsDebug) and $(IsRelease) where the new code would instead do:

 <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> 
   <IsDebug Condition=" '$(IsDebug)' == '' ">true</IsDebug> 
 </PropertyGroup> 
  <PropertyGroup Condition=" '$(Configuration)' == 'Release' "> 
   <IsRelease Condition=" '$(IsRelease)' == '' ">true</IsRelease> 
 </PropertyGroup> 
 <PropertyGroup Condition=" '$(IsDebug)' == 'true' "> 
   <DebugSymbols Condition=" '$(DebugSymbols)' == '' ">true</DebugSymbols> 
   <Optimize Condition=" '$(Optimize)' == '' ">false</Optimize> 
 </PropertyGroup> 
 <PropertyGroup Condition=" '$(IsRelease)' == 'true' "> 
   <Optimize Condition=" '$(Optimize)' == '' ">true</Optimize> 
 </PropertyGroup> 

Customer projects would do:

<PropertyGroup Condition=" '$(Configuration)' == 'DebugFoo' ">
  <IsDebug>true</IsDebug>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'ReleaseFoo' ">
  <IsRelease>true</IsRelease>
</PropertyGroup>

And then any defaults defined in optional workloads, etc. are based on these new properties instead of the configuration name directly.

An alternative would be some new MSBuild feature to "inherit" or "extend" configurations. That may just be too much for solving this problem.

Links

Activity

  1. ghost added
    untriagedRequest triage from a team member
    on Apr 20, 2023
  2. jonathanpeppers commented on Apr 20, 2023

    @jonathanpeppers
    MemberAuthor

    @rolfbjarne is there anything you'd like to add here?

  3. rolfbjarne commented on Apr 21, 2023

    @rolfbjarne
    Member

    We've documented the properties for iOS that depend on the configuration here: https://github.com/xamarin/xamarin-macios/blob/main/docs/configuration-properties.md

    One point is what's the difference beteween "release" and "publish": would "dotnet build /p:Configuration=Release" be the same as "dotnet publish"? Or would we need a third option (say IsPublish) as well?

    Otherwise I agree with everything in the description :)

  4. jonathanpeppers commented on Apr 21, 2023

    @jonathanpeppers
    MemberAuthor

    There is a new $(PublishRelease) that will default to true in .NET 8:

    https://learn.microsoft.com/dotnet/core/project-sdk/msbuild-props#publishrelease

    So anything changed here, should keep this property in mind.

  5. rolfbjarne commented on May 26, 2023

    @rolfbjarne
    Member

    Another idea could be to let the user tell us their intentions.

    So we could have a BuildIntention property with a set of known values (say Debug, Release, Profile, etc.)

    And maybe a PublishIntention property as well (with values such as AppStore, AdHoc, WebSite - each SDK would support a certain set of of intentions, and also define the meaning of each).

    By default we'd do something like:

    <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
        <BuildIntention Condition=" '$(BuildIntention)' == '' ">Debug</BuildIntention>
    </PropertyGroup>
    <PropertyGroup Condition=" '$(BuildIntention)' == 'Debug' "> 
        <DebugSymbols Condition=" '$(DebugSymbols)' == '' ">true</DebugSymbols> 
        <Optimize Condition=" '$(Optimize)' == '' ">false</Optimize> 
    </PropertyGroup> 
  6. grendello commented on Oct 12, 2023

    @grendello

    @rolfbjarne I like your idea, but I would stay with just a single property, say BuildProfile (instead of BuildIntention - I think "profile" expresses the goal better in this case), with the semantics of your BuildIntention. PublishIntention is, IMO, unnecessary since publishing involves building at some point. A single variable with a restricted (but open for future additions) set of values would be easier to document, create less information overload.

  7. rolfbjarne commented on Oct 13, 2023

    @rolfbjarne
    Member

    PublishIntention is, IMO, unnecessary since publishing involves building at some point.

    This is intented to solve the following problem: for macOS (and Mac Catalyst), publishing to the App Store involves using a signing configuration that produces an app that won't run locally, and publishing outside of the App Store involves a signing configuration that produces an app that can't be published to the App Store. People get this wrong all the time (Apple didn't make signing particularly easy to be honest), but if we knew the developer's intentions, we could create better defaults, and show warnings/errors if the developer does something we know won't work. Right now our defaults are wrong half the time...

  8. mtanml commented on May 2, 2024

    @mtanml

    Any updates on this? We have a MAUI project with 14 debug profiles and 14 release profiles to build all of our apps. Among other issues, hot reload isn't working. Thanks

  9. phillippschmedt commented on May 2, 2024

    @phillippschmedt

    @mtanml We have a similar scope on our configurations and also struggle with the hot reload bit the most. We tried to manually set all the android/ios defaults for our debug/release equivalent but it will still not work.

  10. jonathanpeppers commented on May 2, 2024

    @jonathanpeppers
    MemberAuthor

    We have a MAUI project with 14 debug profiles and 14 release profiles

    So, I would assume you have various MSBuild logic that has conditions on $(Configuration). A workaround for now would be to use a different property for now like $(Brand) and set it to your custom values like Nike and Adidas, for example. Then just use Debug and Release for $(Configuration), as it seems like the only sane approach. To toggle the $(Brand) value, you could set it your .csproj, Directory.Build.props, custom MSBuild file, etc.

    However, I'm with you; it would be nice if the .NET SDK had support for this.

  11. MichaelLHerman commented on Feb 5, 2025

    @MichaelLHerman

    For anyone working off the values in the question, PublishTrimmed should not be used anymore

    From https://learn.microsoft.com/en-us/dotnet/maui/deployment/trimming?view=net-maui-9.0:

    Don't set the $(PublishTrimmed) build property in your app's project file, because this is set by default when required.

    Documentation is still not unified and all over the place and it seems like its not possible to make a 2nd Hot Reload Debug-like config

    https://github.com/xamarin/xamarin-macios/blob/main/docs/configuration-properties.md

    https://learn.microsoft.com/en-us/dotnet/ios/building-apps/build-properties#trimmode

    From https://learn.microsoft.com/en-us/dotnet/maui/xaml/hot-reload?view=net-maui-9.0:

    In all cases, XAML Hot Reload requires your debug configuration to be named Debug.

  12. AlleSchonWeg commented on May 6, 2025

    @AlleSchonWeg

    Hi @jonathanpeppers ,

    i also have more than one release configuration. When i use the default 'Release' configuration my apk has a size of 52.391 Kb. When i use my custom configuration my apk is 18.364 Kb. Default 'Debug' the apk is 18.524 Kb. I only add a value to DefineConstants, depending on the configuration.
    My guess the size gap between 'Release' and the other two configurations is because that more architectures included in the 'Release' apk. Is this correct?
    For my custom configuration i want a release build. So i expect that the apk size for my custom build is also 52.391 Kb. What properties i have to set to get a release build?
    It would be nice to know which are the default build property values for 'Debug' and 'Release'. It makes it easier to create custom build configuration based on 'Debug' or 'Release'.

    Thank you.

  13. jonathanpeppers commented on May 6, 2025

    @jonathanpeppers
    MemberAuthor

    Since no one knows the full set of properties, the solution for now is:

    • Use the Release configuration
    • If you need some changes for certain builds, use a different MSBuild property to trigger this, such as:
    dotnet build -c Release -p:IsGooglePlay=true
    
    <PropertyGroup Condition=" '$(IsGooglePlay)' == 'true' ">
        <!-- Any Google Play specific settings -->
    </PropertyGroup>

    You can name $(IsGooglePlay) anything you want, but I would try to choose a unique name that won't conflict with some other existing property.

  14. 3 remaining items

  15. LeoJHarris commented on May 7, 2025

    @LeoJHarris

    @jonathanpeppers I think there's also a lot more developers then we realize that use Config names outside of the Release|Debug etc.

  16. dartasen commented on Jun 16, 2025

    @dartasen

    It's crazy that such an obvious pain-point hasn't been addressed by Microsoft in years

  17. phillippschmedt commented on Jun 16, 2025

    @phillippschmedt

    It's crazy that such an obvious pain-point hasn't been addressed by Microsoft in years

    I agree that it's a useful feature. But there is definitely way more crazy bugs in MAUI that are open for years :-D Does the solution suggested by @baaaaif with custom properties not work for you? We are doing quite fine with it.

  18. added this to the Backlog milestone on Apr 14, 2026
  19. jonathanpeppers commented on May 11, 2026

    @jonathanpeppers
    MemberAuthor

    Reviving this issue, here are some of my current thoughts...

    Name it $(ConfigurationBasedOn), and it's either Debug or Release for now. This name is pretty clean from GH search:

    (Some of the other suggested names, I can find existing usage)

    <PropertyGroup Condition=" '$(ConfigurationBasedOn)' == '' ">
      <ConfigurationBasedOn Condition=" '$(Configuration)' == 'Debug' or '$(Configuration)' == 'Release' ">$(Configuration)</ConfigurationBasedOn>
    </PropertyGroup>
    <PropertyGroup Condition=" '$(ConfigurationBasedOn)' == 'Debug' "> 
      <DebugSymbols Condition=" '$(DebugSymbols)' == '' ">true</DebugSymbols> 
      <Optimize Condition=" '$(Optimize)' == '' ">false</Optimize> 
    </PropertyGroup>
    <PropertyGroup Condition=" '$(ConfigurationBasedOn)' == 'Release' "> 
      <Optimize Condition=" '$(Optimize)' == '' ">true</Optimize> 
    </PropertyGroup>

    Customer projects could do:

    <PropertyGroup Condition="'$(Configuration)' == 'DebugProd'">
      <ConfigurationBasedOn>Debug</ConfigurationBasedOn>
    </PropertyGroup>
    <PropertyGroup Condition="'$(Configuration)' == 'AppStore'">
      <ConfigurationBasedOn>Release</ConfigurationBasedOn>
    </PropertyGroup>

    Then we wouldn't have to update every spot that uses $(Configuration), only places that compare it vs Debug or Release, which is mainly:

    Other repos could slowly start adopting this after merged into dotnet/sdk.

    /cc @baronfel

  20. marcpopMSFT commented on May 12, 2026

    @marcpopMSFT
    Member

    Triage: We discussed and a concern we had is that some of the places that these are used are in props so it would force the customer to set this in directory.build.props (ie it couldn't be a per project Configuration). That limitation affects ArtifactsPath as well and has slowed adoption of that.

    An alternative is to design a props file that gets imported to set all release or all debug properties. We'd need a full list of everywhere this needs to be set so we'd need to check msbuild, roslyn, runtime, vstest, maybe c++ as well. We think msbuild and roslyn are probably clean.

  21. jonathanpeppers commented on May 18, 2026

    @jonathanpeppers
    MemberAuthor

    My example above (#31918 (comment)) wouldn't work due to ordering:

    1. Microsoft.NET.Sdk.props looks at $(Configuration)
    2. User's .csproj is evaluated, where you'd set $(ConfigurationBasedOn) -- this is already too late

    Directory.Build.props might work, but that is solution-wide. "Inventing a new file" seems like the only solution here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions