diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index fc8874e7fa8..0995b202f4a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -6,10 +6,12 @@ /src/Aspire.Hosting.Azure.AppContainers @captainsafia @eerhardt /src/Aspire.Hosting.Azure.AppService @captainsafia @eerhardt /src/Aspire.Hosting.Docker @captainsafia +/src/Aspire.Hosting.Maui @jfversluis # tests /tests/Aspire.EndToEnd.Tests @radical @eerhardt +/tests/Aspire.Hosting.Maui.Tests @jfversluis /tests/Aspire.Hosting.Testing.Tests @reubenbond /tests/Aspire.Hosting.Tests @mitchdenny /tests/Aspire.Templates.Tests @radical @eerhardt @@ -20,3 +22,4 @@ # playground apps /playground/deployers @captainsafia /playground/publishers @captainsafia +/playground/AspireWithMaui @jfversluis diff --git a/Aspire.slnx b/Aspire.slnx index 2dab93a8f6a..c2e83311af1 100644 --- a/Aspire.slnx +++ b/Aspire.slnx @@ -55,6 +55,7 @@ + diff --git a/AspireWithMaui.slnx b/AspireWithMaui.slnx new file mode 100644 index 00000000000..6e84d6544d3 --- /dev/null +++ b/AspireWithMaui.slnx @@ -0,0 +1,479 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NuGet.config b/NuGet.config index bae60ec60c9..04aedeae849 100644 --- a/NuGet.config +++ b/NuGet.config @@ -16,6 +16,7 @@ + @@ -35,6 +36,9 @@ + + + diff --git a/eng/Build.props b/eng/Build.props index ea01d331e94..f07ca2fe49f 100644 --- a/eng/Build.props +++ b/eng/Build.props @@ -28,7 +28,9 @@ - + + + + + Exe + AspireWithMaui.MauiClient + true + true + enable + enable + + + false + + + $(NoWarn);CS8002 + + + $(NoWarn);IDE0005 + + + AspireWithMaui.MauiClient + + + com.companyname.aspirewithmaui.mauiclient + + + 1.0 + 1 + + + None + + 15.0 + 15.0 + 21.0 + 10.0.17763.0 + 10.0.17763.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/playground/AspireWithMaui/AspireWithMaui.MauiClient/EnvironmentPage.xaml b/playground/AspireWithMaui/AspireWithMaui.MauiClient/EnvironmentPage.xaml new file mode 100644 index 00000000000..946c5d642fc --- /dev/null +++ b/playground/AspireWithMaui/AspireWithMaui.MauiClient/EnvironmentPage.xaml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/playground/AspireWithMaui/AspireWithMaui.MauiClient/EnvironmentPage.xaml.cs b/playground/AspireWithMaui/AspireWithMaui.MauiClient/EnvironmentPage.xaml.cs new file mode 100644 index 00000000000..f9a1325aa41 --- /dev/null +++ b/playground/AspireWithMaui/AspireWithMaui.MauiClient/EnvironmentPage.xaml.cs @@ -0,0 +1,79 @@ +using System.Collections; +using System.Collections.ObjectModel; + +namespace AspireWithMaui.MauiClient; + +public partial class EnvironmentPage : ContentPage +{ + public ObservableCollection> AspireEnvironmentVariables { get; } = new(); + + public EnvironmentPage() + { + InitializeComponent(); + BindingContext = this; + } + + protected override void OnAppearing() + { + base.OnAppearing(); + LoadAspireEnvironmentVariables(); + } + + private void LoadAspireEnvironmentVariables() + { + AspireEnvironmentVariables.Clear(); + + var variables = Environment.GetEnvironmentVariables() + .Cast() + .Select(entry => new KeyValuePair(entry.Key?.ToString() ?? string.Empty, DecodeValue(entry.Value?.ToString()))) + .Where(item => IsAspireVariable(item.Key)) + .OrderBy(item => item.Key, StringComparer.OrdinalIgnoreCase); + + foreach (var variable in variables) + { + AspireEnvironmentVariables.Add(variable); + } + } + + private static string DecodeValue(string? value) + { + if (string.IsNullOrEmpty(value)) + { + return string.Empty; + } + + try + { + var decoded = Uri.UnescapeDataString(value); + + // Validate that the decoded string doesn't contain control characters that could indicate malicious content + // Allow only printable characters, tabs, and newlines + if (decoded.Any(c => char.IsControl(c) && c != '\t' && c != '\n' && c != '\r')) + { + // If suspicious control characters found, return the original encoded value for safety + return value; + } + + return decoded; + } + catch (UriFormatException) + { + // If decoding fails, return the original value + return value; + } + } + + private static bool IsAspireVariable(string key) + => key.StartsWith("services__", StringComparison.OrdinalIgnoreCase) + || key.StartsWith("connectionstrings__", StringComparison.OrdinalIgnoreCase) + || key.StartsWith("ASPIRE_", StringComparison.OrdinalIgnoreCase) + || key.StartsWith("AppHost__", StringComparison.OrdinalIgnoreCase) + || key.StartsWith("OTEL_", StringComparison.OrdinalIgnoreCase) + || key.StartsWith("LOGGING__CONSOLE", StringComparison.OrdinalIgnoreCase) + || key.Equals("ASPNETCORE_ENVIRONMENT", StringComparison.OrdinalIgnoreCase) + || key.Equals("ASPNETCORE_URLS", StringComparison.OrdinalIgnoreCase) + || key.Equals("DOTNET_ENVIRONMENT", StringComparison.OrdinalIgnoreCase) + || key.Equals("DOTNET_URLS", StringComparison.OrdinalIgnoreCase) + || key.Equals("DOTNET_LAUNCH_PROFILE", StringComparison.OrdinalIgnoreCase) + || key.Equals("DOTNET_SYSTEM_CONSOLE_ALLOW_ANSI_COLOR_REDIRECTION", StringComparison.OrdinalIgnoreCase); +} diff --git a/playground/AspireWithMaui/AspireWithMaui.MauiClient/MainPage.xaml b/playground/AspireWithMaui/AspireWithMaui.MauiClient/MainPage.xaml new file mode 100644 index 00000000000..6e8ebf4d413 --- /dev/null +++ b/playground/AspireWithMaui/AspireWithMaui.MauiClient/MainPage.xaml @@ -0,0 +1,80 @@ + + + + + + + +