Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions docs/design/FeatureSwitches.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ The following switches are toggled for applications running on Mono for `TrimMod
| MauiNamescopesSupported | Microsoft.Maui.RuntimeFeature.AreNamescopesSupported | Enable support for Namescopes, FindByName if the application uses it, or to keep supporting runtime and XamlC XAML inflators |
| EnableDiagnostics | Microsoft.Maui.RuntimeFeature.EnableDiagnostics | Enables diagnostic for the running app |
| EnableMauiDiagnostics | Microsoft.Maui.RuntimeFeature.EnableMauiDiagnostics | Enables MAUI specific diagnostics, like VisualDiagnostics and BindingDiagnostics. Defaults to EnableDiagnostics |
| _EnableMauiAspire | Microsoft.Maui.RuntimeFeature.EnableMauiAspire | When enabled, MAUI Aspire integration features are available. **Warning**: Using Aspire outside of Debug configuration may introduce performance and security risks in production. |

## MauiEnableIVisualAssemblyScanning

Expand Down Expand Up @@ -99,3 +100,28 @@ Defaults to `false`
Enable VisualDiagnostics and BindingDiagnostics

Defaults to `EnableDiagnostics`

## _EnableMauiAspire

Controls whether MAUI Aspire integration features are enabled at runtime.

**Default Value**: `true`

**Automatic Configuration**: This feature switch is automatically configured by the MAUI build system based on optimization settings:
- **Non-optimized builds (Debug)**: Enabled (`true`)
- **Optimized builds (Release)**: Disabled (`false`)
- **Regular builds (no AOT/Trimming)**: Uses runtime default (`true`)

The automatic configuration only applies when `PublishAot=true` OR `TrimMode=full` is set.

**Manual Override** (Not Recommended): While it's possible to manually override this setting, it's not recommended as it may introduce performance and security risks in production:

```xml
<PropertyGroup>
<_EnableMauiAspire>true</_EnableMauiAspire>
</PropertyGroup>
```

**Warning**: Manually setting this property in optimized builds (where `Optimize=true`) will trigger build warning MA002.

**Trimming Behavior**: When `_EnableMauiAspire=false` and trimming is enabled, the .NET trimmer can eliminate MAUI Aspire-related code paths, reducing the final application size and potentially improving performance in production scenarios.
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,13 @@
<PropertyGroup>
<MauiEnableIVisualAssemblyScanning Condition="'$(MauiEnableIVisualAssemblyScanning)' == ''">false</MauiEnableIVisualAssemblyScanning>
</PropertyGroup>

<!-- Validate _EnableMauiAspire usage - warn when user manually sets it in optimized builds where it conflicts with intended behavior -->
<Warning
Code="MA002"
Text="The _EnableMauiAspire property should not be set manually. Using Aspire outside the Debug configuration may introduce performance and security risks in production. This property is automatically configured based on build configuration."
Condition="'$(_EnableMauiAspire)' != '' and '$(Optimize)' == 'true' and '$(MauiDisableAspireValidation)' != 'True'"/>

<PropertyGroup Condition="'$(PublishAot)' == 'true' or '$(TrimMode)' == 'full'">
<MauiShellSearchResultsRendererDisplayMemberNameSupported Condition="'$(MauiShellSearchResultsRendererDisplayMemberNameSupported)' == ''">false</MauiShellSearchResultsRendererDisplayMemberNameSupported>
<MauiQueryPropertyAttributeSupport Condition="'$(MauiQueryPropertyAttributeSupport)' == ''">false</MauiQueryPropertyAttributeSupport>
Expand All @@ -280,6 +287,10 @@
<MauiHybridWebViewSupported Condition="'$(MauiHybridWebViewSupported)' == ''">false</MauiHybridWebViewSupported>
<!-- FIXME: https://github.com/xamarin/xamarin-macios/issues/22065 -->
<MobileAggressiveAttributeTrimming Condition="'$(PublishAot)' == 'true' and '$(MobileAggressiveAttributeTrimming)' == ''">false</MobileAggressiveAttributeTrimming>

<!-- Set _EnableMauiAspire based on whether optimizations are enabled when not already set -->
<_EnableMauiAspire Condition="'$(_EnableMauiAspire)' == '' and '$(Optimize)' != 'true'">true</_EnableMauiAspire>
<_EnableMauiAspire Condition="'$(_EnableMauiAspire)' == ''">false</_EnableMauiAspire>
</PropertyGroup>
<ItemGroup>
<RuntimeHostConfigurationOption Include="Microsoft.Maui.RuntimeFeature.IsIVisualAssemblyScanningEnabled"
Expand Down Expand Up @@ -318,6 +329,10 @@
Condition="'$(EnableDiagnostics)' != ''"
Value="$(EnableDiagnostics)"
Trim="true" />
<RuntimeHostConfigurationOption Include="Microsoft.Maui.RuntimeFeature.EnableMauiAspire"
Condition="'$(_EnableMauiAspire)' != ''"
Value="$(_EnableMauiAspire)"
Trim="true" />
</ItemGroup>
</Target>
</Project>
27 changes: 27 additions & 0 deletions src/Core/src/Hosting/Dispatching/AppHostBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -35,8 +36,34 @@ public static MauiAppBuilder ConfigureDispatching(this MauiAppBuilder builder)

public static MauiAppBuilder ConfigureEnvironmentVariables(this MauiAppBuilder builder)
{
if (!RuntimeFeature.EnableMauiAspire)
{
return builder;
}

IDictionary environmentVariables = Environment.GetEnvironmentVariables();

#if ANDROID
const string androidEnvVarFilePath = "/data/local/tmp/ide-launchenv.txt";

// For Android we read the environment variables from a text file that is written to the device/emulator
// If the file not exists, we will use the default environment variables which is less stable
if (OperatingSystem.IsAndroid() && System.IO.File.Exists(androidEnvVarFilePath))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the IsAndroid() check if it's inside #if ANDROID?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not! Double safe!

{
var envVarLines = System.IO.File.ReadAllLines(androidEnvVarFilePath);

var fileEnvironmentVariables = envVarLines
.Select(line => line.Split('=', 2))
.ToDictionary(parts => parts[0], parts => parts[1]);

// Merge file environment variables into the existing environment variables
foreach (var kvp in fileEnvironmentVariables)
{
environmentVariables[kvp.Key] = kvp.Value;
}
}
#endif

string devTunnelId = environmentVariables["DEVTUNNEL_ID"]?.ToString() ?? string.Empty;

var variablesToInclude = new HashSet<string>
Expand Down
9 changes: 9 additions & 0 deletions src/Core/src/RuntimeFeature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ static class RuntimeFeature
const bool SupportNamescopesByDefault = true;
const bool EnableDiagnosticsByDefault = false;
const bool IsMeterSupportedByDefault = true;
const bool EnableAspireByDefault = true;

#pragma warning disable IL4000 // Return value does not match FeatureGuardAttribute 'System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute'.
#if NET9_0_OR_GREATER
Expand Down Expand Up @@ -138,6 +139,14 @@ internal set
AppContext.SetSwitch($"{FeatureSwitchPrefix}.{nameof(EnableMauiDiagnostics)}", value);
}
}

#if NET9_0_OR_GREATER
[FeatureSwitchDefinition($"{FeatureSwitchPrefix}.{nameof(EnableMauiAspire)}")]
#endif
public static bool EnableMauiAspire => AppContext.TryGetSwitch($"{FeatureSwitchPrefix}.{nameof(EnableMauiAspire)}", out bool isEnabled)
? isEnabled
: EnableAspireByDefault;

#pragma warning restore IL4000
}
}
Loading