diff --git a/src/mono/browser/runtime/loader/config.ts b/src/mono/browser/runtime/loader/config.ts index c691ee28e08f55..18542269288c23 100644 --- a/src/mono/browser/runtime/loader/config.ts +++ b/src/mono/browser/runtime/loader/config.ts @@ -324,6 +324,11 @@ async function loadBootConfig (module: DotnetModuleInternal): Promise { } } + // Prefer user-defined application environment + if (loaderHelpers.config.applicationEnvironment) { + loadedConfig.applicationEnvironment = loaderHelpers.config.applicationEnvironment; + } + deep_merge_config(loaderHelpers.config, loadedConfig); if (!loaderHelpers.config.applicationEnvironment) { @@ -343,7 +348,7 @@ async function readBootConfigResponse (loadConfigResponse: Response): Promise <_WasmBuildBootJsonPath>$(IntermediateOutputPath)$(_WasmBootConfigFileName) + <_WasmBuildApplicationEnvironmentName>$(WasmApplicationEnvironmentName) + <_WasmBuildApplicationEnvironmentName Condition="'$(_WasmBuildApplicationEnvironmentName)' == ''">Development @@ -359,6 +361,7 @@ Copyright (c) .NET Foundation. All rights reserved. + + <_WasmPublishApplicationEnvironmentName>$(WasmApplicationEnvironmentName) + <_WasmPublishAsset Include="@(StaticWebAsset)" @@ -649,6 +655,7 @@ Copyright (c) .NET Foundation. All rights reserved. LoadAppSettingsBasedOnApplicationEnvironmentData() + { + // Defaults + yield return new object?[] { false, null, null, "Development" }; + yield return new object?[] { true, null, null, "Production" }; + + // Override defaults from MSBuild + yield return new object?[] { false, "Production", null, "Production" }; + yield return new object?[] { true, "Development", null, "Development" }; + + // Override defaults from JavaScript + yield return new object?[] { false, null, "Production", "Production" }; + yield return new object?[] { true, null, "Development", "Development" }; + + // Override MSBuild from JavaScript + yield return new object?[] { false, "FromMSBuild", "Production", "Production" }; + yield return new object?[] { true, "FromMSBuild", "Development", "Development" }; + } + [Theory] - [InlineData("Development")] - [InlineData("Production")] - public async Task LoadAppSettingsBasedOnApplicationEnvironment(string applicationEnvironment) + [MemberData(nameof(LoadAppSettingsBasedOnApplicationEnvironmentData))] + public async Task LoadAppSettingsBasedOnApplicationEnvironment(bool publish, string? msBuildApplicationEnvironment, string? queryApplicationEnvironment, string expectedApplicationEnvironment) { Configuration config = Configuration.Debug; ProjectInfo info = CopyTestAsset(config, aot: false, TestAsset.WasmBasicTestApp, "AppSettingsTest"); - PublishProject(info, config); - BrowserRunOptions options = new( + string extraMSBuildArgs = msBuildApplicationEnvironment != null ? $"-p:WasmApplicationEnvironmentName={msBuildApplicationEnvironment}" : string.Empty; + + if (publish) + PublishProject(info, config, new PublishOptions(ExtraMSBuildArgs: extraMSBuildArgs)); + else + BuildProject(info, config, new BuildOptions(ExtraMSBuildArgs: extraMSBuildArgs)); + + BrowserRunOptions runOptions = new( config, TestScenario: "AppSettingsTest", - BrowserQueryString: new NameValueCollection { { "applicationEnvironment", applicationEnvironment } } + BrowserQueryString: new NameValueCollection { { "applicationEnvironment", queryApplicationEnvironment } } ); - RunResult result = await RunForPublishWithWebServer(options); + RunResult result = publish + ? await RunForPublishWithWebServer(runOptions) + : await RunForBuildWithDotnetRun(runOptions); + Assert.Contains(result.TestOutput, m => m.Contains("'/appsettings.json' exists 'True'")); - Assert.Contains(result.TestOutput, m => m.Contains($"'/appsettings.Development.json' exists '{applicationEnvironment == "Development"}'")); - Assert.Contains(result.TestOutput, m => m.Contains($"'/appsettings.Production.json' exists '{applicationEnvironment == "Production"}'")); + Assert.Contains(result.TestOutput, m => m.Contains($"'/appsettings.Development.json' exists '{expectedApplicationEnvironment == "Development"}'")); + Assert.Contains(result.TestOutput, m => m.Contains($"'/appsettings.Production.json' exists '{expectedApplicationEnvironment == "Production"}'")); } } diff --git a/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTestsBase.cs b/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTestsBase.cs index 688a41d1721358..bd7e983cbe2d95 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTestsBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTestsBase.cs @@ -60,7 +60,7 @@ public ProjectInfo CreateWasmTemplateProject( Configuration config, bool aot, string idPrefix = "wbt", - bool appendUnicodeToPath = true, + bool? appendUnicodeToPath = null, string extraArgs = "", bool runAnalyzers = true, bool addFrameworkArg = false, @@ -69,7 +69,7 @@ public ProjectInfo CreateWasmTemplateProject( string insertAtEnd = "") { (string projectName, string logPath, string nugetDir) = - InitProjectLocation(idPrefix, config, aot, appendUnicodeToPath); + InitProjectLocation(idPrefix, config, aot, appendUnicodeToPath ?? s_buildEnv.IsRunningOnCI); if (addFrameworkArg) extraArgs += $" -f {DefaultTargetFramework}"; @@ -107,14 +107,14 @@ protected ProjectInfo CopyTestAsset( bool aot, TestAsset asset, string idPrefix, - bool appendUnicodeToPath = true, + bool? appendUnicodeToPath = null, bool runAnalyzers = true, string extraProperties = "", string extraItems = "", string insertAtEnd = "") { (string projectName, string logPath, string nugetDir) = - InitProjectLocation(idPrefix, config, aot, appendUnicodeToPath, avoidAotLongPathIssue: s_isWindows && aot); + InitProjectLocation(idPrefix, config, aot, appendUnicodeToPath ?? s_buildEnv.IsRunningOnCI, avoidAotLongPathIssue: s_isWindows && aot); Utils.DirectoryCopy(Path.Combine(BuildEnvironment.TestAssetsPath, asset.Name), Path.Combine(_projectDir)); if (!string.IsNullOrEmpty(asset.RunnableProjectSubPath)) { diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js index 8a773e2756aaa1..500fcc22a3708d 100644 --- a/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js +++ b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js @@ -44,7 +44,10 @@ switch (testCase) { } break; case "AppSettingsTest": - dotnet.withApplicationEnvironment(params.get("applicationEnvironment")); + const applicationEnvironment = params.get("applicationEnvironment"); + if (applicationEnvironment) { + dotnet.withApplicationEnvironment(applicationEnvironment); + } break; case "LazyLoadingTest": dotnet.withDiagnosticTracing(true); diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/README.md b/src/mono/wasm/testassets/WasmBasicTestApp/README.md similarity index 93% rename from src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/README.md rename to src/mono/wasm/testassets/WasmBasicTestApp/README.md index 996992663189fb..2bc6281f4057d7 100644 --- a/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/README.md +++ b/src/mono/wasm/testassets/WasmBasicTestApp/README.md @@ -8,7 +8,7 @@ It typically suits scenario where you need more than a plain template app. If th The app reads `test` query parameter and uses it to switch between test cases. Entrypoint is `main.js`. There is common unit, then switch based on test case for modifying app startup, then app starts and executes next switch based on test case for actually running code. -Some test cases passes additional parameters to differentiate behavior, see `src/mono/wasm/Wasm.Build.Tests/TestAppScenarios`. +Some test cases passes additional parameters to differentiate behavior, see `src/mono/wasm/Wasm.Build.Tests`. ### Running out side of WBT diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/BootJsonData.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/BootJsonData.cs index 4d3c57ff4580ff..c0ef0132d71998 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/BootJsonData.cs +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/BootJsonData.cs @@ -24,6 +24,9 @@ public class BootJsonData public string mainAssemblyName { get; set; } + [DataMember(EmitDefaultValue = false)] + public string applicationEnvironment { get; set; } + /// /// Gets the set of resources needed to boot the application. This includes the transitive /// closure of .NET assemblies (including the entrypoint assembly), the dotnet.wasm file, diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs index 328ac158fdf52d..604422c9a852d0 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs @@ -84,6 +84,8 @@ public class GenerateWasmBootJson : Task public bool FingerprintAssets { get; set; } + public string ApplicationEnvironment { get; set; } + public override bool Execute() { var entryAssemblyName = AssemblyName.GetAssemblyName(AssemblyPath).Name; @@ -107,9 +109,14 @@ private void WriteBootConfig(string entryAssemblyName) var result = new BootJsonData { resources = new ResourcesData(), - startupMemoryCache = helper.ParseOptionalBool(StartupMemoryCache), + startupMemoryCache = helper.ParseOptionalBool(StartupMemoryCache) }; + if (IsTargeting100OrLater()) + { + result.applicationEnvironment = ApplicationEnvironment; + } + if (IsTargeting80OrLater()) { result.mainAssemblyName = entryAssemblyName; @@ -489,6 +496,7 @@ private static bool TryGetLazyLoadedAssembly(Dictionary lazyL private Version? parsedTargetFrameworkVersion; private static readonly Version version80 = new Version(8, 0); private static readonly Version version90 = new Version(9, 0); + private static readonly Version version100 = new Version(10, 0); private bool IsTargeting80OrLater() => IsTargetingVersionOrLater(version80); @@ -496,6 +504,9 @@ private bool IsTargeting80OrLater() private bool IsTargeting90OrLater() => IsTargetingVersionOrLater(version90); + private bool IsTargeting100OrLater() + => IsTargetingVersionOrLater(version100); + private bool IsTargetingVersionOrLater(Version version) { if (parsedTargetFrameworkVersion == null)