diff --git a/NuGet.config b/NuGet.config
index 06e49041de2f..f9ca5d18191c 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -4,10 +4,10 @@
-
+
-
+
@@ -27,10 +27,10 @@
-
+
-
+
diff --git a/eng/Baseline.Designer.props b/eng/Baseline.Designer.props
index 7bbef3953446..67ffbf7b4c5d 100644
--- a/eng/Baseline.Designer.props
+++ b/eng/Baseline.Designer.props
@@ -2,28 +2,28 @@
$(MSBuildAllProjects);$(MSBuildThisFileFullPath)
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
-
-
-
+
+
+
@@ -34,120 +34,120 @@
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
-
-
+
+
- 6.0.4
+ 6.0.5
-
-
+
+
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
-
+
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
@@ -155,114 +155,114 @@
- 6.0.4
+ 6.0.5
-
+
-
+
-
+
- 6.0.4
+ 6.0.5
-
+
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
-
+
- 6.0.4
+ 6.0.5
-
-
+
+
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
-
-
+
+
- 6.0.4
+ 6.0.5
-
+
- 6.0.4
+ 6.0.5
-
-
-
+
+
+
-
+
- 6.0.4
+ 6.0.5
-
-
+
+
- 6.0.4
+ 6.0.5
-
-
+
+
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
-
-
+
+
@@ -270,7 +270,7 @@
- 6.0.4
+ 6.0.5
@@ -278,50 +278,50 @@
- 6.0.4
+ 6.0.5
-
+
-
+
-
-
+
+
-
+
-
+
-
-
+
+
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
-
+
-
+
-
+
- 6.0.4
+ 6.0.5
-
-
+
+
@@ -331,8 +331,8 @@
-
-
+
+
@@ -340,8 +340,8 @@
-
-
+
+
@@ -352,58 +352,58 @@
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
-
-
+
+
- 6.0.4
+ 6.0.5
-
+
-
+
-
+
- 6.0.4
+ 6.0.5
-
+
-
+
-
+
- 6.0.4
+ 6.0.5
-
+
- 6.0.4
+ 6.0.5
@@ -411,71 +411,71 @@
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
-
+
-
+
-
+
-
+
- 6.0.4
+ 6.0.5
-
-
+
+
-
+
-
-
+
+
- 6.0.4
+ 6.0.5
-
-
+
+
- 6.0.4
+ 6.0.5
-
-
+
+
- 6.0.4
+ 6.0.5
@@ -491,195 +491,195 @@
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
-
+
- 6.0.4
+ 6.0.5
-
-
+
+
- 6.0.4
+ 6.0.5
-
-
+
+
- 6.0.4
+ 6.0.5
-
+
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
-
+
- 6.0.4
+ 6.0.5
-
-
+
+
-
-
+
+
-
-
+
+
- 6.0.4
+ 6.0.5
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
- 6.0.4
+ 6.0.5
-
+
-
+
-
+
-
+
-
+
- 6.0.4
+ 6.0.5
-
+
-
+
-
+
- 6.0.4
+ 6.0.5
-
+
-
+
-
+
- 6.0.4
+ 6.0.5
-
+
-
+
-
+
- 6.0.4
+ 6.0.5
-
-
-
-
+
+
+
+
- 6.0.4
+ 6.0.5
@@ -688,69 +688,69 @@
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
-
+
- 6.0.4
+ 6.0.5
-
+
- 6.0.4
+ 6.0.5
-
+
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
@@ -769,7 +769,7 @@
- 6.0.4
+ 6.0.5
@@ -788,7 +788,7 @@
- 6.0.4
+ 6.0.5
@@ -804,46 +804,46 @@
- 6.0.4
+ 6.0.5
-
+
-
+
-
+
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
-
-
-
+
+
+
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
@@ -853,7 +853,7 @@
- 6.0.4
+ 6.0.5
@@ -862,73 +862,73 @@
- 6.0.4
+ 6.0.5
-
+
-
+
-
+
- 6.0.4
+ 6.0.5
-
+
-
+
-
+
- 6.0.4
+ 6.0.5
-
+
-
+
-
+
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
@@ -957,11 +957,11 @@
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
@@ -979,13 +979,13 @@
- 6.0.4
+ 6.0.5
- 6.0.4
+ 6.0.5
-
+
\ No newline at end of file
diff --git a/eng/Baseline.xml b/eng/Baseline.xml
index e20bb4bb51a8..32b7ff01b908 100644
--- a/eng/Baseline.xml
+++ b/eng/Baseline.xml
@@ -4,111 +4,111 @@ This file contains a list of all the packages and their versions which were rele
Update this list when preparing for a new patch.
-->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/eng/Dependencies.props b/eng/Dependencies.props
index 3c179c39aecb..75c41177ffa6 100644
--- a/eng/Dependencies.props
+++ b/eng/Dependencies.props
@@ -69,10 +69,12 @@ and are generated based on the last package release.
+
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 67ad201ccdf6..6f37175f3417 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -9,37 +9,37 @@
-->
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 9b03633bb18b617088b32260065ee385bf9c4491
+ 796d2f8b516781d64bbdf4c21b0163de9fa56ab8
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 9b03633bb18b617088b32260065ee385bf9c4491
+ 796d2f8b516781d64bbdf4c21b0163de9fa56ab8
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 9b03633bb18b617088b32260065ee385bf9c4491
+ 796d2f8b516781d64bbdf4c21b0163de9fa56ab8
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 9b03633bb18b617088b32260065ee385bf9c4491
+ 796d2f8b516781d64bbdf4c21b0163de9fa56ab8
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 9b03633bb18b617088b32260065ee385bf9c4491
+ 796d2f8b516781d64bbdf4c21b0163de9fa56ab8
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 9b03633bb18b617088b32260065ee385bf9c4491
+ 796d2f8b516781d64bbdf4c21b0163de9fa56ab8
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 9b03633bb18b617088b32260065ee385bf9c4491
+ 796d2f8b516781d64bbdf4c21b0163de9fa56ab8
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 9b03633bb18b617088b32260065ee385bf9c4491
+ 796d2f8b516781d64bbdf4c21b0163de9fa56ab8
https://github.com/dotnet/runtime
@@ -177,9 +177,9 @@
https://github.com/dotnet/runtime
4822e3c3aa77eb82b2fb33c9321f923cf11ddde6
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 70ae3df4a6f3c92fb6b315afc405edd10ff38579
+ 7cca709db2944a09b4db6ca7b20c457ff260fb5a
https://github.com/dotnet/runtime
@@ -233,9 +233,9 @@
https://github.com/dotnet/runtime
4822e3c3aa77eb82b2fb33c9321f923cf11ddde6
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 70ae3df4a6f3c92fb6b315afc405edd10ff38579
+ 7cca709db2944a09b4db6ca7b20c457ff260fb5a
https://github.com/dotnet/runtime
@@ -245,57 +245,57 @@
https://github.com/dotnet/runtime
4822e3c3aa77eb82b2fb33c9321f923cf11ddde6
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 70ae3df4a6f3c92fb6b315afc405edd10ff38579
+ 7cca709db2944a09b4db6ca7b20c457ff260fb5a
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 70ae3df4a6f3c92fb6b315afc405edd10ff38579
+ 7cca709db2944a09b4db6ca7b20c457ff260fb5a
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 70ae3df4a6f3c92fb6b315afc405edd10ff38579
+ 7cca709db2944a09b4db6ca7b20c457ff260fb5a
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 70ae3df4a6f3c92fb6b315afc405edd10ff38579
+ 7cca709db2944a09b4db6ca7b20c457ff260fb5a
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 70ae3df4a6f3c92fb6b315afc405edd10ff38579
+ 7cca709db2944a09b4db6ca7b20c457ff260fb5a
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 70ae3df4a6f3c92fb6b315afc405edd10ff38579
+ 7cca709db2944a09b4db6ca7b20c457ff260fb5a
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- be98e88c760526452df94ef452fff4602fb5bded
+ 7cca709db2944a09b4db6ca7b20c457ff260fb5a
-
+
https://github.com/dotnet/arcade
- 1a6b24397e50146d0fece9cfb9c0b87275691e6f
+ e3cbecc5b0e51374e3d71dbb976004ab9cc90430
-
+
https://github.com/dotnet/arcade
- 1a6b24397e50146d0fece9cfb9c0b87275691e6f
+ e3cbecc5b0e51374e3d71dbb976004ab9cc90430
-
+
https://github.com/dotnet/arcade
- 1a6b24397e50146d0fece9cfb9c0b87275691e6f
+ e3cbecc5b0e51374e3d71dbb976004ab9cc90430
-
+
https://github.com/dotnet/arcade
- 1a6b24397e50146d0fece9cfb9c0b87275691e6f
+ e3cbecc5b0e51374e3d71dbb976004ab9cc90430
diff --git a/eng/Versions.props b/eng/Versions.props
index 2ba62764d9b6..3ee5a0799a42 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -8,7 +8,7 @@
6
0
- 5
+ 6
true
6.0.0
- 6.0.5
- 6.0.5
- 6.0.5
- 6.0.5
- 6.0.5
- 6.0.5-servicing.22213.9
+ 6.0.6
+ 6.0.6
+ 6.0.6
+ 6.0.6
+ 6.0.6
+ 6.0.6-servicing.22267.7
6.0.0
6.0.1
6.0.0
@@ -103,7 +103,7 @@
6.0.0
6.0.0
6.0.0
- 6.0.5-servicing.22213.9
+ 6.0.6-servicing.22267.7
6.0.0
6.0.0
6.0.1
@@ -117,22 +117,22 @@
6.0.0
6.0.0
6.0.0
- 6.0.4
+ 6.0.5
6.0.0
- 6.0.3
+ 6.0.4
- 6.0.5
- 6.0.5
- 6.0.5
- 6.0.5
- 6.0.5
- 6.0.5
- 6.0.5
- 6.0.5
+ 6.0.6
+ 6.0.6
+ 6.0.6
+ 6.0.6
+ 6.0.6
+ 6.0.6
+ 6.0.6
+ 6.0.6
- 6.0.0-beta.22212.5
- 6.0.0-beta.22212.5
+ 6.0.0-beta.22261.7
+ 6.0.0-beta.22261.7
2.1.1
2.2.0
- 3.1.24-servicing-22180-6
+ 3.1.25-servicing-22219-10
$(MicrosoftAspNetCoreAzureAppServicesSiteExtension31Version)
$(MicrosoftAspNetCoreAzureAppServicesSiteExtension31Version)
- 5.0.16-servicing-22167-6
+ 5.0.17-servicing-22215-7
$(MicrosoftAspNetCoreAzureAppServicesSiteExtension50Version)
$(MicrosoftAspNetCoreAzureAppServicesSiteExtension50Version)
diff --git a/eng/helix/content/RunTests/ProcessUtil.cs b/eng/helix/content/RunTests/ProcessUtil.cs
index 416ec05a9087..4437e9b40b34 100644
--- a/eng/helix/content/RunTests/ProcessUtil.cs
+++ b/eng/helix/content/RunTests/ProcessUtil.cs
@@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
@@ -80,7 +81,7 @@ public static async Task RunAsync(
Action? onStart = null,
CancellationToken cancellationToken = default)
{
- Console.WriteLine($"Running '{filename} {arguments}'");
+ PrintMessage($"Running '{filename} {arguments}'");
using var process = new Process()
{
StartInfo =
@@ -153,7 +154,7 @@ public static async Task RunAsync(
process.Exited += (_, e) =>
{
- Console.WriteLine($"'{process.StartInfo.FileName} {process.StartInfo.Arguments}' completed with exit code '{process.ExitCode}'");
+ PrintMessage($"'{process.StartInfo.FileName} {process.StartInfo.Arguments}' completed with exit code '{process.ExitCode}'");
if (throwOnError && process.ExitCode != 0)
{
processLifetimeTask.TrySetException(new InvalidOperationException($"Command {filename} {arguments} returned exit code {process.ExitCode} output: {outputBuilder.ToString()}"));
@@ -208,5 +209,8 @@ public static async Task RunAsync(
return await processLifetimeTask.Task;
}
+
+ public static void PrintMessage(string message) => Console.WriteLine($"{DateTime.UtcNow.ToString("O", CultureInfo.InvariantCulture)} {message}");
+ public static void PrintErrorMessage(string message) => Console.Error.WriteLine($"{DateTime.UtcNow.ToString("O", CultureInfo.InvariantCulture)} {message}");
}
}
diff --git a/eng/helix/content/RunTests/Program.cs b/eng/helix/content/RunTests/Program.cs
index 7247c80c364d..e3cbbfbe3a44 100644
--- a/eng/helix/content/RunTests/Program.cs
+++ b/eng/helix/content/RunTests/Program.cs
@@ -25,7 +25,7 @@ static async Task Main(string[] args)
keepGoing = await runner.InstallPlaywrightAsync();
}
#else
- Console.WriteLine("Playwright install skipped.");
+ ProcessUtil.PrintMessage("Playwright install skipped.");
#endif
runner.DisplayContents();
@@ -34,23 +34,23 @@ static async Task Main(string[] args)
{
if (!await runner.CheckTestDiscoveryAsync())
{
- Console.WriteLine("RunTest stopping due to test discovery failure.");
+ ProcessUtil.PrintMessage("RunTest stopping due to test discovery failure.");
Environment.Exit(1);
return;
}
var exitCode = await runner.RunTestsAsync();
runner.UploadResults();
- Console.WriteLine($"Completed Helix job with exit code '{exitCode}'");
+ ProcessUtil.PrintMessage($"Completed Helix job with exit code '{exitCode}'");
Environment.Exit(exitCode);
}
- Console.WriteLine("Tests were not run due to previous failures. Exit code=1");
+ ProcessUtil.PrintMessage("Tests were not run due to previous failures. Exit code=1");
Environment.Exit(1);
}
catch (Exception e)
{
- Console.WriteLine($"RunTests uncaught exception: {e.ToString()}");
+ ProcessUtil.PrintMessage($"RunTests uncaught exception: {e.ToString()}");
Environment.Exit(1);
}
}
diff --git a/eng/helix/content/RunTests/TestRunner.cs b/eng/helix/content/RunTests/TestRunner.cs
index f08fac5fc260..d951ea512f93 100644
--- a/eng/helix/content/RunTests/TestRunner.cs
+++ b/eng/helix/content/RunTests/TestRunner.cs
@@ -33,36 +33,36 @@ public bool SetupEnvironment()
EnvironmentVariables.Add("PATH", Options.Path);
EnvironmentVariables.Add("helix", Options.HelixQueue);
- Console.WriteLine($"Current Directory: {Options.HELIX_WORKITEM_ROOT}");
+ ProcessUtil.PrintMessage($"Current Directory: {Options.HELIX_WORKITEM_ROOT}");
var helixDir = Options.HELIX_WORKITEM_ROOT;
- Console.WriteLine($"Setting HELIX_DIR: {helixDir}");
+ ProcessUtil.PrintMessage($"Setting HELIX_DIR: {helixDir}");
EnvironmentVariables.Add("HELIX_DIR", helixDir);
EnvironmentVariables.Add("NUGET_FALLBACK_PACKAGES", helixDir);
var nugetRestore = Path.Combine(helixDir, "nugetRestore");
EnvironmentVariables.Add("NUGET_RESTORE", nugetRestore);
var dotnetEFFullPath = Path.Combine(nugetRestore, helixDir, "dotnet-ef.exe");
- Console.WriteLine($"Set DotNetEfFullPath: {dotnetEFFullPath}");
+ ProcessUtil.PrintMessage($"Set DotNetEfFullPath: {dotnetEFFullPath}");
EnvironmentVariables.Add("DotNetEfFullPath", dotnetEFFullPath);
var appRuntimePath = $"{Options.DotnetRoot}/shared/Microsoft.AspNetCore.App/{Options.RuntimeVersion}";
- Console.WriteLine($"Set ASPNET_RUNTIME_PATH: {appRuntimePath}");
+ ProcessUtil.PrintMessage($"Set ASPNET_RUNTIME_PATH: {appRuntimePath}");
EnvironmentVariables.Add("ASPNET_RUNTIME_PATH", appRuntimePath);
var dumpPath = Environment.GetEnvironmentVariable("HELIX_DUMP_FOLDER");
- Console.WriteLine($"Set VSTEST_DUMP_PATH: {dumpPath}");
+ ProcessUtil.PrintMessage($"Set VSTEST_DUMP_PATH: {dumpPath}");
EnvironmentVariables.Add("VSTEST_DUMP_PATH", dumpPath);
#if INSTALLPLAYWRIGHT
// Playwright will download and look for browsers to this directory
var playwrightBrowsers = Environment.GetEnvironmentVariable("PLAYWRIGHT_BROWSERS_PATH");
- Console.WriteLine($"Setting PLAYWRIGHT_BROWSERS_PATH: {playwrightBrowsers}");
+ ProcessUtil.PrintMessage($"Setting PLAYWRIGHT_BROWSERS_PATH: {playwrightBrowsers}");
EnvironmentVariables.Add("PLAYWRIGHT_BROWSERS_PATH", playwrightBrowsers);
var playrightDriver = Environment.GetEnvironmentVariable("PLAYWRIGHT_DRIVER_PATH");
- Console.WriteLine($"Setting PLAYWRIGHT_DRIVER_PATH: {playrightDriver}");
+ ProcessUtil.PrintMessage($"Setting PLAYWRIGHT_DRIVER_PATH: {playrightDriver}");
EnvironmentVariables.Add("PLAYWRIGHT_DRIVER_PATH", playrightDriver);
#else
- Console.WriteLine($"Skipping setting PLAYWRIGHT_BROWSERS_PATH");
+ ProcessUtil.PrintMessage($"Skipping setting PLAYWRIGHT_BROWSERS_PATH");
#endif
- Console.WriteLine($"Creating nuget restore directory: {nugetRestore}");
+ ProcessUtil.PrintMessage($"Creating nuget restore directory: {nugetRestore}");
Directory.CreateDirectory(nugetRestore);
// Rename default.runner.json to xunit.runner.json if there is not a custom one from the project
@@ -80,7 +80,7 @@ public bool SetupEnvironment()
}
catch (Exception e)
{
- Console.WriteLine($"Exception in SetupEnvironment: {e.ToString()}");
+ ProcessUtil.PrintMessage($"Exception in SetupEnvironment: {e.ToString()}");
return false;
}
}
@@ -90,20 +90,20 @@ public void DisplayContents(string path = "./")
try
{
Console.WriteLine();
- Console.WriteLine($"Displaying directory contents for {path}:");
+ ProcessUtil.PrintMessage($"Displaying directory contents for {path}:");
foreach (var file in Directory.EnumerateFiles(path))
{
- Console.WriteLine(Path.GetFileName(file));
+ ProcessUtil.PrintMessage(Path.GetFileName(file));
}
foreach (var file in Directory.EnumerateDirectories(path))
{
- Console.WriteLine(Path.GetFileName(file));
+ ProcessUtil.PrintMessage(Path.GetFileName(file));
}
Console.WriteLine();
}
catch (Exception e)
{
- Console.WriteLine($"Exception in DisplayContents: {e.ToString()}");
+ ProcessUtil.PrintMessage($"Exception in DisplayContents: {e.ToString()}");
}
}
@@ -112,14 +112,14 @@ public async Task InstallPlaywrightAsync()
{
try
{
- Console.WriteLine($"Installing Playwright to Browsers: {Environment.GetEnvironmentVariable("PLAYWRIGHT_BROWSERS_PATH")} Driver: {Environment.GetEnvironmentVariable("PLAYWRIGHT_DRIVER_PATH")}");
+ ProcessUtil.PrintMessage($"Installing Playwright to Browsers: {Environment.GetEnvironmentVariable("PLAYWRIGHT_BROWSERS_PATH")} Driver: {Environment.GetEnvironmentVariable("PLAYWRIGHT_DRIVER_PATH")}");
await Playwright.InstallAsync(Environment.GetEnvironmentVariable("PLAYWRIGHT_BROWSERS_PATH"), Environment.GetEnvironmentVariable("PLAYWRIGHT_DRIVER_PATH"));
DisplayContents(Environment.GetEnvironmentVariable("PLAYWRIGHT_BROWSERS_PATH"));
return true;
}
catch (Exception e)
{
- Console.WriteLine($"Exception installing playwright: {e.ToString()}");
+ ProcessUtil.PrintMessage($"Exception installing playwright: {e.ToString()}");
return false;
}
}
@@ -133,18 +133,18 @@ public async Task InstallDotnetToolsAsync()
await ProcessUtil.RunAsync($"{Options.DotnetRoot}/dotnet",
$"tool install dotnet-dump --tool-path {Options.HELIX_WORKITEM_ROOT} --version 5.0.0-*",
environmentVariables: EnvironmentVariables,
- outputDataReceived: Console.WriteLine,
- errorDataReceived: Console.Error.WriteLine,
+ outputDataReceived: ProcessUtil.PrintMessage,
+ errorDataReceived: ProcessUtil.PrintErrorMessage,
throwOnError: false,
cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(2)).Token);
- Console.WriteLine($"Adding current directory to nuget sources: {Options.HELIX_WORKITEM_ROOT}");
+ ProcessUtil.PrintMessage($"Adding current directory to nuget sources: {Options.HELIX_WORKITEM_ROOT}");
await ProcessUtil.RunAsync($"{Options.DotnetRoot}/dotnet",
$"nuget add source {Options.HELIX_WORKITEM_ROOT} --configfile NuGet.config",
environmentVariables: EnvironmentVariables,
- outputDataReceived: Console.WriteLine,
- errorDataReceived: Console.Error.WriteLine,
+ outputDataReceived: ProcessUtil.PrintMessage,
+ errorDataReceived: ProcessUtil.PrintErrorMessage,
throwOnError: false,
cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(2)).Token);
@@ -152,24 +152,24 @@ await ProcessUtil.RunAsync($"{Options.DotnetRoot}/dotnet",
await ProcessUtil.RunAsync($"{Options.DotnetRoot}/dotnet",
"nuget list source",
environmentVariables: EnvironmentVariables,
- outputDataReceived: Console.WriteLine,
- errorDataReceived: Console.Error.WriteLine,
+ outputDataReceived: ProcessUtil.PrintMessage,
+ errorDataReceived: ProcessUtil.PrintErrorMessage,
throwOnError: false,
cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(2)).Token);
await ProcessUtil.RunAsync($"{Options.DotnetRoot}/dotnet",
$"tool install dotnet-ef --version {Options.EfVersion} --tool-path {Options.HELIX_WORKITEM_ROOT}",
environmentVariables: EnvironmentVariables,
- outputDataReceived: Console.WriteLine,
- errorDataReceived: Console.Error.WriteLine,
+ outputDataReceived: ProcessUtil.PrintMessage,
+ errorDataReceived: ProcessUtil.PrintErrorMessage,
throwOnError: false,
cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(2)).Token);
await ProcessUtil.RunAsync($"{Options.DotnetRoot}/dotnet",
$"tool install dotnet-serve --tool-path {Options.HELIX_WORKITEM_ROOT}",
environmentVariables: EnvironmentVariables,
- outputDataReceived: Console.WriteLine,
- errorDataReceived: Console.Error.WriteLine,
+ outputDataReceived: ProcessUtil.PrintMessage,
+ errorDataReceived: ProcessUtil.PrintErrorMessage,
throwOnError: false,
cancellationToken: new CancellationTokenSource(TimeSpan.FromMinutes(2)).Token);
@@ -177,7 +177,7 @@ await ProcessUtil.RunAsync($"{Options.DotnetRoot}/dotnet",
}
catch (Exception e)
{
- Console.WriteLine($"Exception in InstallDotnetTools: {e}");
+ ProcessUtil.PrintMessage($"Exception in InstallDotnetTools: {e}");
return false;
}
}
@@ -194,15 +194,15 @@ public async Task CheckTestDiscoveryAsync()
if (discoveryResult.StandardOutput.Contains("Exception thrown"))
{
- Console.WriteLine("Exception thrown during test discovery.");
- Console.WriteLine(discoveryResult.StandardOutput);
+ ProcessUtil.PrintMessage("Exception thrown during test discovery.");
+ ProcessUtil.PrintMessage(discoveryResult.StandardOutput);
return false;
}
return true;
}
catch (Exception e)
{
- Console.WriteLine($"Exception in CheckTestDiscovery: {e.ToString()}");
+ ProcessUtil.PrintMessage($"Exception in CheckTestDiscovery: {e.ToString()}");
return false;
}
}
@@ -213,50 +213,60 @@ public async Task RunTestsAsync()
try
{
// Timeout test run 5 minutes before the Helix job would timeout
- var cts = new CancellationTokenSource(Options.Timeout.Subtract(TimeSpan.FromMinutes(5)));
+ var testProcessTimeout = Options.Timeout.Subtract(TimeSpan.FromMinutes(5));
+ var cts = new CancellationTokenSource(testProcessTimeout);
var diagLog = Path.Combine(Environment.GetEnvironmentVariable("HELIX_WORKITEM_UPLOAD_ROOT"), "vstest.log");
- var commonTestArgs = $"test {Options.Target} --diag:{diagLog} --logger:xunit --logger:\"console;verbosity=normal\" --blame \"CollectHangDump;TestTimeout=15m\"";
+ var commonTestArgs = $"test {Options.Target} --diag:{diagLog} --logger xunit --logger \"console;verbosity=normal\" " +
+ "--blame-crash --blame-hang-timeout 15m";
if (Options.Quarantined)
{
- Console.WriteLine("Running quarantined tests.");
+ ProcessUtil.PrintMessage("Running quarantined tests.");
// Filter syntax: https://github.com/Microsoft/vstest-docs/blob/master/docs/filter.md
var result = await ProcessUtil.RunAsync($"{Options.DotnetRoot}/dotnet",
commonTestArgs + " --TestCaseFilter:\"Quarantined=true\"",
environmentVariables: EnvironmentVariables,
- outputDataReceived: Console.WriteLine,
- errorDataReceived: Console.Error.WriteLine,
+ outputDataReceived: ProcessUtil.PrintMessage,
+ errorDataReceived: ProcessUtil.PrintErrorMessage,
throwOnError: false,
cancellationToken: cts.Token);
+ if (cts.Token.IsCancellationRequested)
+ {
+ ProcessUtil.PrintMessage($"Quarantined tests exceeded configured timeout: {testProcessTimeout.TotalMinutes}m.");
+ }
if (result.ExitCode != 0)
{
- Console.WriteLine($"Failure in quarantined tests. Exit code: {result.ExitCode}.");
+ ProcessUtil.PrintMessage($"Failure in quarantined tests. Exit code: {result.ExitCode}.");
}
}
else
{
- Console.WriteLine("Running non-quarantined tests.");
+ ProcessUtil.PrintMessage("Running non-quarantined tests.");
// Filter syntax: https://github.com/Microsoft/vstest-docs/blob/master/docs/filter.md
var result = await ProcessUtil.RunAsync($"{Options.DotnetRoot}/dotnet",
commonTestArgs + " --TestCaseFilter:\"Quarantined!=true|Quarantined=false\"",
environmentVariables: EnvironmentVariables,
- outputDataReceived: Console.WriteLine,
- errorDataReceived: Console.Error.WriteLine,
+ outputDataReceived: ProcessUtil.PrintMessage,
+ errorDataReceived: ProcessUtil.PrintErrorMessage,
throwOnError: false,
cancellationToken: cts.Token);
+ if (cts.Token.IsCancellationRequested)
+ {
+ ProcessUtil.PrintMessage($"Non-quarantined tests exceeded configured timeout: {testProcessTimeout.TotalMinutes}m.");
+ }
if (result.ExitCode != 0)
{
- Console.WriteLine($"Failure in non-quarantined tests. Exit code: {result.ExitCode}.");
+ ProcessUtil.PrintMessage($"Failure in non-quarantined tests. Exit code: {result.ExitCode}.");
exitCode = result.ExitCode;
}
}
}
catch (Exception e)
{
- Console.WriteLine($"Exception in RunTests: {e.ToString()}");
+ ProcessUtil.PrintMessage($"Exception in RunTests: {e.ToString()}");
exitCode = 1;
}
return exitCode;
@@ -265,51 +275,51 @@ public async Task RunTestsAsync()
public void UploadResults()
{
// 'testResults.xml' is the file Helix looks for when processing test results
- Console.WriteLine("Trying to upload results...");
+ ProcessUtil.PrintMessage("Trying to upload results...");
if (File.Exists("TestResults/TestResults.xml"))
{
- Console.WriteLine("Copying TestResults/TestResults.xml to ./testResults.xml");
+ ProcessUtil.PrintMessage("Copying TestResults/TestResults.xml to ./testResults.xml");
File.Copy("TestResults/TestResults.xml", "testResults.xml");
}
else
{
- Console.WriteLine("No test results found.");
+ ProcessUtil.PrintMessage("No test results found.");
}
var HELIX_WORKITEM_UPLOAD_ROOT = Environment.GetEnvironmentVariable("HELIX_WORKITEM_UPLOAD_ROOT");
if (string.IsNullOrEmpty(HELIX_WORKITEM_UPLOAD_ROOT))
{
- Console.WriteLine("No HELIX_WORKITEM_UPLOAD_ROOT specified, skipping log copy");
+ ProcessUtil.PrintMessage("No HELIX_WORKITEM_UPLOAD_ROOT specified, skipping log copy");
return;
}
- Console.WriteLine($"Copying artifacts/log/ to {HELIX_WORKITEM_UPLOAD_ROOT}/");
+ ProcessUtil.PrintMessage($"Copying artifacts/log/ to {HELIX_WORKITEM_UPLOAD_ROOT}/");
if (Directory.Exists("artifacts/log"))
{
foreach (var file in Directory.EnumerateFiles("artifacts/log", "*.log", SearchOption.AllDirectories))
{
// Combine the directory name + log name for the copied log file name to avoid overwriting duplicate test names in different test projects
var logName = $"{Path.GetFileName(Path.GetDirectoryName(file))}_{Path.GetFileName(file)}";
- Console.WriteLine($"Copying: {file} to {Path.Combine(HELIX_WORKITEM_UPLOAD_ROOT, logName)}");
+ ProcessUtil.PrintMessage($"Copying: {file} to {Path.Combine(HELIX_WORKITEM_UPLOAD_ROOT, logName)}");
File.Copy(file, Path.Combine(HELIX_WORKITEM_UPLOAD_ROOT, logName));
}
}
else
{
- Console.WriteLine("No logs found in artifacts/log");
+ ProcessUtil.PrintMessage("No logs found in artifacts/log");
}
- Console.WriteLine($"Copying TestResults/**/Sequence*.xml to {HELIX_WORKITEM_UPLOAD_ROOT}/");
+ ProcessUtil.PrintMessage($"Copying TestResults/**/Sequence*.xml to {HELIX_WORKITEM_UPLOAD_ROOT}/");
if (Directory.Exists("TestResults"))
{
foreach (var file in Directory.EnumerateFiles("TestResults", "Sequence*.xml", SearchOption.AllDirectories))
{
var fileName = Path.GetFileName(file);
- Console.WriteLine($"Copying: {file} to {Path.Combine(HELIX_WORKITEM_UPLOAD_ROOT, fileName)}");
+ ProcessUtil.PrintMessage($"Copying: {file} to {Path.Combine(HELIX_WORKITEM_UPLOAD_ROOT, fileName)}");
File.Copy(file, Path.Combine(HELIX_WORKITEM_UPLOAD_ROOT, fileName));
}
}
else
{
- Console.WriteLine("No TestResults directory found.");
+ ProcessUtil.PrintMessage("No TestResults directory found.");
}
}
}
diff --git a/eng/targets/Helix.props b/eng/targets/Helix.props
index dc2bad9552b9..3554c48dd037 100644
--- a/eng/targets/Helix.props
+++ b/eng/targets/Helix.props
@@ -11,8 +11,7 @@
true
- 00:30:00
- 00:40:00
+ 00:45:00
false
$(MSBuildProjectName)--$(TargetFramework)
false
diff --git a/global.json b/global.json
index 30a17d2cce7a..538e11d2fced 100644
--- a/global.json
+++ b/global.json
@@ -1,9 +1,9 @@
{
"sdk": {
- "version": "6.0.104"
+ "version": "6.0.105"
},
"tools": {
- "dotnet": "6.0.104",
+ "dotnet": "6.0.105",
"runtimes": {
"dotnet/x64": [
"2.1.30",
@@ -13,7 +13,7 @@
"$(MicrosoftNETCoreBrowserDebugHostTransportVersion)"
],
"aspnetcore/x64": [
- "3.1.24"
+ "3.1.25"
]
},
"Git": "2.22.0",
@@ -29,7 +29,7 @@
},
"msbuild-sdks": {
"Yarn.MSBuild": "1.22.10",
- "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.22212.5",
- "Microsoft.DotNet.Helix.Sdk": "6.0.0-beta.22212.5"
+ "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.22261.7",
+ "Microsoft.DotNet.Helix.Sdk": "6.0.0-beta.22261.7"
}
}
diff --git a/src/Components/Web.JS/yarn.lock b/src/Components/Web.JS/yarn.lock
index f67cf3464f37..36dc8fce6c96 100644
--- a/src/Components/Web.JS/yarn.lock
+++ b/src/Components/Web.JS/yarn.lock
@@ -3738,9 +3738,9 @@ minimatch@^3.0.4:
brace-expansion "^1.1.7"
minimist@^1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
- integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
+ integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
ms@2.1.2:
version "2.1.2"
diff --git a/src/Components/WebAssembly/Authentication.Msal/src/Interop/yarn.lock b/src/Components/WebAssembly/Authentication.Msal/src/Interop/yarn.lock
index 51b9f4e1bfde..0a5574d5d439 100644
--- a/src/Components/WebAssembly/Authentication.Msal/src/Interop/yarn.lock
+++ b/src/Components/WebAssembly/Authentication.Msal/src/Interop/yarn.lock
@@ -2169,9 +2169,9 @@ minimatch@^3.0.4:
brace-expansion "^1.1.7"
minimist@^1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
- integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
+ integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
ms@2.1.2:
version "2.1.2"
diff --git a/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/yarn.lock b/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/yarn.lock
index 6c69bb84ab52..a11ccca0b617 100644
--- a/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/yarn.lock
+++ b/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/yarn.lock
@@ -2170,9 +2170,9 @@ minimatch@^3.0.4:
brace-expansion "^1.1.7"
minimist@^1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
- integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
+ integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
ms@2.1.2:
version "2.1.2"
diff --git a/src/Components/test/E2ETest/yarn.lock b/src/Components/test/E2ETest/yarn.lock
index 55b89cd5cc35..cd5a69ac5f3a 100644
--- a/src/Components/test/E2ETest/yarn.lock
+++ b/src/Components/test/E2ETest/yarn.lock
@@ -71,9 +71,9 @@ arg@^4.1.0:
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
async@^2.1.2:
- version "2.6.3"
- resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
- integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
+ version "2.6.4"
+ resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221"
+ integrity "sha1-cGt/9ghGZM1+rnE/b5ZUM7VQQiE= sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA=="
dependencies:
lodash "^4.17.14"
@@ -363,9 +363,9 @@ minimatch@^3.0.4:
brace-expansion "^1.1.7"
minimist@^1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
- integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
+ integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
mkdirp@^1.0.4:
version "1.0.4"
diff --git a/src/Components/test/testassets/BasicTestApp/BasicTestApp.csproj b/src/Components/test/testassets/BasicTestApp/BasicTestApp.csproj
index 476107e41440..f81ddcae75ca 100644
--- a/src/Components/test/testassets/BasicTestApp/BasicTestApp.csproj
+++ b/src/Components/test/testassets/BasicTestApp/BasicTestApp.csproj
@@ -26,6 +26,7 @@
+
diff --git a/src/DefaultBuilder/src/ConfigureHostBuilder.cs b/src/DefaultBuilder/src/ConfigureHostBuilder.cs
index fdf8b2d0bc00..87e24d848894 100644
--- a/src/DefaultBuilder/src/ConfigureHostBuilder.cs
+++ b/src/DefaultBuilder/src/ConfigureHostBuilder.cs
@@ -62,6 +62,7 @@ public IHostBuilder ConfigureHostConfiguration(Action con
var previousApplicationName = _configuration[HostDefaults.ApplicationKey];
// Use the real content root so we can compare paths
var previousContentRoot = _context.HostingEnvironment.ContentRootPath;
+ var previousContentRootConfig = _configuration[HostDefaults.ContentRootKey];
var previousEnvironment = _configuration[HostDefaults.EnvironmentKey];
// Run these immediately so that they are observable by the imperative code
@@ -74,7 +75,8 @@ public IHostBuilder ConfigureHostConfiguration(Action con
throw new NotSupportedException($"The application name changed from \"{previousApplicationName}\" to \"{_configuration[HostDefaults.ApplicationKey]}\". Changing the host configuration using WebApplicationBuilder.Host is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.");
}
- if (!string.Equals(previousContentRoot, HostingPathResolver.ResolvePath(_configuration[HostDefaults.ContentRootKey]), StringComparison.OrdinalIgnoreCase))
+ if (!string.Equals(previousContentRootConfig, _configuration[HostDefaults.ContentRootKey], StringComparison.OrdinalIgnoreCase)
+ && !string.Equals(previousContentRoot, HostingPathResolver.ResolvePath(_configuration[HostDefaults.ContentRootKey]), StringComparison.OrdinalIgnoreCase))
{
throw new NotSupportedException($"The content root changed from \"{previousContentRoot}\" to \"{HostingPathResolver.ResolvePath(_configuration[HostDefaults.ContentRootKey])}\". Changing the host configuration using WebApplicationBuilder.Host is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.");
}
diff --git a/src/DefaultBuilder/src/ConfigureWebHostBuilder.cs b/src/DefaultBuilder/src/ConfigureWebHostBuilder.cs
index 0a2c482f53f0..d0ed6a822ab1 100644
--- a/src/DefaultBuilder/src/ConfigureWebHostBuilder.cs
+++ b/src/DefaultBuilder/src/ConfigureWebHostBuilder.cs
@@ -39,7 +39,9 @@ IWebHost IWebHostBuilder.Build()
public IWebHostBuilder ConfigureAppConfiguration(Action configureDelegate)
{
var previousContentRoot = _context.HostingEnvironment.ContentRootPath;
+ var previousContentRootConfig = _configuration[WebHostDefaults.ContentRootKey];
var previousWebRoot = _context.HostingEnvironment.WebRootPath;
+ var previousWebRootConfig = _configuration[WebHostDefaults.WebRootKey];
var previousApplication = _configuration[WebHostDefaults.ApplicationKey];
var previousEnvironment = _configuration[WebHostDefaults.EnvironmentKey];
var previousHostingStartupAssemblies = _configuration[WebHostDefaults.HostingStartupAssembliesKey];
@@ -48,7 +50,8 @@ public IWebHostBuilder ConfigureAppConfiguration(Action { });
+
+ using var app = builder.Build();
+ var hostEnv = app.Services.GetRequiredService();
+ Assert.Equal(wwwroot, hostEnv.WebRootPath);
+ }
+ finally
+ {
+ if (createdDirectory)
+ {
+ Directory.Delete(wwwroot);
+ }
+ }
+ }
+
[Fact]
public void HostConfigurationNotAffectedByConfiguration()
{
diff --git a/src/Hosting/Hosting/src/Internal/WebHost.cs b/src/Hosting/Hosting/src/Internal/WebHost.cs
index ca52bd1f400b..bf9e339ddb51 100644
--- a/src/Hosting/Hosting/src/Internal/WebHost.cs
+++ b/src/Hosting/Hosting/src/Internal/WebHost.cs
@@ -81,12 +81,12 @@ public WebHost(
// There's no way to to register multiple service types per definition. See https://github.com/aspnet/DependencyInjection/issues/360
#pragma warning disable CS8634 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'class' constraint.
_applicationServiceCollection.AddSingleton(services
- => services.GetService() as IHostApplicationLifetime);
+ => services.GetService()! as IHostApplicationLifetime);
#pragma warning disable CS0618 // Type or member is obsolete
_applicationServiceCollection.AddSingleton(services
- => services.GetService() as AspNetCore.Hosting.IApplicationLifetime);
+ => services.GetService()! as AspNetCore.Hosting.IApplicationLifetime);
_applicationServiceCollection.AddSingleton(services
- => services.GetService() as Extensions.Hosting.IApplicationLifetime);
+ => services.GetService()! as Extensions.Hosting.IApplicationLifetime);
#pragma warning restore CS0618 // Type or member is obsolete
#pragma warning restore CS8634 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'class' constraint.
_applicationServiceCollection.AddSingleton();
diff --git a/src/Http/Http.Abstractions/src/Extensions/MapMiddleware.cs b/src/Http/Http.Abstractions/src/Extensions/MapMiddleware.cs
index 35b25f40e62b..3122b7640909 100644
--- a/src/Http/Http.Abstractions/src/Extensions/MapMiddleware.cs
+++ b/src/Http/Http.Abstractions/src/Extensions/MapMiddleware.cs
@@ -64,7 +64,7 @@ public Task Invoke(HttpContext context)
return _next(context);
}
- private async Task InvokeCore(HttpContext context, string matchedPath, string remainingPath)
+ private async Task InvokeCore(HttpContext context, PathString matchedPath, PathString remainingPath)
{
var path = context.Request.Path;
var pathBase = context.Request.PathBase;
diff --git a/src/Http/Http.Abstractions/src/Extensions/UsePathBaseExtensions.cs b/src/Http/Http.Abstractions/src/Extensions/UsePathBaseExtensions.cs
index 0bdf4fcfed97..46280bb4f221 100644
--- a/src/Http/Http.Abstractions/src/Extensions/UsePathBaseExtensions.cs
+++ b/src/Http/Http.Abstractions/src/Extensions/UsePathBaseExtensions.cs
@@ -1,4 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
@@ -26,7 +26,7 @@ public static IApplicationBuilder UsePathBase(this IApplicationBuilder app, Path
}
// Strip trailing slashes
- pathBase = pathBase.Value?.TrimEnd('/');
+ pathBase = new PathString(pathBase.Value?.TrimEnd('/'));
if (!pathBase.HasValue)
{
return app;
@@ -35,4 +35,4 @@ public static IApplicationBuilder UsePathBase(this IApplicationBuilder app, Path
return app.UseMiddleware(pathBase);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Http/Http.Abstractions/src/Extensions/UsePathBaseMiddleware.cs b/src/Http/Http.Abstractions/src/Extensions/UsePathBaseMiddleware.cs
index 34ffc5738d40..ef7b9d586cfd 100644
--- a/src/Http/Http.Abstractions/src/Extensions/UsePathBaseMiddleware.cs
+++ b/src/Http/Http.Abstractions/src/Extensions/UsePathBaseMiddleware.cs
@@ -55,7 +55,7 @@ public Task Invoke(HttpContext context)
return _next(context);
}
- private async Task InvokeCore(HttpContext context, string matchedPath, string remainingPath)
+ private async Task InvokeCore(HttpContext context, PathString matchedPath, PathString remainingPath)
{
var originalPath = context.Request.Path;
var originalPathBase = context.Request.PathBase;
diff --git a/src/Http/Http.Abstractions/test/MapPathMiddlewareTests.cs b/src/Http/Http.Abstractions/test/MapPathMiddlewareTests.cs
index 48c718a47c16..acaa0e0bce6d 100644
--- a/src/Http/Http.Abstractions/test/MapPathMiddlewareTests.cs
+++ b/src/Http/Http.Abstractions/test/MapPathMiddlewareTests.cs
@@ -43,24 +43,27 @@ public void NullArguments_ArgumentNullException()
}
[Theory]
- [InlineData("/foo", "", "/foo")]
- [InlineData("/foo", "", "/foo/")]
- [InlineData("/foo", "/Bar", "/foo")]
- [InlineData("/foo", "/Bar", "/foo/cho")]
- [InlineData("/foo", "/Bar", "/foo/cho/")]
- [InlineData("/foo/cho", "/Bar", "/foo/cho")]
- [InlineData("/foo/cho", "/Bar", "/foo/cho/do")]
- public async Task PathMatchFunc_BranchTaken(string matchPath, string basePath, string requestPath)
+ [InlineData("/foo", "", "/foo", "/foo", "")]
+ [InlineData("/foo", "", "/foo/", "/foo", "/")]
+ [InlineData("/foo", "/Bar", "/foo", "/Bar/foo", "")]
+ [InlineData("/foo", "/Bar", "/foo/cho", "/Bar/foo", "/cho")]
+ [InlineData("/foo", "/Bar", "/foo/cho/", "/Bar/foo", "/cho/")]
+ [InlineData("/foo/cho", "/Bar", "/foo/cho", "/Bar/foo/cho", "")]
+ [InlineData("/foo/cho", "/Bar", "/foo/cho/do", "/Bar/foo/cho", "/do")]
+ [InlineData("/foo%42/cho", "/Bar%42", "/foo%42/cho/do%42", "/Bar%42/foo%42/cho", "/do%42")]
+ public async Task PathMatchFunc_BranchTaken(string matchPath, string basePath, string requestPath, string expectedPathBase, string expectedPath)
{
HttpContext context = CreateRequest(basePath, requestPath);
var builder = new ApplicationBuilder(serviceProvider: null!);
- builder.Map(matchPath, UseSuccess);
+ builder.Map(new PathString(matchPath), UseSuccess);
var app = builder.Build();
await app.Invoke(context);
Assert.Equal(200, context.Response.StatusCode);
Assert.Equal(basePath, context.Request.PathBase.Value);
Assert.Equal(requestPath, context.Request.Path.Value);
+ Assert.Equal(expectedPathBase, (string)context.Items["test.PathBase"]!);
+ Assert.Equal(expectedPath, context.Items["test.Path"]);
}
[Theory]
diff --git a/src/Http/Http.Abstractions/test/UsePathBaseExtensionsTests.cs b/src/Http/Http.Abstractions/test/UsePathBaseExtensionsTests.cs
index a5511ef0c18b..ebb695ed0656 100644
--- a/src/Http/Http.Abstractions/test/UsePathBaseExtensionsTests.cs
+++ b/src/Http/Http.Abstractions/test/UsePathBaseExtensionsTests.cs
@@ -131,11 +131,23 @@ public Task PathBaseCanHaveUnicodeCharacters(string registeredPathBase, string p
return TestPathBase(registeredPathBase, pathBase, requestPath, expectedPathBase, expectedPath);
}
+ [Theory]
+ [InlineData("/b%42", "", "/b%42/something%42", "/b%42", "/something%42")]
+ [InlineData("/b%42", "", "/B%42/something%42", "/B%42", "/something%42")]
+ [InlineData("/b%42", "", "/b%42/Something%42", "/b%42", "/Something%42")]
+ [InlineData("/b%42", "/oldb%42", "/b%42/something%42", "/oldb%42/b%42", "/something%42")]
+ [InlineData("/b%42", "/oldb%42", "/b%42/Something%42", "/oldb%42/b%42", "/Something%42")]
+ [InlineData("/b%42", "/oldb%42", "/B%42/something%42", "/oldb%42/B%42", "/something%42")]
+ public Task PathBaseCanHavePercentCharacters(string registeredPathBase, string pathBase, string requestPath, string expectedPathBase, string expectedPath)
+ {
+ return TestPathBase(registeredPathBase, pathBase, requestPath, expectedPathBase, expectedPath);
+ }
+
private static async Task TestPathBase(string registeredPathBase, string pathBase, string requestPath, string expectedPathBase, string expectedPath)
{
HttpContext requestContext = CreateRequest(pathBase, requestPath);
var builder = CreateBuilder()
- .UsePathBase(registeredPathBase);
+ .UsePathBase(new PathString(registeredPathBase));
builder.Run(context =>
{
context.Items["test.Path"] = context.Request.Path;
diff --git a/src/Http/WebUtilities/src/FileBufferingReadStream.cs b/src/Http/WebUtilities/src/FileBufferingReadStream.cs
index 720b8921b553..f66916c8ebff 100644
--- a/src/Http/WebUtilities/src/FileBufferingReadStream.cs
+++ b/src/Http/WebUtilities/src/FileBufferingReadStream.cs
@@ -317,7 +317,8 @@ public override int Read(Span buffer)
{
_buffer.Write(buffer.Slice(0, read));
}
- else
+ // Allow zero-byte reads
+ else if (buffer.Length > 0)
{
_completelyBuffered = true;
}
@@ -392,7 +393,8 @@ public override async ValueTask ReadAsync(Memory buffer, Cancellation
{
await _buffer.WriteAsync(buffer.Slice(0, read), cancellationToken);
}
- else
+ // Allow zero-byte reads
+ else if (buffer.Length > 0)
{
_completelyBuffered = true;
}
diff --git a/src/Http/WebUtilities/test/FileBufferingReadStreamTests.cs b/src/Http/WebUtilities/test/FileBufferingReadStreamTests.cs
index 7d6c42229239..640562b6c6a0 100644
--- a/src/Http/WebUtilities/test/FileBufferingReadStreamTests.cs
+++ b/src/Http/WebUtilities/test/FileBufferingReadStreamTests.cs
@@ -35,6 +35,39 @@ public void FileBufferingReadStream_Properties_ExpectedValues()
}
}
+ [Fact]
+ public void FileBufferingReadStream_Sync0ByteReadUnderThreshold_DoesntCreateFile()
+ {
+ var inner = MakeStream(1024);
+ using (var stream = new FileBufferingReadStream(inner, 1024 * 2, null, Directory.GetCurrentDirectory()))
+ {
+ var bytes = new byte[1000];
+ var read0 = stream.Read(bytes, 0, 0);
+ Assert.Equal(0, read0);
+ Assert.Equal(read0, stream.Length);
+ Assert.Equal(read0, stream.Position);
+ Assert.True(stream.InMemory);
+ Assert.Null(stream.TempFileName);
+
+ var read1 = stream.Read(bytes, 0, bytes.Length);
+ Assert.Equal(bytes.Length, read1);
+ Assert.Equal(read0 + read1, stream.Length);
+ Assert.Equal(read0 + read1, stream.Position);
+ Assert.True(stream.InMemory);
+ Assert.Null(stream.TempFileName);
+
+ var read2 = stream.Read(bytes, 0, bytes.Length);
+ Assert.Equal(inner.Length - read0 - read1, read2);
+ Assert.Equal(read0 + read1 + read2, stream.Length);
+ Assert.Equal(read0 + read1 + read2, stream.Position);
+ Assert.True(stream.InMemory);
+ Assert.Null(stream.TempFileName);
+
+ var read3 = stream.Read(bytes, 0, bytes.Length);
+ Assert.Equal(0, read3);
+ }
+ }
+
[Fact]
public void FileBufferingReadStream_SyncReadUnderThreshold_DoesntCreateFile()
{
@@ -164,6 +197,39 @@ public void FileBufferingReadStream_SyncReadWithOnDiskLimit_EnforcesLimit()
///////////////////
+ [Fact]
+ public async Task FileBufferingReadStream_Async0ByteReadUnderThreshold_DoesntCreateFile()
+ {
+ var inner = MakeStream(1024);
+ using (var stream = new FileBufferingReadStream(inner, 1024 * 2, null, Directory.GetCurrentDirectory()))
+ {
+ var bytes = new byte[1000];
+ var read0 = await stream.ReadAsync(bytes, 0, 0);
+ Assert.Equal(0, read0);
+ Assert.Equal(read0, stream.Length);
+ Assert.Equal(read0, stream.Position);
+ Assert.True(stream.InMemory);
+ Assert.Null(stream.TempFileName);
+
+ var read1 = await stream.ReadAsync(bytes, 0, bytes.Length);
+ Assert.Equal(bytes.Length, read1);
+ Assert.Equal(read0 + read1, stream.Length);
+ Assert.Equal(read0 + read1, stream.Position);
+ Assert.True(stream.InMemory);
+ Assert.Null(stream.TempFileName);
+
+ var read2 = await stream.ReadAsync(bytes, 0, bytes.Length);
+ Assert.Equal(inner.Length - read0 - read1, read2);
+ Assert.Equal(read0 + read1 + read2, stream.Length);
+ Assert.Equal(read0 + read1 + read2, stream.Position);
+ Assert.True(stream.InMemory);
+ Assert.Null(stream.TempFileName);
+
+ var read3 = await stream.ReadAsync(bytes, 0, bytes.Length);
+ Assert.Equal(0, read3);
+ }
+ }
+
[Fact]
public async Task FileBufferingReadStream_AsyncReadUnderThreshold_DoesntCreateFile()
{
@@ -236,6 +302,47 @@ public async Task FileBufferingReadStream_AsyncReadOverThreshold_CreatesFile()
Assert.False(File.Exists(tempFileName));
}
+ [Fact]
+ public async Task FileBufferingReadStream_Async0ByteReadAfterBuffering_ReadsFromFile()
+ {
+ var inner = MakeStream(1024 * 2);
+ string tempFileName;
+ using (var stream = new FileBufferingReadStream(inner, 1024, null, GetCurrentDirectory()))
+ {
+ await stream.DrainAsync(default);
+ stream.Position = 0;
+ Assert.Equal(inner.Length, stream.Length);
+ Assert.Equal(0, stream.Position);
+ Assert.False(stream.InMemory);
+ Assert.NotNull(stream.TempFileName);
+ tempFileName = stream.TempFileName!;
+ Assert.True(File.Exists(tempFileName));
+
+ var bytes = new byte[1000];
+ var read0 = await stream.ReadAsync(bytes, 0, 0);
+ Assert.Equal(0, read0);
+ Assert.Equal(read0, stream.Position);
+
+ var read1 = await stream.ReadAsync(bytes, 0, bytes.Length);
+ Assert.Equal(bytes.Length, read1);
+ Assert.Equal(read0 + read1, stream.Position);
+
+ var read2 = await stream.ReadAsync(bytes, 0, bytes.Length);
+ Assert.Equal(bytes.Length, read2);
+ Assert.Equal(read0 + read1 + read2, stream.Position);
+
+ var read3 = await stream.ReadAsync(bytes, 0, bytes.Length);
+ Assert.Equal(inner.Length - read0 - read1 - read2, read3);
+ Assert.Equal(read0 + read1 + read2 + read3, stream.Length);
+ Assert.Equal(read0 + read1 + read2 + read3, stream.Position);
+
+ var read4 = await stream.ReadAsync(bytes, 0, bytes.Length);
+ Assert.Equal(0, read4);
+ }
+
+ Assert.False(File.Exists(tempFileName));
+ }
+
[Fact]
public async Task FileBufferingReadStream_AsyncReadWithInMemoryLimit_EnforcesLimit()
{
diff --git a/src/JSInterop/Microsoft.JSInterop.JS/src/yarn.lock b/src/JSInterop/Microsoft.JSInterop.JS/src/yarn.lock
index b438080d556a..886066a3154c 100644
--- a/src/JSInterop/Microsoft.JSInterop.JS/src/yarn.lock
+++ b/src/JSInterop/Microsoft.JSInterop.JS/src/yarn.lock
@@ -176,9 +176,9 @@ minimatch@^3.0.4:
brace-expansion "^1.1.7"
minimist@^1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
- integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
+ integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
mkdirp@^0.5.3:
version "0.5.5"
@@ -200,9 +200,9 @@ path-is-absolute@^1.0.0:
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
path-parse@^1.0.6:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
- integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
resolve@^1.3.2:
version "1.20.0"
diff --git a/src/Middleware/HttpLogging/src/FileLoggerProcessor.cs b/src/Middleware/HttpLogging/src/FileLoggerProcessor.cs
index 9f0e4f5821ba..60b4a6265867 100644
--- a/src/Middleware/HttpLogging/src/FileLoggerProcessor.cs
+++ b/src/Middleware/HttpLogging/src/FileLoggerProcessor.cs
@@ -156,23 +156,28 @@ private async Task WriteMessagesAsync(List messages, CancellationToken c
{
// Files are written up to _maxFileSize before rolling to a new file
DateTime today = DateTime.Now;
+
+ if (!TryCreateDirectory())
+ {
+ // return early if we fail to create the directory
+ return;
+ }
+
var fullName = GetFullName(today);
// Don't write to an incomplete file left around by a previous FileLoggerProcessor
if (_firstFile)
{
- while (File.Exists(fullName))
+ _fileNumber = GetFirstFileCount(today);
+ fullName = GetFullName(today);
+ if (_fileNumber >= W3CLoggerOptions.MaxFileCount)
{
- _fileNumber++;
- if (_fileNumber >= W3CLoggerOptions.MaxFileCount)
- {
- _maxFilesReached = true;
- // Return early if log directory is already full
- Log.MaxFilesReached(_logger);
- return;
- }
- fullName = GetFullName(today);
+ _maxFilesReached = true;
+ // Return early if log directory is already full
+ Log.MaxFilesReached(_logger);
+ return;
}
}
+
_firstFile = false;
if (_maxFilesReached)
{
@@ -300,6 +305,23 @@ public async ValueTask DisposeAsync()
await _outputTask;
}
+ private int GetFirstFileCount(DateTime date)
+ {
+ lock (_pathLock)
+ {
+ var searchString = FormattableString.Invariant($"{_fileName}{date.Year:0000}{date.Month:00}{date.Day:00}.*.txt");
+ var files = new DirectoryInfo(_path)
+ .GetFiles(searchString);
+
+ return files.Length == 0
+ ? 0
+ : files
+ .Max(x => int.TryParse(x.Name.Split('.').ElementAtOrDefault(Index.FromEnd(2)), out var parsed)
+ ? parsed + 1
+ : 0);
+ }
+ }
+
private string GetFullName(DateTime date)
{
lock (_pathLock)
diff --git a/src/Middleware/HttpLogging/src/W3CLoggerProcessor.cs b/src/Middleware/HttpLogging/src/W3CLoggerProcessor.cs
index 749da2b6cfbe..d3a44994a8bb 100644
--- a/src/Middleware/HttpLogging/src/W3CLoggerProcessor.cs
+++ b/src/Middleware/HttpLogging/src/W3CLoggerProcessor.cs
@@ -27,7 +27,7 @@ public override async Task OnFirstWrite(StreamWriter streamWriter, CancellationT
{
await WriteMessageAsync("#Version: 1.0", streamWriter, cancellationToken);
- await WriteMessageAsync("#Start-Date: " + DateTimeOffset.UtcNow.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), streamWriter, cancellationToken);
+ await WriteMessageAsync("#Start-Date: " + DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), streamWriter, cancellationToken);
await WriteMessageAsync(GetFieldsDirective(), streamWriter, cancellationToken);
}
diff --git a/src/Middleware/HttpLogging/test/FileLoggerProcessorTests.cs b/src/Middleware/HttpLogging/test/FileLoggerProcessorTests.cs
index b051337a5c7d..fd00142756f4 100644
--- a/src/Middleware/HttpLogging/test/FileLoggerProcessorTests.cs
+++ b/src/Middleware/HttpLogging/test/FileLoggerProcessorTests.cs
@@ -12,6 +12,7 @@
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Hosting.Internal;
using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Extensions.Logging.Testing;
using Microsoft.Net.Http.Headers;
using Xunit;
@@ -23,6 +24,8 @@ public class FileLoggerProcessorTests
private string _messageOne = "Message one";
private string _messageTwo = "Message two";
private string _messageThree = "Message three";
+ private string _messageFour = "Message four";
+ private readonly DateTime _today = DateTime.UtcNow;
public FileLoggerProcessorTests()
{
@@ -190,6 +193,60 @@ public async Task RespectsMaxFileCount()
}
}
+ [Fact]
+ public async Task StopsLoggingAfter10000Files()
+ {
+ var path = Path.Combine(TempPath, Path.GetRandomFileName());
+ Directory.CreateDirectory(path);
+
+ try
+ {
+ string lastFileName;
+ var options = new W3CLoggerOptions()
+ {
+ LogDirectory = path,
+ FileSizeLimit = 5,
+ RetainedFileCountLimit = 10000
+ };
+ var testSink = new TestSink();
+ var testLogger = new TestLoggerFactory(testSink, enabled:true);
+ await using (var logger = new FileLoggerProcessor(new OptionsWrapperMonitor(options), new HostingEnvironment(), testLogger))
+ {
+ for (int i = 0; i < 10000; i++)
+ {
+ logger.EnqueueMessage(_messageOne);
+ }
+ lastFileName = Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.9999.txt"));
+ await WaitForFile(lastFileName, _messageOne.Length).DefaultTimeout();
+
+ // directory is full, no warnings yet
+ Assert.Equal(0, testSink.Writes.Count);
+
+ logger.EnqueueMessage(_messageOne);
+ await WaitForCondition(() => testSink.Writes.FirstOrDefault()?.EventId.Name == "MaxFilesReached").DefaultTimeout();
+ }
+
+ Assert.Equal(10000, new DirectoryInfo(path)
+ .GetFiles()
+ .ToArray().Length);
+
+ // restarting the logger should do nothing since the folder is still full
+ var testSink2 = new TestSink();
+ var testLogger2 = new TestLoggerFactory(testSink2, enabled:true);
+ await using (var logger = new FileLoggerProcessor(new OptionsWrapperMonitor(options), new HostingEnvironment(), testLogger2))
+ {
+ Assert.Equal(0, testSink2.Writes.Count);
+
+ logger.EnqueueMessage(_messageOne);
+ await WaitForCondition(() => testSink2.Writes.FirstOrDefault()?.EventId.Name == "MaxFilesReached").DefaultTimeout();
+ }
+ }
+ finally
+ {
+ Helpers.DisposeDirectory(path);
+ }
+ }
+
[Fact]
public async Task InstancesWriteToSameDirectory()
{
@@ -340,6 +397,66 @@ public async Task WritesToNewFileOnNewInstance()
}
}
+ [Fact]
+ public async Task RollsTextFilesWhenFirstLogOfDayIsMissing()
+ {
+ var path = Path.Combine(TempPath, Path.GetRandomFileName());
+ Directory.CreateDirectory(path);
+
+ try
+ {
+ var options = new W3CLoggerOptions()
+ {
+ LogDirectory = path,
+ FileSizeLimit = 5,
+ RetainedFileCountLimit = 2,
+ };
+ var fileName1 = Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.0000.txt"));
+ var fileName2 = Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.0001.txt"));
+ var fileName3 = Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.0002.txt"));
+ var fileName4 = Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.0003.txt"));
+
+ await using (var logger = new FileLoggerProcessor(new OptionsWrapperMonitor(options), new HostingEnvironment(), NullLoggerFactory.Instance))
+ {
+ logger.EnqueueMessage(_messageOne);
+ logger.EnqueueMessage(_messageTwo);
+ logger.EnqueueMessage(_messageThree);
+ // Pause for a bit before disposing so logger can finish logging
+ await WaitForFile(fileName3, _messageThree.Length).DefaultTimeout();
+ }
+
+ // Even with a big enough FileSizeLimit, we still won't try to write to files from a previous instance.
+ options.FileSizeLimit = 10000;
+
+ await using (var logger = new FileLoggerProcessor(new OptionsWrapperMonitor(options), new HostingEnvironment(), NullLoggerFactory.Instance))
+ {
+ logger.EnqueueMessage(_messageFour);
+ // Pause for a bit before disposing so logger can finish logging
+ await WaitForFile(fileName4, _messageFour.Length).DefaultTimeout();
+ }
+
+ var actualFiles = new DirectoryInfo(path)
+ .GetFiles()
+ .Select(f => f.Name)
+ .OrderBy(f => f)
+ .ToArray();
+
+ Assert.Equal(2, actualFiles.Length);
+
+ Assert.False(File.Exists(fileName1));
+ Assert.False(File.Exists(fileName2));
+ Assert.True(File.Exists(fileName3));
+ Assert.True(File.Exists(fileName4));
+
+ Assert.Equal(_messageThree + Environment.NewLine, File.ReadAllText(fileName3));
+ Assert.Equal(_messageFour + Environment.NewLine, File.ReadAllText(fileName4));
+ }
+ finally
+ {
+ Helpers.DisposeDirectory(path);
+ }
+ }
+
[QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/34982")]
[Fact]
public async Task WritesToNewFileOnOptionsChange()
@@ -420,6 +537,14 @@ private async Task WaitForFile(string fileName, int length)
}
}
+ private async Task WaitForCondition(Func waitForLog)
+ {
+ while (!waitForLog())
+ {
+ await Task.Delay(10);
+ }
+ }
+
private async Task WaitForRoll(string fileName)
{
while (File.Exists(fileName))
diff --git a/src/Middleware/HttpLogging/test/W3CLoggerTests.cs b/src/Middleware/HttpLogging/test/W3CLoggerTests.cs
index 759f6354ea86..078aa5af4c46 100644
--- a/src/Middleware/HttpLogging/test/W3CLoggerTests.cs
+++ b/src/Middleware/HttpLogging/test/W3CLoggerTests.cs
@@ -25,7 +25,7 @@ public class W3CLoggerTests
public async Task WritesDateTime()
{
var path = Path.GetTempFileName() + "_";
- var now = DateTime.Now;
+ var now = DateTime.UtcNow;
var options = new W3CLoggerOptions()
{
LoggingFields = W3CLoggingFields.Date | W3CLoggingFields.Time,
@@ -48,7 +48,9 @@ public async Task WritesDateTime()
Assert.StartsWith("#Start-Date: ", lines[1]);
var startDate = DateTime.Parse(lines[1].Substring(13), CultureInfo.InvariantCulture);
// Assert that the log was written in the last 10 seconds
- Assert.True(now.Subtract(startDate).TotalSeconds < 10);
+ // W3CLogger writes start-time to second precision, so delta could be as low as -0.999...
+ var delta = startDate.Subtract(now).TotalSeconds;
+ Assert.InRange(delta, -1, 10);
Assert.Equal("#Fields: date time", lines[2]);
@@ -89,7 +91,9 @@ public async Task HandlesNullValuesAsync()
Assert.StartsWith("#Start-Date: ", lines[1]);
var startDate = DateTime.Parse(lines[1].Substring(13), CultureInfo.InvariantCulture);
// Assert that the log was written in the last 10 seconds
- Assert.True(now.Subtract(startDate).TotalSeconds < 10);
+ // W3CLogger writes start-time to second precision, so delta could be as low as -0.999...
+ var delta = startDate.Subtract(now).TotalSeconds;
+ Assert.InRange(delta, -1, 10);
Assert.Equal("#Fields: cs-uri-query sc-status cs-host", lines[2]);
Assert.Equal("- - -", lines[3]);
diff --git a/src/Middleware/HttpLogging/test/W3CLoggingMiddlewareTests.cs b/src/Middleware/HttpLogging/test/W3CLoggingMiddlewareTests.cs
index e1f1d0ab6849..9c4a20f3e72c 100644
--- a/src/Middleware/HttpLogging/test/W3CLoggingMiddlewareTests.cs
+++ b/src/Middleware/HttpLogging/test/W3CLoggingMiddlewareTests.cs
@@ -94,7 +94,7 @@ public async Task DefaultDoesNotLogOptionalFields()
httpContext.Request.Headers["Cookie"] = "Snickerdoodle";
httpContext.Response.StatusCode = 200;
- var now = DateTime.Now;
+ var now = DateTime.UtcNow;
await middleware.Invoke(httpContext);
await logger.Processor.WaitForWrites(4).DefaultTimeout();
@@ -104,7 +104,9 @@ public async Task DefaultDoesNotLogOptionalFields()
Assert.StartsWith("#Start-Date: ", lines[1]);
var startDate = DateTime.Parse(lines[1].Substring(13), CultureInfo.InvariantCulture);
// Assert that the log was written in the last 10 seconds
- Assert.True(now.Subtract(startDate).TotalSeconds < 10);
+ // W3CLogger writes start-time to second precision, so delta could be as low as -0.999...
+ var delta = startDate.Subtract(now).TotalSeconds;
+ Assert.InRange(delta, -1, 10);
Assert.Equal("#Fields: date time c-ip s-computername s-ip s-port cs-method cs-uri-stem cs-uri-query sc-status time-taken cs-version cs-host cs(User-Agent) cs(Referer)", lines[2]);
Assert.DoesNotContain(lines[3], "Snickerdoodle");
@@ -128,7 +130,7 @@ public async Task TimeTakenIsInMilliseconds()
var httpContext = new DefaultHttpContext();
- var now = DateTime.Now;
+ var now = DateTime.UtcNow;
await middleware.Invoke(httpContext);
await logger.Processor.WaitForWrites(4).DefaultTimeout();
@@ -138,7 +140,9 @@ public async Task TimeTakenIsInMilliseconds()
Assert.StartsWith("#Start-Date: ", lines[1]);
var startDate = DateTime.Parse(lines[1].Substring(13), CultureInfo.InvariantCulture);
// Assert that the log was written in the last 10 seconds
- Assert.True(now.Subtract(startDate).TotalSeconds < 10);
+ // W3CLogger writes start-time to second precision, so delta could be as low as -0.999...
+ var delta = startDate.Subtract(now).TotalSeconds;
+ Assert.InRange(delta, -1, 10);
Assert.Equal("#Fields: time-taken", lines[2]);
double num;
diff --git a/src/ProjectTemplates/BlazorTemplates.Tests/BlazorTemplateTest.cs b/src/ProjectTemplates/BlazorTemplates.Tests/BlazorTemplateTest.cs
index 7ff582dcd896..3a8523a5e23f 100644
--- a/src/ProjectTemplates/BlazorTemplates.Tests/BlazorTemplateTest.cs
+++ b/src/ProjectTemplates/BlazorTemplates.Tests/BlazorTemplateTest.cs
@@ -29,7 +29,7 @@ protected async Task CreateBuildPublishAsync(string projectName, string
// Additional arguments are needed. See: https://github.com/dotnet/aspnetcore/issues/24278
Environment.SetEnvironmentVariable("EnableDefaultScopedCssItems", "true");
- var project = await ProjectFactory.GetOrCreateProject(projectName, Output);
+ var project = await ProjectFactory.CreateProject(Output);
if (targetFramework != null)
{
project.TargetFramework = targetFramework;
diff --git a/src/ProjectTemplates/BlazorTemplates.Tests/yarn.lock b/src/ProjectTemplates/BlazorTemplates.Tests/yarn.lock
index 136eccbe7f67..8eb6533d4475 100644
--- a/src/ProjectTemplates/BlazorTemplates.Tests/yarn.lock
+++ b/src/ProjectTemplates/BlazorTemplates.Tests/yarn.lock
@@ -254,9 +254,9 @@ mimic-response@^3.1.0:
integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
minimist@^1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
- integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
+ integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
mkdirp@^1.0.4:
version "1.0.4"
diff --git a/src/ProjectTemplates/Shared/ProcessResult.cs b/src/ProjectTemplates/Shared/ProcessResult.cs
index 81ff0f2bd13b..474f252f2e80 100644
--- a/src/ProjectTemplates/Shared/ProcessResult.cs
+++ b/src/ProjectTemplates/Shared/ProcessResult.cs
@@ -17,7 +17,7 @@ public ProcessResult(ProcessEx process)
public string Process { get; }
- public int ExitCode { get; }
+ public int ExitCode { get; set; }
public string Error { get; }
diff --git a/src/ProjectTemplates/Shared/Project.cs b/src/ProjectTemplates/Shared/Project.cs
index f78a7d4ab238..14e4c1985e1a 100644
--- a/src/ProjectTemplates/Shared/Project.cs
+++ b/src/ProjectTemplates/Shared/Project.cs
@@ -54,6 +54,7 @@ internal async Task RunDotNetNewAsync(
string language = null,
bool useLocalDB = false,
bool noHttps = false,
+ bool errorOnRestoreError = true,
string[] args = null,
// Used to set special options in MSBuild
IDictionary environmentVariables = null)
@@ -95,29 +96,15 @@ internal async Task RunDotNetNewAsync(
argString += $" -o {TemplateOutputDir}";
- // Only run one instance of 'dotnet new' at once, as a workaround for
- // https://github.com/aspnet/templating/issues/63
-
- await DotNetNewLock.WaitAsync();
- try
- {
- Output.WriteLine("Acquired DotNetNewLock");
-
- if (Directory.Exists(TemplateOutputDir))
- {
- Output.WriteLine($"Template directory already exists, deleting contents of {TemplateOutputDir}");
- Directory.Delete(TemplateOutputDir, recursive: true);
- }
-
- using var execution = ProcessEx.Run(Output, AppContext.BaseDirectory, DotNetMuxer.MuxerPathOrDefault(), argString, environmentVariables);
- await execution.Exited;
- return new ProcessResult(execution);
- }
- finally
+ if (Directory.Exists(TemplateOutputDir))
{
- DotNetNewLock.Release();
- Output.WriteLine("Released DotNetNewLock");
+ Output.WriteLine($"Template directory already exists, deleting contents of {TemplateOutputDir}");
+ Directory.Delete(TemplateOutputDir, recursive: true);
}
+
+ using var execution = ProcessEx.Run(Output, AppContext.BaseDirectory, DotNetMuxer.MuxerPathOrDefault(), argString, environmentVariables);
+ await execution.Exited;
+ return new ProcessResult(execution);
}
internal async Task RunDotNetPublishAsync(IDictionary packageOptions = null, string additionalArgs = null, bool noRestore = true)
@@ -183,31 +170,19 @@ internal async Task RunDotNetEfCreateMigrationAsync(string migrat
{
var args = $"--verbose --no-build migrations add {migrationName}";
- // Only run one instance of 'dotnet new' at once, as a workaround for
- // https://github.com/aspnet/templating/issues/63
- await DotNetNewLock.WaitAsync();
- try
+ var command = DotNetMuxer.MuxerPathOrDefault();
+ if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("DotNetEfFullPath")))
{
- Output.WriteLine("Acquired DotNetNewLock");
- var command = DotNetMuxer.MuxerPathOrDefault();
- if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("DotNetEfFullPath")))
- {
- args = $"\"{DotNetEfFullPath}\" " + args;
- }
- else
- {
- command = "dotnet-ef";
- }
-
- using var result = ProcessEx.Run(Output, TemplateOutputDir, command, args);
- await result.Exited;
- return new ProcessResult(result);
+ args = $"\"{DotNetEfFullPath}\" " + args;
}
- finally
+ else
{
- DotNetNewLock.Release();
- Output.WriteLine("Released DotNetNewLock");
+ command = "dotnet-ef";
}
+
+ using var result = ProcessEx.Run(Output, TemplateOutputDir, command, args);
+ await result.Exited;
+ return new ProcessResult(result);
}
internal async Task RunDotNetEfUpdateDatabaseAsync()
@@ -216,31 +191,19 @@ internal async Task RunDotNetEfUpdateDatabaseAsync()
var args = "--verbose --no-build database update";
- // Only run one instance of 'dotnet new' at once, as a workaround for
- // https://github.com/aspnet/templating/issues/63
- await DotNetNewLock.WaitAsync();
- try
+ var command = DotNetMuxer.MuxerPathOrDefault();
+ if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("DotNetEfFullPath")))
{
- Output.WriteLine("Acquired DotNetNewLock");
- var command = DotNetMuxer.MuxerPathOrDefault();
- if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("DotNetEfFullPath")))
- {
- args = $"\"{DotNetEfFullPath}\" " + args;
- }
- else
- {
- command = "dotnet-ef";
- }
-
- using var result = ProcessEx.Run(Output, TemplateOutputDir, command, args);
- await result.Exited;
- return new ProcessResult(result);
+ args = $"\"{DotNetEfFullPath}\" " + args;
}
- finally
+ else
{
- DotNetNewLock.Release();
- Output.WriteLine("Released DotNetNewLock");
+ command = "dotnet-ef";
}
+
+ using var result = ProcessEx.Run(Output, TemplateOutputDir, command, args);
+ await result.Exited;
+ return new ProcessResult(result);
}
// If this fails, you should generate new migrations via migrations/updateMigrations.cmd
@@ -294,25 +257,15 @@ public string ReadFile(string path)
internal async Task RunDotNetNewRawAsync(string arguments)
{
- await DotNetNewLock.WaitAsync();
- try
- {
- Output.WriteLine("Acquired DotNetNewLock");
- var result = ProcessEx.Run(
- Output,
- AppContext.BaseDirectory,
- DotNetMuxer.MuxerPathOrDefault(),
- arguments +
- $" --debug:disable-sdk-templates --debug:custom-hive \"{TemplatePackageInstaller.CustomHivePath}\"" +
- $" -o {TemplateOutputDir}");
- await result.Exited;
- return result;
- }
- finally
- {
- DotNetNewLock.Release();
- Output.WriteLine("Released DotNetNewLock");
- }
+ var result = ProcessEx.Run(
+ Output,
+ AppContext.BaseDirectory,
+ DotNetMuxer.MuxerPathOrDefault(),
+ arguments +
+ $" --debug:disable-sdk-templates --debug:custom-hive \"{TemplatePackageInstaller.CustomHivePath}\"" +
+ $" -o {TemplateOutputDir}");
+ await result.Exited;
+ return result;
}
public void Dispose()
diff --git a/src/ProjectTemplates/Shared/ProjectFactoryFixture.cs b/src/ProjectTemplates/Shared/ProjectFactoryFixture.cs
index 9af84efc680d..f18518286018 100644
--- a/src/ProjectTemplates/Shared/ProjectFactoryFixture.cs
+++ b/src/ProjectTemplates/Shared/ProjectFactoryFixture.cs
@@ -14,6 +14,7 @@ namespace Templates.Test.Helpers
{
public class ProjectFactoryFixture : IDisposable
{
+ private const string LetterChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private readonly ConcurrentDictionary _projects = new ConcurrentDictionary();
public IMessageSink DiagnosticsMessageSink { get; }
@@ -23,6 +24,21 @@ public ProjectFactoryFixture(IMessageSink diagnosticsMessageSink)
DiagnosticsMessageSink = diagnosticsMessageSink;
}
+ public async Task CreateProject(ITestOutputHelper output)
+ {
+ await TemplatePackageInstaller.EnsureTemplatingEngineInitializedAsync(output);
+
+ var project = CreateProjectImpl(output);
+
+ var projectKey = Guid.NewGuid().ToString().Substring(0, 10).ToLowerInvariant();
+ if (!_projects.TryAdd(projectKey, project))
+ {
+ throw new InvalidOperationException($"Project key collision in {nameof(ProjectFactoryFixture)}.{nameof(CreateProject)}!");
+ }
+
+ return project;
+ }
+
public async Task GetOrCreateProject(string projectKey, ITestOutputHelper output)
{
await TemplatePackageInstaller.EnsureTemplatingEngineInitializedAsync(output);
@@ -34,24 +50,31 @@ public async Task GetOrCreateProject(string projectKey, ITestOutputHelp
}
return _projects.GetOrAdd(
projectKey,
- (key, outputHelper) =>
- {
- var project = new Project
- {
- Output = outputHelper,
- DiagnosticsMessageSink = DiagnosticsMessageSink,
- ProjectGuid = Path.GetRandomFileName().Replace(".", string.Empty)
- };
- project.ProjectName = $"AspNet.{project.ProjectGuid}";
-
- var assemblyPath = GetType().Assembly;
- var basePath = GetTemplateFolderBasePath(assemblyPath);
- project.TemplateOutputDir = Path.Combine(basePath, project.ProjectName);
- return project;
- },
+ (_, outputHelper) => CreateProjectImpl(outputHelper),
output);
}
+ private Project CreateProjectImpl(ITestOutputHelper output)
+ {
+ var project = new Project
+ {
+ Output = output,
+ DiagnosticsMessageSink = DiagnosticsMessageSink,
+ // Ensure first character is a letter to avoid random insertions of '_' into template namespace
+ // declarations (i.e. make it more stable for testing)
+ ProjectGuid = GetRandomLetter() + Path.GetRandomFileName().Replace(".", string.Empty)
+ };
+ project.ProjectName = $"AspNetCore.{project.ProjectGuid}";
+
+ var assemblyPath = GetType().Assembly;
+ var basePath = GetTemplateFolderBasePath(assemblyPath);
+ project.TemplateOutputDir = Path.Combine(basePath, project.ProjectName);
+
+ return project;
+ }
+
+ private static char GetRandomLetter() => LetterChars[Random.Shared.Next(LetterChars.Length - 1)];
+
private static string GetTemplateFolderBasePath(Assembly assembly) =>
(string.IsNullOrEmpty(Environment.GetEnvironmentVariable("HELIX_DIR")))
? assembly.GetCustomAttributes()
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/Program.Main.cs
index 92eb45d80a91..a0b654422797 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/Program.Main.cs
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/Program.Main.cs
@@ -37,7 +37,7 @@
#endif
using BlazorServerWeb_CSharp.Data;
-namespace Company.WebApplication1;
+namespace BlazorServerWeb_CSharp;
public class Program
{
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Program.Main.cs
index 8b870e5dc9d3..18be2444cb69 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Program.Main.cs
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Program.Main.cs
@@ -9,7 +9,11 @@
using ComponentsWebAssembly_CSharp;
#endif
-namespace Company.WebApplication1;
+#if (Hosted)
+namespace ComponentsWebAssembly_CSharp.Client;
+#else
+namespace ComponentsWebAssembly_CSharp;
+#endif
public class Program
{
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Program.Main.cs
index 31835439cd28..f6e53531c467 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Program.Main.cs
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Program.Main.cs
@@ -19,7 +19,7 @@
using ComponentsWebAssembly_CSharp.Server.Models;
#endif
-namespace Company.WebApplication1;
+namespace ComponentsWebAssembly_CSharp;
public class Program
{
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Program.Main.cs
index ec1af1a7e9c6..04fc97d104f1 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Program.Main.cs
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Program.Main.cs
@@ -1,6 +1,6 @@
using GrpcService_CSharp.Services;
-namespace Company.WebApplication1;
+namespace GrpcService_CSharp;
public class Program
{
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/template.json
index 5c9b53aedcd1..9cf6ab2fa69e 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/template.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/template.json
@@ -44,9 +44,11 @@
]
},
{
- "condition": "(UseProgramMain && !UseMinimalAPIs)",
+ "condition": "(UseProgramMain)",
"exclude": [
- "Program.cs"
+ "Program.cs",
+ "Program.MinimalAPIs.OrgOrIndividualB2CAuth.cs",
+ "Program.MinimalAPIs.WindowsOrNoAuth.cs"
],
"rename": {
"Program.Main.cs": "Program.cs"
@@ -55,13 +57,17 @@
{
"condition": "(UseMinimalAPIs)",
"exclude": [
- "Controllers/WeatherForecastController.cs",
- "Program.cs",
+ "Controllers/WeatherForecastController.cs"
+ ]
+ },
+ {
+ "condition": "(UseMinimalAPIs && !UseProgramMain)",
+ "exclude": [
"WeatherForecast.cs"
]
},
{
- "condition": "(UseMinimalAPIs && (NoAuth || WindowsAuth))",
+ "condition": "(!UseProgramMain && UseMinimalAPIs && (NoAuth || WindowsAuth))",
"rename": {
"Program.MinimalAPIs.WindowsOrNoAuth.cs": "Program.cs"
},
@@ -70,7 +76,7 @@
]
},
{
- "condition": "(UseMinimalAPIs && (IndividualAuth || OrganizationalAuth))",
+ "condition": "(!UseProgramMain && UseMinimalAPIs && (IndividualAuth || OrganizationalAuth))",
"rename": {
"Program.MinimalAPIs.OrgOrIndividualB2CAuth.cs": "Program.cs"
},
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.Main.cs
index a0c9ad67e817..a882ad35c648 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.Main.cs
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.Main.cs
@@ -10,6 +10,7 @@
#endif
#if (OrganizationalAuth || IndividualB2CAuth)
using Microsoft.Identity.Web;
+using Microsoft.Identity.Web.Resource;
#endif
#if (OrganizationalAuth || IndividualB2CAuth || GenerateGraph || WindowsAuth)
@@ -20,76 +21,168 @@ public class Program
{
public static void Main(string[] args)
{
- var builder = WebApplication.CreateBuilder(args);
-
- // Add services to the container.
- #if (OrganizationalAuth)
- builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
- #if (GenerateApiOrGraph)
- .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
- .EnableTokenAcquisitionToCallDownstreamApi()
- #if (GenerateApi)
- .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
- #endif
- #if (GenerateGraph)
- .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
- #endif
- .AddInMemoryTokenCaches();
- #else
- .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
- #endif
- #elif (IndividualB2CAuth)
- builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
- #if (GenerateApi)
- .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAdB2C"))
- .EnableTokenAcquisitionToCallDownstreamApi()
- .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
- .AddInMemoryTokenCaches();
- #else
- .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAdB2C"));
- #endif
- #endif
-
- builder.Services.AddControllers();
- #if (EnableOpenAPI)
- // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
- builder.Services.AddEndpointsApiExplorer();
- builder.Services.AddSwaggerGen();
- #endif
- #if (WindowsAuth)
-
- builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
- .AddNegotiate();
-
- builder.Services.AddAuthorization(options =>
- {
- // By default, all incoming requests will be authorized according to the default policy.
- options.FallbackPolicy = options.DefaultPolicy;
- });
- #endif
+ var builder = WebApplication.CreateBuilder(args);
- var app = builder.Build();
+ // Add services to the container.
+ #if (OrganizationalAuth)
+ builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+ #if (GenerateApiOrGraph)
+ .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
+ .EnableTokenAcquisitionToCallDownstreamApi()
+ #if (GenerateApi)
+ .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
+ #endif
+ #if (GenerateGraph)
+ .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
+ #endif
+ .AddInMemoryTokenCaches();
+ #else
+ .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
+ #endif
+ #elif (IndividualB2CAuth)
+ builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+ #if (GenerateApi)
+ .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAdB2C"))
+ .EnableTokenAcquisitionToCallDownstreamApi()
+ .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
+ .AddInMemoryTokenCaches();
+ #else
+ .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAdB2C"));
+ #endif
+ #endif
+ #if (UseMinimalAPIs)
+ builder.Services.AddAuthorization();
+ #endif
- // Configure the HTTP request pipeline.
- #if (EnableOpenAPI)
- if (app.Environment.IsDevelopment())
- {
- app.UseSwagger();
- app.UseSwaggerUI();
- }
- #endif
- #if (RequiresHttps)
+ #if (UseControllers)
+ builder.Services.AddControllers();
+ #endif
+ #if (EnableOpenAPI)
+ // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
+ builder.Services.AddEndpointsApiExplorer();
+ builder.Services.AddSwaggerGen();
+ #endif
+ #if (WindowsAuth)
+
+ builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
+ .AddNegotiate();
+
+ builder.Services.AddAuthorization(options =>
+ {
+ // By default, all incoming requests will be authorized according to the default policy.
+ options.FallbackPolicy = options.DefaultPolicy;
+ });
+ #endif
+
+ var app = builder.Build();
+
+ // Configure the HTTP request pipeline.
+ #if (EnableOpenAPI)
+ if (app.Environment.IsDevelopment())
+ {
+ app.UseSwagger();
+ app.UseSwaggerUI();
+ }
+ #endif
+ #if (RequiresHttps)
+
+ app.UseHttpsRedirection();
+ #endif
+
+ #if (OrganizationalAuth || IndividualAuth || WindowsAuth)
+ app.UseAuthentication();
+ #endif
+ app.UseAuthorization();
+
+ #if (UseMinimalAPIs)
+ #if (OrganizationalAuth || IndividualB2CAuth)
+ var scopeRequiredByApi = app.Configuration["AzureAd:Scopes"] ?? "";
+ #endif
+ var summaries = new[]
+ {
+ "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
+ };
+
+ #if (GenerateApi)
+ app.MapGet("/weatherforecast", async (HttpContext httpContext, IDownstreamWebApi downstreamWebApi) =>
+ {
+ httpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
+
+ using var response = await downstreamWebApi.CallWebApiForUserAsync("DownstreamApi").ConfigureAwait(false);
+ if (response.StatusCode == System.Net.HttpStatusCode.OK)
+ {
+ var apiResult = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
+ // Do something
+ }
+ else
+ {
+ var error = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
+ throw new HttpRequestException($"Invalid status code in the HttpResponseMessage: {response.StatusCode}: {error}");
+ }
+
+ var forecast = Enumerable.Range(1, 5).Select(index =>
+ new WeatherForecast
+ {
+ Date = DateTime.Now.AddDays(index),
+ TemperatureC = Random.Shared.Next(-20, 55),
+ Summary = summaries[Random.Shared.Next(summaries.Length)]
+ })
+ .ToArray();
+
+ return forecast;
+ #elif (GenerateGraph)
+ app.MapGet("/weatherforecast", async (HttpContext httpContext, Graph.GraphServiceClient graphServiceClient) =>
+ {
+ httpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
+
+ var user = await graphServiceClient.Me.Request().GetAsync();
+
+ var forecast = Enumerable.Range(1, 5).Select(index =>
+ new WeatherForecast
+ {
+ Date = DateTime.Now.AddDays(index),
+ TemperatureC = Random.Shared.Next(-20, 55),
+ Summary = summaries[Random.Shared.Next(summaries.Length)]
+ })
+ .ToArray();
- app.UseHttpsRedirection();
- #endif
+ return forecast;
+ #else
+ app.MapGet("/weatherforecast", (HttpContext httpContext) =>
+ {
+ #if (OrganizationalAuth || IndividualB2CAuth)
+ httpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
- #if (OrganizationalAuth || IndividualAuth || WindowsAuth)
- app.UseAuthentication();
- #endif
- app.UseAuthorization();
+ #endif
+ var forecast = Enumerable.Range(1, 5).Select(index =>
+ new WeatherForecast
+ {
+ Date = DateTime.Now.AddDays(index),
+ TemperatureC = Random.Shared.Next(-20, 55),
+ Summary = summaries[Random.Shared.Next(summaries.Length)]
+ })
+ .ToArray();
+ return forecast;
+ #endif
+ #if (EnableOpenAPI && !NoAuth)
+ })
+ .WithName("GetWeatherForecast")
+ .RequireAuthorization();
+ #elif (EnableOpenAPI && NoAuth)
+ })
+ .WithName("GetWeatherForecast");
+ #elif (!EnableOpenAPI && !NoAuth)
+ })
+ .RequireAuthorization();
+ #else
+ });
+ #endif
+ #endif
+ #if (UseControllers)
- app.MapControllers();
+ app.MapControllers();
+ #endif
- app.Run();
+ app.Run();
}
}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.MinimalAPIs.OrgOrIndividualB2CAuth.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.MinimalAPIs.OrgOrIndividualB2CAuth.cs
index 2329d42dafe3..c83adb9d8201 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.MinimalAPIs.OrgOrIndividualB2CAuth.cs
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.MinimalAPIs.OrgOrIndividualB2CAuth.cs
@@ -64,14 +64,14 @@
app.UseAuthentication();
app.UseAuthorization();
-var scopeRequiredByApi = app.Configuration["AzureAd:Scopes"];
+var scopeRequiredByApi = app.Configuration["AzureAd:Scopes"] ?? "";
var summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
#if (GenerateApi)
-app.MapGet("/weatherforecast", (HttpContext httpContext, IDownstreamWebApi downstreamWebApi) =>
+app.MapGet("/weatherforecast", async (HttpContext httpContext, IDownstreamWebApi downstreamWebApi) =>
{
httpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
@@ -97,13 +97,12 @@
.ToArray();
return forecast;
-})
-#elseif (GenerateGraph)
-app.MapGet("/weahterforecast", (HttpContext httpContext, GraphServiceClient graphServiceClient) =>
+#elif (GenerateGraph)
+app.MapGet("/weatherforecast", async (HttpContext httpContext, Graph.GraphServiceClient graphServiceClient) =>
{
httpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
- var user = await _graphServiceClient.Me.Request().GetAsync();
+ var user = await graphServiceClient.Me.Request().GetAsync();
var forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
@@ -115,7 +114,6 @@
.ToArray();
return forecast;
-})
#else
app.MapGet("/weatherforecast", (HttpContext httpContext) =>
{
@@ -145,4 +143,4 @@
record WeatherForecast(DateTime Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
-}
\ No newline at end of file
+}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.MinimalAPIs.WindowsOrNoAuth.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.MinimalAPIs.WindowsOrNoAuth.cs
index 8b8e2b81afd0..77eb04f48ac8 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.MinimalAPIs.WindowsOrNoAuth.cs
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.MinimalAPIs.WindowsOrNoAuth.cs
@@ -37,6 +37,7 @@
#endif
#if (WindowsAuth)
app.UseAuthentication();
+app.UseAuthorization();
#endif
var summaries = new[]
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/Program.Main.cs
index d69747f38d51..10fac97af3ec 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/Program.Main.cs
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/Program.Main.cs
@@ -1,6 +1,4 @@
-using Company.Application1;
-
-namespace Company.WebApplication1;
+namespace Company.Application1;
public class Program
{
diff --git a/src/ProjectTemplates/scripts/Run-Angular-Locally.ps1 b/src/ProjectTemplates/scripts/Run-Angular-Locally.ps1
index 95de6568eab1..30e5329e5efa 100644
--- a/src/ProjectTemplates/scripts/Run-Angular-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-Angular-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "angular" "angular" "Microsoft.DotNet.Web.Spa.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
+Test-Template "angular" "angular" "Microsoft.DotNet.Web.Spa.ProjectTemplates.6.0.6.0.6.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-AngularProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-AngularProgramMain-Locally.ps1
index 93127bb08be0..1db52862a374 100644
--- a/src/ProjectTemplates/scripts/Run-AngularProgramMain-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-AngularProgramMain-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "angular" "angular --use-program-main" "Microsoft.DotNet.Web.Spa.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
+Test-Template "angular" "angular --use-program-main" "Microsoft.DotNet.Web.Spa.ProjectTemplates.6.0.6.0.6.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-Blazor-Locally.ps1 b/src/ProjectTemplates/scripts/Run-Blazor-Locally.ps1
index 7a510a7a9a45..1b0a84aaae62 100644
--- a/src/ProjectTemplates/scripts/Run-Blazor-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-Blazor-Locally.ps1
@@ -10,4 +10,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "blazorserver" "blazorserver" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
+Test-Template "blazorserver" "blazorserver" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.6.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-BlazorProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-BlazorProgramMain-Locally.ps1
index 3d9fdd64a70d..c06d9f83aa80 100644
--- a/src/ProjectTemplates/scripts/Run-BlazorProgramMain-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-BlazorProgramMain-Locally.ps1
@@ -10,4 +10,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "blazorserver" "blazorserver --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
+Test-Template "blazorserver" "blazorserver --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.6.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-BlazorWasm-Locally.ps1 b/src/ProjectTemplates/scripts/Run-BlazorWasm-Locally.ps1
index 50f70bb1b04d..5945a9fd00bd 100644
--- a/src/ProjectTemplates/scripts/Run-BlazorWasm-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-BlazorWasm-Locally.ps1
@@ -10,4 +10,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "blazorwasm" "blazorwasm --hosted --auth Individual" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $true
+Test-Template "blazorwasm" "blazorwasm --hosted --auth Individual" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.6.nupkg" $true
diff --git a/src/ProjectTemplates/scripts/Run-BlazorWasmProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-BlazorWasmProgramMain-Locally.ps1
index 7c8755a8bba3..d7541fe5505f 100644
--- a/src/ProjectTemplates/scripts/Run-BlazorWasmProgramMain-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-BlazorWasmProgramMain-Locally.ps1
@@ -10,4 +10,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "blazorwasm" "blazorwasm --use-program-main --hosted --auth Individual" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $true
+Test-Template "blazorwasm" "blazorwasm --use-program-main --hosted --auth Individual" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.6.nupkg" $true
diff --git a/src/ProjectTemplates/scripts/Run-EmptyWeb-Locally.ps1 b/src/ProjectTemplates/scripts/Run-EmptyWeb-Locally.ps1
index 10e743504b58..ad97e7ed4e3e 100644
--- a/src/ProjectTemplates/scripts/Run-EmptyWeb-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-EmptyWeb-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "web" "web" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
+Test-Template "web" "web" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.6.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-EmptyWebProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-EmptyWebProgramMain-Locally.ps1
index 7453063baf21..d2a4b5f55bf1 100644
--- a/src/ProjectTemplates/scripts/Run-EmptyWebProgramMain-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-EmptyWebProgramMain-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "web" "web --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
+Test-Template "web" "web --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.6.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-Razor-Locally.ps1 b/src/ProjectTemplates/scripts/Run-Razor-Locally.ps1
index 6f16590be8fe..8d562fe763c2 100644
--- a/src/ProjectTemplates/scripts/Run-Razor-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-Razor-Locally.ps1
@@ -6,4 +6,4 @@ param()
. $PSScriptRoot\Test-Template.ps1
-Test-Template "webapp" "webapp -au Individual" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
+Test-Template "webapp" "webapp -au Individual" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.6.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-RazorProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-RazorProgramMain-Locally.ps1
index 4224cf985dd2..bfc7748ccdd4 100644
--- a/src/ProjectTemplates/scripts/Run-RazorProgramMain-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-RazorProgramMain-Locally.ps1
@@ -6,4 +6,4 @@ param()
. $PSScriptRoot\Test-Template.ps1
-Test-Template "webapp" "webapp -au Individual --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
+Test-Template "webapp" "webapp -au Individual --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.6.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-React-Locally.ps1 b/src/ProjectTemplates/scripts/Run-React-Locally.ps1
index a4baf0c40568..c09e8c1fc624 100644
--- a/src/ProjectTemplates/scripts/Run-React-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-React-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "react" "react" "Microsoft.DotNet.Web.Spa.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
+Test-Template "react" "react" "Microsoft.DotNet.Web.Spa.ProjectTemplates.6.0.6.0.6.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-ReactProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-ReactProgramMain-Locally.ps1
index df61a5a11740..b05f556fc17f 100644
--- a/src/ProjectTemplates/scripts/Run-ReactProgramMain-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-ReactProgramMain-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "react" "react --use-program-main" "Microsoft.DotNet.Web.Spa.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
+Test-Template "react" "react --use-program-main" "Microsoft.DotNet.Web.Spa.ProjectTemplates.6.0.6.0.6.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-ReactRedux-Locally.ps1 b/src/ProjectTemplates/scripts/Run-ReactRedux-Locally.ps1
index aedd8ec88acb..df02bed62438 100644
--- a/src/ProjectTemplates/scripts/Run-ReactRedux-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-ReactRedux-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "reactredux" "reactredux" "Microsoft.DotNet.Web.Spa.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
+Test-Template "reactredux" "reactredux" "Microsoft.DotNet.Web.Spa.ProjectTemplates.6.0.6.0.6.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-Starterweb-Locally.ps1 b/src/ProjectTemplates/scripts/Run-Starterweb-Locally.ps1
index ab195cd016ef..6d6afa43a39c 100644
--- a/src/ProjectTemplates/scripts/Run-Starterweb-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-Starterweb-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "mvc" "mvc -au Individual" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
+Test-Template "mvc" "mvc -au Individual" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.6.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-StarterwebProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-StarterwebProgramMain-Locally.ps1
index 076106d3e861..4965829b3904 100644
--- a/src/ProjectTemplates/scripts/Run-StarterwebProgramMain-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-StarterwebProgramMain-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "mvc" "mvc -au Individual --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
+Test-Template "mvc" "mvc -au Individual --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.6.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-WebApi-Locally.ps1 b/src/ProjectTemplates/scripts/Run-WebApi-Locally.ps1
index 467d6e57e76e..cd866e4e355e 100644
--- a/src/ProjectTemplates/scripts/Run-WebApi-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-WebApi-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "webapi" "webapi" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
+Test-Template "webapi" "webapi" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.6.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-WebApiMinimal-Locally.ps1 b/src/ProjectTemplates/scripts/Run-WebApiMinimal-Locally.ps1
index 19325a7c7eca..5afe6c0d586f 100644
--- a/src/ProjectTemplates/scripts/Run-WebApiMinimal-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-WebApiMinimal-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "webapimin" "webapi -minimal" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
+Test-Template "webapimin" "webapi -minimal" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.6.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-WebApiProgamMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-WebApiProgamMain-Locally.ps1
index 41f794b7eaaf..045d249e9aa3 100644
--- a/src/ProjectTemplates/scripts/Run-WebApiProgamMain-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-WebApiProgamMain-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "webapi" "webapi --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
+Test-Template "webapi" "webapi --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.6.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-WebApiProgamMainMinimal-Locally.ps1 b/src/ProjectTemplates/scripts/Run-WebApiProgamMainMinimal-Locally.ps1
new file mode 100644
index 000000000000..c8b66bdcc0ad
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-WebApiProgamMainMinimal-Locally.ps1
@@ -0,0 +1,12 @@
+#!/usr/bin/env pwsh
+#requires -version 4
+
+[CmdletBinding(PositionalBinding = $false)]
+param()
+
+Set-StrictMode -Version 2
+$ErrorActionPreference = 'Stop'
+
+. $PSScriptRoot\Test-Template.ps1
+
+Test-Template "webapi" "webapi --use-program-main --use-minimal-apis" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.6.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-Worker-Locally.ps1 b/src/ProjectTemplates/scripts/Run-Worker-Locally.ps1
index 9f3c0272096d..c201a4fa2e73 100644
--- a/src/ProjectTemplates/scripts/Run-Worker-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-Worker-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "worker" "worker" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
+Test-Template "worker" "worker" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.6.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-WorkerProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-WorkerProgramMain-Locally.ps1
index 9e0aa3d4607b..2852882312c5 100644
--- a/src/ProjectTemplates/scripts/Run-WorkerProgramMain-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-WorkerProgramMain-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "worker" "worker --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
+Test-Template "worker" "worker --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.6.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-gRPC-Locally.ps1 b/src/ProjectTemplates/scripts/Run-gRPC-Locally.ps1
index 2803a34d9c9c..21950ac78920 100644
--- a/src/ProjectTemplates/scripts/Run-gRPC-Locally.ps1
+++ b/src/ProjectTemplates/scripts/Run-gRPC-Locally.ps1
@@ -9,4 +9,4 @@ $ErrorActionPreference = 'Stop'
. $PSScriptRoot\Test-Template.ps1
-Test-Template "grpc" "grpc" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
+Test-Template "grpc" "grpc" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.6.nupkg" $false
diff --git a/src/ProjectTemplates/test/ArgConstants.cs b/src/ProjectTemplates/test/ArgConstants.cs
new file mode 100644
index 000000000000..94a3b2965cce
--- /dev/null
+++ b/src/ProjectTemplates/test/ArgConstants.cs
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Templates.Test;
+
+internal static class ArgConstants
+{
+ public const string UseProgramMain = "--use-program-main";
+ public const string UseMinimalApis = "--use-minimal-apis";
+ public const string Hosted = "--hosted";
+ public const string Pwa = "--pwa";
+ public const string CallsGraph = "--calls-graph";
+ public const string CalledApiUrl = "--called-api-url";
+ public const string CalledApiUrlGraphMicrosoftCom = "--called-api-url \"https://graph.microsoft.com\"";
+ public const string CalledApiScopes = "--called-api-scopes";
+ public const string CalledApiScopesUserReadWrite = $"{CalledApiScopes} user.readwrite";
+ public const string NoOpenApi = "--no-openapi";
+ public const string Auth = "-au";
+ public const string ClientId = "--client-id";
+ public const string Domain = "--domain";
+ public const string DefaultScope = "--default-scope";
+ public const string AppIdUri = "--app-id-uri";
+ public const string AppIdClientId = "--api-client-id";
+ public const string TenantId = "--tenant-id";
+ public const string AadB2cInstance = "--aad-b2c-instance";
+ public const string UseLocalDb = "-uld";
+}
diff --git a/src/ProjectTemplates/test/AssemblyInfo.AssemblyFixtures.cs b/src/ProjectTemplates/test/AssemblyInfo.AssemblyFixtures.cs
index 7e531ec57ea6..3422eecd8c53 100644
--- a/src/ProjectTemplates/test/AssemblyInfo.AssemblyFixtures.cs
+++ b/src/ProjectTemplates/test/AssemblyInfo.AssemblyFixtures.cs
@@ -3,5 +3,7 @@
using Microsoft.AspNetCore.Testing;
using Templates.Test.Helpers;
+using Xunit;
[assembly: AssemblyFixture(typeof(ProjectFactoryFixture))]
+[assembly: CollectionBehavior(DisableTestParallelization = true)]
\ No newline at end of file
diff --git a/src/ProjectTemplates/test/BaselineTest.cs b/src/ProjectTemplates/test/BaselineTest.cs
index 786b7d36dc6b..f98f69b4f0d7 100644
--- a/src/ProjectTemplates/test/BaselineTest.cs
+++ b/src/ProjectTemplates/test/BaselineTest.cs
@@ -67,11 +67,12 @@ public ITestOutputHelper Output
}
// This test should generally not be quarantined as it only is checking that the expected files are on disk
+ // and that the namespace declarations in the generated .cs files start with the project name
[Theory]
[MemberData(nameof(TemplateBaselines))]
public async Task Template_Produces_The_Right_Set_Of_FilesAsync(string arguments, string[] expectedFiles)
{
- Project = await ProjectFactory.GetOrCreateProject(CreateProjectKey(arguments), Output);
+ Project = await ProjectFactory.CreateProject(Output);
var createResult = await Project.RunDotNetNewRawAsync(arguments);
Assert.True(createResult.ExitCode == 0, createResult.GetFormattedOutput());
@@ -100,66 +101,22 @@ public async Task Template_Produces_The_Right_Set_Of_FilesAsync(string arguments
continue;
}
Assert.Contains(relativePath, expectedFiles);
- }
- }
-
- private static ConcurrentDictionary _projectKeys = new();
-
- private string CreateProjectKey(string arguments)
- {
- var text = "baseline";
-
- // Turn string like "new templatename -minimal -au SingleOrg --another-option OptionValue"
- // into array like [ "new templatename", "minimal", "au SingleOrg", "another-option OptionValue" ]
- var argumentsArray = arguments
- .Split(new[] { " --", " -" }, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)
- .ToArray();
- // Add template name, value has form of "new name"
- text += argumentsArray[0].Substring("new ".Length);
-
- // Sort arguments to ensure definitions that differ only by arguments order are caught
- Array.Sort(argumentsArray, StringComparer.Ordinal);
-
- foreach (var argValue in argumentsArray)
- {
- var argSegments = argValue.Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
-
- if (argSegments.Length == 0)
- {
- continue;
- }
- else if (argSegments.Length == 1)
- {
- text += argSegments[0] switch
- {
- "ho" => "hosted",
- "p" => "pwa",
- _ => argSegments[0].Replace("-","")
- };
- }
- else
+ // Commented out to see if it impacts the Helix test failures
+ if (relativePath.EndsWith(".cs", StringComparison.Ordinal))
{
- text += argSegments[0] switch
+ var namespaceDeclarationPrefix = "namespace ";
+ var namespaceDeclaration = File.ReadLines(file)
+ .SingleOrDefault(line => line.StartsWith(namespaceDeclarationPrefix, StringComparison.Ordinal))
+ ?.Substring(namespaceDeclarationPrefix.Length);
+
+ // nullable because Program.cs with top-level statements doesn't have a namespace declaration
+ if (namespaceDeclaration is not null)
{
- "au" => argSegments[1],
- "uld" => "uld",
- "language" => argSegments[1].Replace("#", "Sharp"),
- "support-pages-and-views" when argSegments[1] == "true" => "supportpagesandviewstrue",
- _ => ""
- };
+ Assert.StartsWith(Project.ProjectName, namespaceDeclaration, StringComparison.Ordinal);
+ }
}
}
-
- if (!_projectKeys.TryAdd(text, null))
- {
- throw new InvalidOperationException(
- $"Project key for template with args '{arguments}' already exists. " +
- $"Check that the metadata specified in {BaselineDefinitionFileResourceName} is correct and that " +
- $"the {nameof(CreateProjectKey)} method is considering enough template arguments to ensure uniqueness.");
- }
-
- return text;
}
private void AssertFileExists(string basePath, string path, bool shouldExist)
diff --git a/src/ProjectTemplates/test/BlazorServerTemplateTest.cs b/src/ProjectTemplates/test/BlazorServerTemplateTest.cs
index 104f2304020d..6f277abd3a74 100644
--- a/src/ProjectTemplates/test/BlazorServerTemplateTest.cs
+++ b/src/ProjectTemplates/test/BlazorServerTemplateTest.cs
@@ -24,30 +24,37 @@ public BlazorServerTemplateTest(ProjectFactoryFixture projectFactory)
public override string ProjectType { get; } = "blazorserver";
[Fact]
- public Task BlazorServerTemplateWorks_NoAuth() => CreateBuildPublishAsync("blazorservernoauth");
+ public Task BlazorServerTemplateWorks_NoAuth() => CreateBuildPublishAsync();
[Fact]
- public Task BlazorServerTemplateWorks_ProgamMainNoAuth() => CreateBuildPublishAsync("blazorservernoauth", args: new [] { "--use-program-main" });
+ public Task BlazorServerTemplateWorks_ProgamMainNoAuth() => CreateBuildPublishAsync(args: new [] { ArgConstants.UseProgramMain });
- [Theory]
- [InlineData(true, null)]
- [InlineData(true, new string[] { "--use-program-main" })]
- [InlineData(false, null)]
- [InlineData(false, new string[] { "--use-program-main" })]
+ [ConditionalTheory]
+ [InlineData("Individual", null)]
+ [InlineData("Individual", new string[] { ArgConstants.UseProgramMain })]
[SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/30825", Queues = "All.OSX")]
- public Task BlazorServerTemplateWorks_IndividualAuth(bool useLocalDB, string[] args) => CreateBuildPublishAsync("blazorserverindividual" + (useLocalDB ? "uld" : "", args: args));
+ public Task BlazorServerTemplateWorks_IndividualAuth(string auth, string[] args) => CreateBuildPublishAsync(auth, args: args);
+
+ [ConditionalTheory]
+ [InlineData("Individual", new string[] { ArgConstants.UseLocalDb })]
+ [InlineData("Individual", new string[] { ArgConstants.UseProgramMain, ArgConstants.UseLocalDb })]
+ [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX, SkipReason = "No LocalDb on non-Windows")]
+ public Task BlazorServerTemplateWorks_IndividualAuth_LocalDb(string auth, string[] args) => CreateBuildPublishAsync(auth, args: args);
[Theory]
[InlineData("IndividualB2C", null)]
- [InlineData("IndividualB2C", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
- [InlineData("IndividualB2C", new string[] { "--use-program-main", "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
- [InlineData("SingleOrg", null)]
- [InlineData("SingleOrg", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
- [InlineData("SingleOrg", new string[] { "--use-program-main --called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
- [InlineData("SingleOrg", new string[] { "--calls-graph" })]
- [InlineData("SingleOrg", new string[] { "--use-program-main --calls-graph" })]
- public Task BlazorServerTemplate_IdentityWeb_BuildAndPublish(string auth, string[] args)
- => CreateBuildPublishAsync("blazorserveridweb" + Guid.NewGuid().ToString().Substring(0, 10).ToLowerInvariant(), auth, args);
+ [InlineData("IndividualB2C", new[] { ArgConstants.UseProgramMain })]
+ [InlineData("IndividualB2C", new[] { ArgConstants.CalledApiUrlGraphMicrosoftCom, ArgConstants.CalledApiScopesUserReadWrite })]
+ [InlineData("IndividualB2C", new[] { ArgConstants.UseProgramMain, ArgConstants.CalledApiUrlGraphMicrosoftCom, ArgConstants.CalledApiScopesUserReadWrite })]
+ public Task BlazorServerTemplate_IdentityWeb_BuildAndPublish_IndividualB2C(string auth, string[] args) => CreateBuildPublishAsync(auth, args);
+ [Theory]
+ [InlineData("SingleOrg", null)]
+ [InlineData("SingleOrg", new[] { ArgConstants.UseProgramMain })]
+ [InlineData("SingleOrg", new[] { ArgConstants.CalledApiUrlGraphMicrosoftCom, ArgConstants.CalledApiScopesUserReadWrite })]
+ [InlineData("SingleOrg", new[] { ArgConstants.UseProgramMain, ArgConstants.CalledApiUrlGraphMicrosoftCom, ArgConstants.CalledApiScopesUserReadWrite })]
+ [InlineData("SingleOrg", new[] { ArgConstants.CallsGraph })]
+ [InlineData("SingleOrg", new[] { ArgConstants.UseProgramMain, ArgConstants.CallsGraph })]
+ public Task BlazorServerTemplate_IdentityWeb_BuildAndPublish_SingleOrg(string auth, string[] args) => CreateBuildPublishAsync(auth, args);
}
}
diff --git a/src/ProjectTemplates/test/BlazorTemplateTest.cs b/src/ProjectTemplates/test/BlazorTemplateTest.cs
index 792e9fd24750..b6096de7ce63 100644
--- a/src/ProjectTemplates/test/BlazorTemplateTest.cs
+++ b/src/ProjectTemplates/test/BlazorTemplateTest.cs
@@ -41,12 +41,12 @@ public ITestOutputHelper Output
public abstract string ProjectType { get; }
- protected async Task CreateBuildPublishAsync(string projectName, string auth = null, string[] args = null, string targetFramework = null, bool serverProject = false, bool onlyCreate = false)
+ protected async Task CreateBuildPublishAsync(string auth = null, string[] args = null, string targetFramework = null, bool serverProject = false, bool onlyCreate = false)
{
// Additional arguments are needed. See: https://github.com/dotnet/aspnetcore/issues/24278
Environment.SetEnvironmentVariable("EnableDefaultScopedCssItems", "true");
- var project = await ProjectFactory.GetOrCreateProject(projectName, Output);
+ var project = await ProjectFactory.CreateProject(Output);
if (targetFramework != null)
{
project.TargetFramework = targetFramework;
diff --git a/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs b/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs
index dae6148d213a..fc9bfa5f8e4a 100644
--- a/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs
+++ b/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs
@@ -27,7 +27,7 @@ public BlazorWasmTemplateTest(ProjectFactoryFixture projectFactory)
[Fact]
public async Task BlazorWasmStandaloneTemplateCanCreateBuildPublish()
{
- var project = await CreateBuildPublishAsync("blazorstandalone");
+ var project = await CreateBuildPublishAsync();
// The service worker assets manifest isn't generated for non-PWA projects
var publishDir = Path.Combine(project.TemplatePublishDir, "wwwroot");
@@ -35,18 +35,18 @@ public async Task BlazorWasmStandaloneTemplateCanCreateBuildPublish()
}
[Fact]
- public Task BlazorWasmHostedTemplateCanCreateBuildPublish() => CreateBuildPublishAsync("blazorhosted", args: new[] { "--hosted" }, serverProject: true);
+ public Task BlazorWasmHostedTemplateCanCreateBuildPublish() => CreateBuildPublishAsync(args: new[] { ArgConstants.Hosted }, serverProject: true);
[Fact]
- public Task BlazorWasmHostedTemplateWithProgamMainCanCreateBuildPublish() => CreateBuildPublishAsync("blazorhosted", args: new[] { "--use-program-main", "--hosted" }, serverProject: true);
+ public Task BlazorWasmHostedTemplateWithProgamMainCanCreateBuildPublish() => CreateBuildPublishAsync(args: new[] { ArgConstants.UseProgramMain, ArgConstants.Hosted }, serverProject: true);
[Fact]
- public Task BlazorWasmStandalonePwaTemplateCanCreateBuildPublish() => CreateBuildPublishAsync("blazorstandalonepwa", args: new[] { "--pwa" });
+ public Task BlazorWasmStandalonePwaTemplateCanCreateBuildPublish() => CreateBuildPublishAsync(args: new[] { ArgConstants.Pwa });
[Fact]
public async Task BlazorWasmHostedPwaTemplateCanCreateBuildPublish()
{
- var project = await CreateBuildPublishAsync("blazorhostedpwa", args: new[] { "--hosted", "--pwa" }, serverProject: true);
+ var project = await CreateBuildPublishAsync(args: new[] { ArgConstants.Hosted, ArgConstants.Pwa }, serverProject: true);
var serverProject = GetSubProject(project, "Server", $"{project.ProjectName}.Server");
@@ -81,20 +81,32 @@ private void ValidatePublishedServiceWorker(Project project)
// LocalDB doesn't work on non Windows platforms
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
public Task BlazorWasmHostedTemplate_IndividualAuth_Works_WithLocalDB()
- => BlazorWasmHostedTemplate_IndividualAuth_Works(true);
+ => BlazorWasmHostedTemplate_IndividualAuth_Works(true, false);
[ConditionalFact]
[SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/34554", Queues = "Windows.10.Arm64v8.Open")]
public Task BlazorWasmHostedTemplate_IndividualAuth_Works_WithOutLocalDB()
- => BlazorWasmHostedTemplate_IndividualAuth_Works(false);
+ => BlazorWasmHostedTemplate_IndividualAuth_Works(false, false);
- private async Task CreateBuildPublishIndividualAuthProject(bool useLocalDb)
+ [ConditionalFact]
+ [SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/34554", Queues = "Windows.10.Arm64v8.Open")]
+ // LocalDB doesn't work on non Windows platforms
+ [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
+ public Task BlazorWasmHostedTemplate_IndividualAuth_Works_WithLocalDB_ProgramMain()
+ => BlazorWasmHostedTemplate_IndividualAuth_Works(true, true);
+
+ [ConditionalFact]
+ [SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/34554", Queues = "Windows.10.Arm64v8.Open")]
+ public Task BlazorWasmHostedTemplate_IndividualAuth_Works_WithOutLocalDB_ProgramMain()
+ => BlazorWasmHostedTemplate_IndividualAuth_Works(false, true);
+
+ private async Task CreateBuildPublishIndividualAuthProject(bool useLocalDb, bool useProgramMain = false)
{
// Additional arguments are needed. See: https://github.com/dotnet/aspnetcore/issues/24278
Environment.SetEnvironmentVariable("EnableDefaultScopedCssItems", "true");
- var project = await CreateBuildPublishAsync("blazorhostedindividual" + (useLocalDb ? "uld" : ""),
- args: new[] { "--hosted", "-au", "Individual", useLocalDb ? "-uld" : "" });
+ var project = await CreateBuildPublishAsync("Individual",
+ args: new[] { ArgConstants.Hosted, useLocalDb ? ArgConstants.UseLocalDb : "", useProgramMain ? ArgConstants.UseProgramMain : "" });
var serverProject = GetSubProject(project, "Server", $"{project.ProjectName}.Server");
@@ -128,9 +140,9 @@ private async Task CreateBuildPublishIndividualAuthProject(bool useLoca
return project;
}
- private async Task BlazorWasmHostedTemplate_IndividualAuth_Works(bool useLocalDb)
+ private async Task BlazorWasmHostedTemplate_IndividualAuth_Works(bool useLocalDb, bool useProgramMain)
{
- var project = await CreateBuildPublishIndividualAuthProject(useLocalDb: useLocalDb);
+ var project = await CreateBuildPublishIndividualAuthProject(useLocalDb: useLocalDb, useProgramMain: useProgramMain);
var serverProject = GetSubProject(project, "Server", $"{project.ProjectName}.Server");
}
@@ -138,71 +150,136 @@ private async Task BlazorWasmHostedTemplate_IndividualAuth_Works(bool useLocalDb
[Fact]
public async Task BlazorWasmStandaloneTemplate_IndividualAuth_CreateBuildPublish()
{
- var project = await CreateBuildPublishAsync("blazorstandaloneindividual", args: new[] {
- "-au",
- "Individual",
+ var project = await CreateBuildPublishAsync("Individual", args: new[] {
"--authority",
"https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration",
- "--client-id",
+ ArgConstants.ClientId,
"sample-client-id"
});
}
- public static TheoryData TemplateData => new TheoryData
+ public static TheoryData TemplateDataIndividualB2C => new TheoryData
{
new TemplateInstance(
"blazorwasmhostedaadb2c", "-ho",
- "-au", "IndividualB2C",
- "--aad-b2c-instance", "example.b2clogin.com",
+ ArgConstants.Auth, "IndividualB2C",
+ ArgConstants.AadB2cInstance, "example.b2clogin.com",
"-ssp", "b2c_1_siupin",
- "--client-id", "clientId",
- "--domain", "my-domain",
- "--default-scope", "full",
- "--app-id-uri", "ApiUri",
- "--api-client-id", "1234123413241324"),
+ ArgConstants.ClientId, "clientId",
+ ArgConstants.Domain, "my-domain",
+ ArgConstants.DefaultScope, "full",
+ ArgConstants.AppIdUri, "ApiUri",
+ ArgConstants.AppIdClientId, "1234123413241324"),
+ new TemplateInstance(
+ "blazorwasmhostedaadb2c_program_main", "-ho",
+ ArgConstants.Auth, "IndividualB2C",
+ ArgConstants.AadB2cInstance, "example.b2clogin.com",
+ "-ssp", "b2c_1_siupin",
+ ArgConstants.ClientId, "clientId",
+ ArgConstants.Domain, "my-domain",
+ ArgConstants.DefaultScope, "full",
+ ArgConstants.AppIdUri, "ApiUri",
+ ArgConstants.AppIdClientId, "1234123413241324",
+ ArgConstants.UseProgramMain),
+ new TemplateInstance(
+ "blazorwasmstandaloneaadb2c",
+ ArgConstants.Auth, "IndividualB2C",
+ ArgConstants.AadB2cInstance, "example.b2clogin.com",
+ "-ssp", "b2c_1_siupin",
+ ArgConstants.ClientId, "clientId",
+ ArgConstants.Domain, "my-domain"),
+ new TemplateInstance(
+ "blazorwasmstandaloneaadb2c_program_main",
+ ArgConstants.Auth, "IndividualB2C",
+ ArgConstants.AadB2cInstance, "example.b2clogin.com",
+ "-ssp", "b2c_1_siupin",
+ ArgConstants.ClientId, "clientId",
+ ArgConstants.Domain, "my-domain",
+ ArgConstants.UseProgramMain),
+ };
+
+ public static TheoryData TemplateDataSingleOrg => new TheoryData
+ {
new TemplateInstance(
"blazorwasmhostedaad", "-ho",
- "-au", "SingleOrg",
- "--domain", "my-domain",
- "--tenant-id", "tenantId",
- "--client-id", "clientId",
- "--default-scope", "full",
- "--app-id-uri", "ApiUri",
- "--api-client-id", "1234123413241324"),
+ ArgConstants.Auth, "SingleOrg",
+ ArgConstants.Domain, "my-domain",
+ ArgConstants.TenantId, "tenantId",
+ ArgConstants.ClientId, "clientId",
+ ArgConstants.DefaultScope, "full",
+ ArgConstants.AppIdUri, "ApiUri",
+ ArgConstants.AppIdClientId, "1234123413241324"),
new TemplateInstance(
"blazorwasmhostedaadgraph", "-ho",
- "-au", "SingleOrg",
- "--calls-graph",
- "--domain", "my-domain",
- "--tenant-id", "tenantId",
- "--client-id", "clientId",
- "--default-scope", "full",
- "--app-id-uri", "ApiUri",
- "--api-client-id", "1234123413241324"),
+ ArgConstants.Auth, "SingleOrg",
+ ArgConstants.CallsGraph,
+ ArgConstants.Domain, "my-domain",
+ ArgConstants.TenantId, "tenantId",
+ ArgConstants.ClientId, "clientId",
+ ArgConstants.DefaultScope, "full",
+ ArgConstants.AppIdUri, "ApiUri",
+ ArgConstants.AppIdClientId, "1234123413241324"),
new TemplateInstance(
"blazorwasmhostedaadapi", "-ho",
- "-au", "SingleOrg",
- "--called-api-url", "\"https://graph.microsoft.com\"",
- "--called-api-scopes", "user.readwrite",
- "--domain", "my-domain",
- "--tenant-id", "tenantId",
- "--client-id", "clientId",
- "--default-scope", "full",
- "--app-id-uri", "ApiUri",
- "--api-client-id", "1234123413241324"),
- new TemplateInstance(
- "blazorwasmstandaloneaadb2c",
- "-au", "IndividualB2C",
- "--aad-b2c-instance", "example.b2clogin.com",
- "-ssp", "b2c_1_siupin",
- "--client-id", "clientId",
- "--domain", "my-domain"),
+ ArgConstants.Auth, "SingleOrg",
+ ArgConstants.CalledApiUrl, "\"https://graph.microsoft.com\"",
+ ArgConstants.CalledApiScopes, "user.readwrite",
+ ArgConstants.Domain, "my-domain",
+ ArgConstants.TenantId, "tenantId",
+ ArgConstants.ClientId, "clientId",
+ ArgConstants.DefaultScope, "full",
+ ArgConstants.AppIdUri, "ApiUri",
+ ArgConstants.AppIdClientId, "1234123413241324"),
new TemplateInstance(
"blazorwasmstandaloneaad",
- "-au", "SingleOrg",
- "--domain", "my-domain",
- "--tenant-id", "tenantId",
- "--client-id", "clientId"),
+ ArgConstants.Auth, "SingleOrg",
+ ArgConstants.Domain, "my-domain",
+ ArgConstants.TenantId, "tenantId",
+ ArgConstants.ClientId, "clientId"),
+ };
+
+ public static TheoryData TemplateDataSingleOrgProgramMain => new TheoryData
+ {
+ new TemplateInstance(
+ "blazorwasmhostedaad_program_main", "-ho",
+ ArgConstants.Auth, "SingleOrg",
+ ArgConstants.Domain, "my-domain",
+ ArgConstants.TenantId, "tenantId",
+ ArgConstants.ClientId, "clientId",
+ ArgConstants.DefaultScope, "full",
+ ArgConstants.AppIdUri, "ApiUri",
+ ArgConstants.AppIdClientId, "1234123413241324",
+ ArgConstants.UseProgramMain),
+ new TemplateInstance(
+ "blazorwasmhostedaadgraph_program_main", "-ho",
+ ArgConstants.Auth, "SingleOrg",
+ ArgConstants.CallsGraph,
+ ArgConstants.Domain, "my-domain",
+ ArgConstants.TenantId, "tenantId",
+ ArgConstants.ClientId, "clientId",
+ ArgConstants.DefaultScope, "full",
+ ArgConstants.AppIdUri, "ApiUri",
+ ArgConstants.AppIdClientId, "1234123413241324",
+ ArgConstants.UseProgramMain),
+ new TemplateInstance(
+ "blazorwasmhostedaadapi_program_main", "-ho",
+ ArgConstants.Auth, "SingleOrg",
+ ArgConstants.CalledApiUrl, "\"https://graph.microsoft.com\"",
+ ArgConstants.CalledApiScopes, "user.readwrite",
+ ArgConstants.Domain, "my-domain",
+ ArgConstants.TenantId, "tenantId",
+ ArgConstants.ClientId, "clientId",
+ ArgConstants.DefaultScope, "full",
+ ArgConstants.AppIdUri, "ApiUri",
+ ArgConstants.AppIdClientId, "1234123413241324",
+ ArgConstants.UseProgramMain),
+ new TemplateInstance(
+ "blazorwasmstandaloneaad_program_main",
+ ArgConstants.Auth, "SingleOrg",
+ ArgConstants.Domain, "my-domain",
+ ArgConstants.TenantId, "tenantId",
+ ArgConstants.ClientId, "clientId",
+ ArgConstants.UseProgramMain),
};
public class TemplateInstance
@@ -218,9 +295,19 @@ public TemplateInstance(string name, params string[] arguments)
}
[Theory]
- [MemberData(nameof(TemplateData))]
- public Task BlazorWasmHostedTemplate_AzureActiveDirectoryTemplate_Works(TemplateInstance instance)
- => CreateBuildPublishAsync(instance.Name, args: instance.Arguments, targetFramework: "netstandard2.1");
+ [MemberData(nameof(TemplateDataIndividualB2C))]
+ public Task BlazorWasmHostedTemplate_AzureActiveDirectoryTemplate_IndividualB2C_Works(TemplateInstance instance)
+ => CreateBuildPublishAsync(args: instance.Arguments, targetFramework: "netstandard2.1");
+
+ [Theory]
+ [MemberData(nameof(TemplateDataSingleOrg))]
+ public Task BlazorWasmHostedTemplate_AzureActiveDirectoryTemplate_SingleOrg_Works(TemplateInstance instance)
+ => CreateBuildPublishAsync(args: instance.Arguments, targetFramework: "netstandard2.1");
+
+ [Theory]
+ [MemberData(nameof(TemplateDataSingleOrgProgramMain))]
+ public Task BlazorWasmHostedTemplate_AzureActiveDirectoryTemplate_SingleOrg_ProgramMain_Works(TemplateInstance instance)
+ => CreateBuildPublishAsync(args: instance.Arguments, targetFramework: "netstandard2.1");
private string ReadFile(string basePath, string path)
{
diff --git a/src/ProjectTemplates/test/EmptyWebTemplateTest.cs b/src/ProjectTemplates/test/EmptyWebTemplateTest.cs
index 7468a587b41e..e350f65cb583 100644
--- a/src/ProjectTemplates/test/EmptyWebTemplateTest.cs
+++ b/src/ProjectTemplates/test/EmptyWebTemplateTest.cs
@@ -42,7 +42,7 @@ public async Task EmptyWebTemplateCSharp()
[SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
public async Task EmptyWebTemplateProgramMainCSharp()
{
- await EmtpyTemplateCore(languageOverride: null, args: new [] { "--use-program-main" });
+ await EmtpyTemplateCore(languageOverride: null, args: new[] { ArgConstants.UseProgramMain });
}
[Fact]
@@ -53,7 +53,7 @@ public async Task EmptyWebTemplateFSharp()
private async Task EmtpyTemplateCore(string languageOverride, string[] args = null)
{
- var project = await ProjectFactory.GetOrCreateProject("empty" + (languageOverride == "F#" ? "fsharp" : "csharp"), Output);
+ var project = await ProjectFactory.CreateProject(Output);
var createResult = await project.RunDotNetNewAsync("web", args: args, language: languageOverride);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
diff --git a/src/ProjectTemplates/test/GrpcTemplateTest.cs b/src/ProjectTemplates/test/GrpcTemplateTest.cs
index d26d0f8623a6..128ca22f4251 100644
--- a/src/ProjectTemplates/test/GrpcTemplateTest.cs
+++ b/src/ProjectTemplates/test/GrpcTemplateTest.cs
@@ -41,9 +41,9 @@ public ITestOutputHelper Output
[InlineData(false)]
public async Task GrpcTemplate(bool useProgramMain)
{
- var project = await ProjectFactory.GetOrCreateProject("grpc", Output);
+ var project = await ProjectFactory.CreateProject(Output);
- var args = useProgramMain ? new [] { "--use-program-main" } : null;
+ var args = useProgramMain ? new [] { ArgConstants.UseProgramMain } : null;
var createResult = await project.RunDotNetNewAsync("grpc", args: args);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
diff --git a/src/ProjectTemplates/test/IdentityUIPackageTest.cs b/src/ProjectTemplates/test/IdentityUIPackageTest.cs
index aa73178833a8..75b94f804a26 100644
--- a/src/ProjectTemplates/test/IdentityUIPackageTest.cs
+++ b/src/ProjectTemplates/test/IdentityUIPackageTest.cs
@@ -102,7 +102,7 @@ public ITestOutputHelper Output
public async Task IdentityUIPackage_WorksWithDifferentOptions()
{
var packageOptions = new Dictionary();
- var project = await ProjectFactory.GetOrCreateProject("identityuipackage" + string.Concat(packageOptions.Values), Output);
+ var project = await ProjectFactory.CreateProject(Output);
var useLocalDB = false;
var createResult = await project.RunDotNetNewAsync("razor", auth: "Individual", useLocalDB: useLocalDB, environmentVariables: packageOptions);
diff --git a/src/ProjectTemplates/test/ItemTemplateTests/BlazorServerTests.cs b/src/ProjectTemplates/test/ItemTemplateTests/BlazorServerTests.cs
index 3b97cfdaff78..af904522a756 100644
--- a/src/ProjectTemplates/test/ItemTemplateTests/BlazorServerTests.cs
+++ b/src/ProjectTemplates/test/ItemTemplateTests/BlazorServerTests.cs
@@ -25,7 +25,7 @@ public BlazorServerTest(ProjectFactoryFixture projectFactory, ITestOutputHelper
[Fact]
public async Task BlazorServerItemTemplate()
{
- Project = await ProjectFactory.GetOrCreateProject("razorcomponentitem", Output);
+ Project = await ProjectFactory.CreateProject(Output);
var createResult = await Project.RunDotNetNewAsync("razorcomponent --name Different");
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create", Project, createResult));
diff --git a/src/ProjectTemplates/test/MvcTemplateTest.cs b/src/ProjectTemplates/test/MvcTemplateTest.cs
index a5d6bec38066..8984c7bbd7bd 100644
--- a/src/ProjectTemplates/test/MvcTemplateTest.cs
+++ b/src/ProjectTemplates/test/MvcTemplateTest.cs
@@ -45,11 +45,11 @@ public ITestOutputHelper Output
[ConditionalFact]
[SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
- public async Task MvcTemplate_ProgramMainNoAuthCSharp() => await MvcTemplateCore(languageOverride: null, new [] { "--use-program-main" });
+ public async Task MvcTemplate_ProgramMainNoAuthCSharp() => await MvcTemplateCore(languageOverride: null, new [] { ArgConstants.UseProgramMain });
private async Task MvcTemplateCore(string languageOverride, string[] args = null)
{
- var project = await ProjectFactory.GetOrCreateProject("mvcnoauth" + (languageOverride == "F#" ? "fsharp" : "csharp"), Output);
+ var project = await ProjectFactory.CreateProject(Output);
var createResult = await project.RunDotNetNewAsync("mvc", language: languageOverride, args: args);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
@@ -120,16 +120,23 @@ private async Task MvcTemplateCore(string languageOverride, string[] args = null
}
[ConditionalTheory]
- [InlineData(true, false)]
- [InlineData(true, true)]
- [InlineData(false, false)]
- [InlineData(false, true)]
+ [InlineData(false)]
+ [InlineData(true)]
[SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
- public async Task MvcTemplate_IndividualAuth(bool useLocalDB, bool useProgramMain)
+ [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX, SkipReason = "No LocalDb on non-Windows")]
+ public Task MvcTemplate_IndividualAuth_LocalDb(bool useProgramMain) => MvcTemplate_IndividualAuth_Core(useLocalDB: true, useProgramMain);
+
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64 + HelixConstants.DebianAmd64)]
+ public Task MvcTemplate_IndividualAuth(bool useProgramMain) => MvcTemplate_IndividualAuth_Core(useLocalDB: false, useProgramMain);
+
+ private async Task MvcTemplate_IndividualAuth_Core(bool useLocalDB, bool useProgramMain)
{
- var project = await ProjectFactory.GetOrCreateProject("mvcindividual" + (useLocalDB ? "uld" : ""), Output);
+ var project = await ProjectFactory.CreateProject(Output);
- var args = useProgramMain ? new [] { "--use-program-main" } : null;
+ var args = useProgramMain ? new [] { ArgConstants.UseProgramMain } : null;
var createResult = await project.RunDotNetNewAsync("mvc", auth: "Individual", useLocalDB: useLocalDB, args: args);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
@@ -249,13 +256,13 @@ public async Task MvcTemplate_SingleFileExe()
// This test verifies publishing an MVC app as a single file exe works. We'll limit testing
// this to a few operating systems to make our lives easier.
var runtimeIdentifer = "win-x64";
- var project = await ProjectFactory.GetOrCreateProject("mvcsinglefileexe", Output);
+ var project = await ProjectFactory.CreateProject(Output);
project.RuntimeIdentifier = runtimeIdentifer;
var createResult = await project.RunDotNetNewAsync("mvc");
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
- var publishResult = await project.RunDotNetPublishAsync(additionalArgs: $"/p:PublishSingleFile=true -r {runtimeIdentifer}", noRestore: false);
+ var publishResult = await project.RunDotNetPublishAsync(additionalArgs: $"/p:PublishSingleFile=true -r {runtimeIdentifer} --self-contained", noRestore: false);
Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", project, publishResult));
var menuLinks = new[]
@@ -292,15 +299,24 @@ public async Task MvcTemplate_SingleFileExe()
[ConditionalTheory]
[SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/28090", Queues = HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
[InlineData("IndividualB2C", null)]
- [InlineData("IndividualB2C", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
+ [InlineData("IndividualB2C", new[] { ArgConstants.UseProgramMain })]
+ [InlineData("IndividualB2C", new[] { ArgConstants.CalledApiUrlGraphMicrosoftCom, ArgConstants.CalledApiScopesUserReadWrite })]
+ [InlineData("IndividualB2C", new[] { ArgConstants.UseProgramMain, ArgConstants.CalledApiUrlGraphMicrosoftCom, ArgConstants.CalledApiScopesUserReadWrite })]
+ public Task MvcTemplate_IdentityWeb_IndividualB2C_BuildsAndPublishes(string auth, string[] args) => MvcTemplateBuildsAndPublishes(auth: auth, args: args);
+
+ [ConditionalTheory]
+ [SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/28090", Queues = HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
[InlineData("SingleOrg", null)]
- [InlineData("SingleOrg", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
- [InlineData("SingleOrg", new string[] { "--calls-graph" })]
- public Task MvcTemplate_IdentityWeb_BuildsAndPublishes(string auth, string[] args) => MvcTemplateBuildsAndPublishes(auth: auth, args: args);
+ [InlineData("SingleOrg", new[] { ArgConstants.UseProgramMain })]
+ [InlineData("SingleOrg", new[] { ArgConstants.CalledApiUrlGraphMicrosoftCom, ArgConstants.CalledApiScopesUserReadWrite })]
+ [InlineData("SingleOrg", new[] { ArgConstants.UseProgramMain, ArgConstants.CalledApiUrlGraphMicrosoftCom, ArgConstants.CalledApiScopesUserReadWrite })]
+ [InlineData("SingleOrg", new[] { ArgConstants.CallsGraph })]
+ [InlineData("SingleOrg", new[] { ArgConstants.UseProgramMain, ArgConstants.CallsGraph })]
+ public Task MvcTemplate_IdentityWeb_SingleOrg_BuildsAndPublishes(string auth, string[] args) => MvcTemplateBuildsAndPublishes(auth: auth, args: args);
private async Task MvcTemplateBuildsAndPublishes(string auth, string[] args)
{
- var project = await ProjectFactory.GetOrCreateProject("mvc" + Guid.NewGuid().ToString().Substring(0, 10).ToLowerInvariant(), Output);
+ var project = await ProjectFactory.CreateProject(Output);
var createResult = await project.RunDotNetNewAsync("mvc", auth: auth, args: args);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
diff --git a/src/ProjectTemplates/test/ProjectTemplates.Tests.csproj b/src/ProjectTemplates/test/ProjectTemplates.Tests.csproj
index 8a9e1fa661cd..9f3a2986b389 100644
--- a/src/ProjectTemplates/test/ProjectTemplates.Tests.csproj
+++ b/src/ProjectTemplates/test/ProjectTemplates.Tests.csproj
@@ -19,6 +19,9 @@
TestTemplates\
$([MSBuild]::EnsureTrailingSlash('$(RepoRoot)'))obj\template-restore\
true
+
+ $(HelixQueueArmDebian11);
+
diff --git a/src/ProjectTemplates/test/RazorClassLibraryTemplateTest.cs b/src/ProjectTemplates/test/RazorClassLibraryTemplateTest.cs
index 4a547b2377fe..5c84f9135dec 100644
--- a/src/ProjectTemplates/test/RazorClassLibraryTemplateTest.cs
+++ b/src/ProjectTemplates/test/RazorClassLibraryTemplateTest.cs
@@ -33,7 +33,7 @@ public ITestOutputHelper Output
[Fact]
public async Task RazorClassLibraryTemplate_WithViews_Async()
{
- var project = await ProjectFactory.GetOrCreateProject("razorclasslibwithviews", Output);
+ var project = await ProjectFactory.CreateProject(Output);
var createResult = await project.RunDotNetNewAsync("razorclasslib", args: new[] { "--support-pages-and-views", "true" });
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
@@ -53,7 +53,7 @@ public async Task RazorClassLibraryTemplate_WithViews_Async()
[SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/28090", Queues = HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
public async Task RazorClassLibraryTemplateAsync()
{
- var project = await ProjectFactory.GetOrCreateProject("razorclasslib", Output);
+ var project = await ProjectFactory.CreateProject(Output);
var createResult = await project.RunDotNetNewAsync("razorclasslib");
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
diff --git a/src/ProjectTemplates/test/RazorPagesTemplateTest.cs b/src/ProjectTemplates/test/RazorPagesTemplateTest.cs
index 3412233f5dd5..ca1affdcadf1 100644
--- a/src/ProjectTemplates/test/RazorPagesTemplateTest.cs
+++ b/src/ProjectTemplates/test/RazorPagesTemplateTest.cs
@@ -40,9 +40,9 @@ public ITestOutputHelper Output
[InlineData(false)]
public async Task RazorPagesTemplate_NoAuth(bool useProgramMain)
{
- var project = await ProjectFactory.GetOrCreateProject("razorpagesnoauth", Output);
+ var project = await ProjectFactory.CreateProject(Output);
- var args = useProgramMain ? new [] { "--use-program-main" } : null;
+ var args = useProgramMain ? new [] { ArgConstants.UseProgramMain } : null;
var createResult = await project.RunDotNetNewAsync("razor", args: args);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("razor", project, createResult));
@@ -107,16 +107,23 @@ public async Task RazorPagesTemplate_NoAuth(bool useProgramMain)
}
[ConditionalTheory]
- [InlineData(false, false)]
- [InlineData(false, true)]
- [InlineData(true, false)]
- [InlineData(true, true)]
- [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
- public async Task RazorPagesTemplate_IndividualAuth(bool useLocalDB, bool useProgramMain)
+ [InlineData(false)]
+ [InlineData(true)]
+ [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64 + HelixConstants.DebianAmd64)]
+ [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX, SkipReason = "No LocalDb on non-Windows")]
+ public Task RazorPagesTemplate_IndividualAuth_LocalDb(bool useProgramMain) => RazorPagesTemplate_IndividualAuth_Core(useLocalDB: true, useProgramMain);
+
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64 + HelixConstants.DebianAmd64)]
+ public Task RazorPagesTemplate_IndividualAuth(bool useProgramMain) => RazorPagesTemplate_IndividualAuth_Core(useLocalDB: false, useProgramMain);
+
+ private async Task RazorPagesTemplate_IndividualAuth_Core(bool useLocalDB, bool useProgramMain)
{
- var project = await ProjectFactory.GetOrCreateProject("razorpagesindividual" + (useLocalDB ? "uld" : ""), Output);
+ var project = await ProjectFactory.CreateProject(Output);
- var args = useProgramMain ? new [] { "--use-program-main" } : null;
+ var args = useProgramMain ? new [] { ArgConstants.UseProgramMain } : null;
var createResult = await project.RunDotNetNewAsync("razor", auth: "Individual", useLocalDB: useLocalDB, args: args);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
@@ -231,21 +238,27 @@ public async Task RazorPagesTemplate_IndividualAuth(bool useLocalDB, bool usePro
[ConditionalTheory]
[SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/28090", Queues = HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
[InlineData("IndividualB2C", null)]
- [InlineData("IndividualB2C", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
- [InlineData("IndividualB2C", new string[] { "--use-program-main --called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
+ [InlineData("IndividualB2C", new[] { ArgConstants.UseProgramMain })]
+ [InlineData("IndividualB2C", new[] { ArgConstants.CalledApiUrlGraphMicrosoftCom, ArgConstants.CalledApiScopesUserReadWrite })]
+ [InlineData("IndividualB2C", new[] { ArgConstants.UseProgramMain, ArgConstants.CalledApiUrlGraphMicrosoftCom, ArgConstants.CalledApiScopesUserReadWrite })]
+ public Task RazorPagesTemplate_IdentityWeb_IndividualB2C_BuildsAndPublishes(string auth, string[] args) => BuildAndPublishRazorPagesTemplate(auth: auth, args: args);
+
+ [ConditionalTheory]
+ [SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/28090", Queues = HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
[InlineData("SingleOrg", null)]
- [InlineData("SingleOrg", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
- [InlineData("SingleOrg", new string[] { "--use-program-main --called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
- public Task RazorPagesTemplate_IdentityWeb_BuildsAndPublishes(string auth, string[] args) => BuildAndPublishRazorPagesTemplate(auth: auth, args: args);
+ [InlineData("SingleOrg", new[] { ArgConstants.UseProgramMain })]
+ [InlineData("SingleOrg", new[] { ArgConstants.CalledApiUrlGraphMicrosoftCom, ArgConstants.CalledApiScopesUserReadWrite })]
+ [InlineData("SingleOrg", new[] { ArgConstants.UseProgramMain, ArgConstants.CalledApiUrlGraphMicrosoftCom, ArgConstants.CalledApiScopesUserReadWrite })]
+ public Task RazorPagesTemplate_IdentityWeb_SingleOrg_BuildsAndPublishes(string auth, string[] args) => BuildAndPublishRazorPagesTemplate(auth: auth, args: args);
[ConditionalTheory]
- [InlineData("SingleOrg", new string[] { "--calls-graph" })]
- [InlineData("SingleOrg", new string[] { "--use-program-main --calls-graph" })]
- public Task RazorPagesTemplate_IdentityWeb_BuildsAndPublishes_WithSingleOrg(string auth, string[] args) => BuildAndPublishRazorPagesTemplate(auth: auth, args: args);
+ [InlineData("SingleOrg", new[] { ArgConstants.CallsGraph })]
+ [InlineData("SingleOrg", new[] { ArgConstants.UseProgramMain, ArgConstants.CallsGraph })]
+ public Task RazorPagesTemplate_IdentityWeb_SingleOrg_CallsGraph_BuildsAndPublishes(string auth, string[] args) => BuildAndPublishRazorPagesTemplate(auth: auth, args: args);
private async Task BuildAndPublishRazorPagesTemplate(string auth, string[] args)
{
- var project = await ProjectFactory.GetOrCreateProject("razorpages" + Guid.NewGuid().ToString().Substring(0, 10).ToLowerInvariant(), Output);
+ var project = await ProjectFactory.CreateProject(Output);
var createResult = await project.RunDotNetNewAsync("razor", auth: auth, args: args);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
diff --git a/src/ProjectTemplates/test/SpaTemplatesTest.cs b/src/ProjectTemplates/test/SpaTemplatesTest.cs
index c5271f7f7ebd..a990217047d5 100644
--- a/src/ProjectTemplates/test/SpaTemplatesTest.cs
+++ b/src/ProjectTemplates/test/SpaTemplatesTest.cs
@@ -35,13 +35,13 @@ public ITestOutputHelper Output
}
[Theory]
- [InlineData("angularind", "angular", "Individual")]
- [InlineData("reactind", "react", "Individual")]
- [InlineData("angularnoauth", "angular", null)]
- [InlineData("reactnoauth", "react", null)]
- public async Task SpaTemplates_BuildAndPublish(string projectKey, string template, string auth)
+ [InlineData("angular", "Individual")]
+ [InlineData("react", "Individual")]
+ [InlineData("angular", null)]
+ [InlineData("react", null)]
+ public async Task SpaTemplates_BuildAndPublish(string template, string auth)
{
- var project = await ProjectFactory.GetOrCreateProject(projectKey, Output);
+ var project = await ProjectFactory.CreateProject(Output);
var args = new[] { "--NoSpaFrontEnd", "true" };
var createResult = await project.RunDotNetNewAsync(template, auth: auth, args: args);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage(template, project, createResult));
diff --git a/src/ProjectTemplates/test/WebApiTemplateTest.cs b/src/ProjectTemplates/test/WebApiTemplateTest.cs
index f727abcc92c0..95b483311466 100644
--- a/src/ProjectTemplates/test/WebApiTemplateTest.cs
+++ b/src/ProjectTemplates/test/WebApiTemplateTest.cs
@@ -35,16 +35,40 @@ public ITestOutputHelper Output
[ConditionalTheory]
[SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/28090", Queues = HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
[InlineData("IndividualB2C", null)]
- [InlineData("IndividualB2C", new string[] { "--use-program-main" })]
- [InlineData("IndividualB2C", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
- [InlineData("IndividualB2C", new string[] { "--use-program-main --called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
+ [InlineData("IndividualB2C", new string[] { ArgConstants.UseMinimalApis })]
+ [InlineData("IndividualB2C", new string[] { ArgConstants.CalledApiUrlGraphMicrosoftCom, ArgConstants.CalledApiScopesUserReadWrite })]
+ [InlineData("IndividualB2C", new string[] { ArgConstants.UseMinimalApis, ArgConstants.CalledApiUrlGraphMicrosoftCom, ArgConstants.CalledApiScopesUserReadWrite })]
+ public Task WebApiTemplateCSharp_IdentityWeb_IndividualB2C_BuildsAndPublishes(string auth, string[] args) => PublishAndBuildWebApiTemplate(languageOverride: null, auth: auth, args: args);
+
+ [ConditionalTheory]
+ [SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/28090", Queues = HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
+ [InlineData("IndividualB2C", null)]
+ [InlineData("IndividualB2C", new string[] { ArgConstants.UseProgramMain })]
+ [InlineData("IndividualB2C", new string[] { ArgConstants.UseProgramMain, ArgConstants.UseMinimalApis })]
+ [InlineData("IndividualB2C", new string[] { ArgConstants.UseProgramMain, ArgConstants.CalledApiUrlGraphMicrosoftCom, ArgConstants.CalledApiScopesUserReadWrite })]
+ [InlineData("IndividualB2C", new string[] { ArgConstants.UseProgramMain, ArgConstants.UseMinimalApis, ArgConstants.CalledApiUrlGraphMicrosoftCom, ArgConstants.CalledApiScopesUserReadWrite })]
+ public Task WebApiTemplateCSharp_IdentityWeb_IndividualB2C_ProgramMain_BuildsAndPublishes(string auth, string[] args) => PublishAndBuildWebApiTemplate(languageOverride: null, auth: auth, args: args);
+
+ [ConditionalTheory]
+ [SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/28090", Queues = HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
+ [InlineData("SingleOrg", null)]
+ [InlineData("SingleOrg", new string[] { ArgConstants.UseMinimalApis })]
+ [InlineData("SingleOrg", new string[] { ArgConstants.CalledApiUrlGraphMicrosoftCom, ArgConstants.CalledApiScopesUserReadWrite })]
+ [InlineData("SingleOrg", new string[] { ArgConstants.UseMinimalApis, ArgConstants.CalledApiUrlGraphMicrosoftCom, ArgConstants.CalledApiScopesUserReadWrite })]
+ [InlineData("SingleOrg", new string[] { ArgConstants.CallsGraph })]
+ [InlineData("SingleOrg", new string[] { ArgConstants.UseMinimalApis, ArgConstants.CallsGraph })]
+ public Task WebApiTemplateCSharp_IdentityWeb_SingleOrg_BuildsAndPublishes(string auth, string[] args) => PublishAndBuildWebApiTemplate(languageOverride: null, auth: auth, args: args);
+
+ [ConditionalTheory]
+ [SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/28090", Queues = HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
[InlineData("SingleOrg", null)]
- [InlineData("SingleOrg", new string[] { "--use-program-main" })]
- [InlineData("SingleOrg", new string[] { "--called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
- [InlineData("SingleOrg", new string[] { "--use-program-main --called-api-url \"https://graph.microsoft.com\"", "--called-api-scopes user.readwrite" })]
- [InlineData("SingleOrg", new string[] { "--calls-graph" })]
- [InlineData("SingleOrg", new string[] { "--use-program-main --calls-graph" })]
- public Task WebApiTemplateCSharp_IdentityWeb_BuildsAndPublishes(string auth, string[] args) => PublishAndBuildWebApiTemplate(languageOverride: null, auth: auth, args: args);
+ [InlineData("SingleOrg", new string[] { ArgConstants.UseProgramMain })]
+ [InlineData("SingleOrg", new string[] { ArgConstants.UseProgramMain, ArgConstants.UseMinimalApis })]
+ [InlineData("SingleOrg", new string[] { ArgConstants.UseProgramMain, ArgConstants.CalledApiUrlGraphMicrosoftCom, ArgConstants.CalledApiScopesUserReadWrite })]
+ [InlineData("SingleOrg", new string[] { ArgConstants.UseProgramMain, ArgConstants.UseMinimalApis, ArgConstants.CalledApiUrlGraphMicrosoftCom, ArgConstants.CalledApiScopesUserReadWrite })]
+ [InlineData("SingleOrg", new string[] { ArgConstants.UseProgramMain, ArgConstants.CallsGraph })]
+ [InlineData("SingleOrg", new string[] { ArgConstants.UseProgramMain, ArgConstants.UseMinimalApis, ArgConstants.CallsGraph })]
+ public Task WebApiTemplateCSharp_IdentityWeb_SingleOrg_ProgramMain_BuildsAndPublishes(string auth, string[] args) => PublishAndBuildWebApiTemplate(languageOverride: null, auth: auth, args: args);
[Fact]
public Task WebApiTemplateFSharp() => WebApiTemplateCore(languageOverride: "F#");
@@ -55,17 +79,33 @@ public ITestOutputHelper Output
[ConditionalFact]
[SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
- public Task WebApiTemplateProgramMainCSharp() => WebApiTemplateCore(languageOverride: null, args: new [] { "--use-program-main" });
+ public Task WebApiTemplateProgramMainCSharp() => WebApiTemplateCore(languageOverride: null, args: new [] { ArgConstants.UseProgramMain });
+
+ [ConditionalFact]
+ [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
+ public Task WebApiTemplateMinimalApisCSharp() => WebApiTemplateCore(languageOverride: null, args: new[] { ArgConstants.UseMinimalApis });
+
+ [ConditionalFact]
+ [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
+ public Task WebApiTemplateProgramMainMinimalApisCSharp() => WebApiTemplateCore(languageOverride: null, args: new[] { ArgConstants.UseProgramMain, ArgConstants.UseMinimalApis });
[ConditionalTheory]
- [InlineData(false)]
- [InlineData(true)]
+ [InlineData(false, false)]
+ [InlineData(false, true)]
+ [InlineData(true, true)]
+ [InlineData(true, false)]
[SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
- public async Task WebApiTemplateCSharp_WithoutOpenAPI(bool useProgramMain)
+ public async Task WebApiTemplateCSharp_WithoutOpenAPI(bool useProgramMain, bool useMinimalApis)
{
- var project = await FactoryFixture.GetOrCreateProject("webapinoopenapi", Output);
-
- var args = useProgramMain ? new[] { "--use-program-main --no-openapi" } : new[] { "--no-openapi" };
+ var project = await FactoryFixture.CreateProject(Output);
+
+ var args = useProgramMain
+ ? useMinimalApis
+ ? new[] { ArgConstants.UseProgramMain, ArgConstants.UseMinimalApis, ArgConstants.NoOpenApi }
+ : new[] { ArgConstants.UseProgramMain, ArgConstants.NoOpenApi }
+ : useMinimalApis
+ ? new[] { ArgConstants.UseMinimalApis, ArgConstants.NoOpenApi }
+ : new[] { ArgConstants.NoOpenApi };
var createResult = await project.RunDotNetNewAsync("webapi", args: args);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
diff --git a/src/ProjectTemplates/test/WorkerTemplateTest.cs b/src/ProjectTemplates/test/WorkerTemplateTest.cs
index ba82b5073c0e..60b3f519040b 100644
--- a/src/ProjectTemplates/test/WorkerTemplateTest.cs
+++ b/src/ProjectTemplates/test/WorkerTemplateTest.cs
@@ -33,14 +33,12 @@ public ITestOutputHelper Output
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux, SkipReason = "https://github.com/dotnet/sdk/issues/12831")]
[InlineData("C#", null)]
- [InlineData("C#", new string[] { "--use-program-main" })]
+ [InlineData("C#", new string[] { ArgConstants.UseProgramMain })]
[InlineData("F#", null)]
[QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/25404")]
public async Task WorkerTemplateAsync(string language, string[] args)
{
- var project = await ProjectFactory.GetOrCreateProject(
- $"worker-{ language.ToLowerInvariant()[0] }sharp",
- Output);
+ var project = await ProjectFactory.CreateProject(Output);
var createResult = await project.RunDotNetNewAsync("worker", language: language, args: args);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
diff --git a/src/ProjectTemplates/test/template-baselines.json b/src/ProjectTemplates/test/template-baselines.json
index b707dcd78819..4c364f3b9298 100644
--- a/src/ProjectTemplates/test/template-baselines.json
+++ b/src/ProjectTemplates/test/template-baselines.json
@@ -541,6 +541,19 @@
],
"AuthOption": "IndividualB2C"
},
+ "IndividualB2CProgramMain": {
+ "Template": "webapi",
+ "Arguments": "new webapi -au IndividualB2C --use-program-main --aad-b2c-instance https://login.microsoftonline.com/tfp/ --domain fake-b2c-domain.onmicrosoft.com --client-id 64f31f76-2750-49e4-aab9-f5de105b5172 -ssp B2C_1_SiUpIn",
+ "Files": [
+ "appsettings.Development.json",
+ "appsettings.json",
+ "Program.cs",
+ "WeatherForecast.cs",
+ "Controllers/WeatherForecastController.cs",
+ "Properties/launchSettings.json"
+ ],
+ "AuthOption": "IndividualB2C"
+ },
"SingleOrg": {
"Template": "webapi",
"Arguments": "new webapi -au SingleOrg --aad-instance https://login.microsoftonline.com/ --domain fake-aad-domain.onmicrosoft.com --client-id db33c356-12cc-4953-9167-00ad56c2e8b2 --tenant-id 7e511586-66ec-4108-bc9c-a68dee0dc2aa",
@@ -554,6 +567,19 @@
],
"AuthOption": "SingleOrg"
},
+ "SingleOrgProgramMain": {
+ "Template": "webapi",
+ "Arguments": "new webapi -au SingleOrg --use-program-main --aad-instance https://login.microsoftonline.com/ --domain fake-aad-domain.onmicrosoft.com --client-id db33c356-12cc-4953-9167-00ad56c2e8b2 --tenant-id 7e511586-66ec-4108-bc9c-a68dee0dc2aa",
+ "Files": [
+ "appsettings.Development.json",
+ "appsettings.json",
+ "Program.cs",
+ "WeatherForecast.cs",
+ "Controllers/WeatherForecastController.cs",
+ "Properties/launchSettings.json"
+ ],
+ "AuthOption": "SingleOrg"
+ },
"None": {
"Template": "webapi",
"Arguments": "new webapi -au None",
@@ -567,6 +593,19 @@
],
"AuthOption": "None"
},
+ "NoneProgramMain": {
+ "Template": "webapi",
+ "Arguments": "new webapi -au None --use-program-main",
+ "Files": [
+ "appsettings.Development.json",
+ "appsettings.json",
+ "Program.cs",
+ "WeatherForecast.cs",
+ "Controllers/WeatherForecastController.cs",
+ "Properties/launchSettings.json"
+ ],
+ "AuthOption": "None"
+ },
"MinimalIndividualB2C": {
"Template": "webapi",
"Arguments": "new webapi -minimal -au IndividualB2C --aad-b2c-instance https://login.microsoftonline.com/tfp/ --domain fake-b2c-domain.onmicrosoft.com --client-id 64f31f76-2750-49e4-aab9-f5de105b5172 -ssp B2C_1_SiUpIn",
@@ -578,6 +617,18 @@
],
"AuthOption": "IndividualB2C"
},
+ "MinimalIndividualB2CProgramMain": {
+ "Template": "webapi",
+ "Arguments": "new webapi -minimal --use-program-main -au IndividualB2C --aad-b2c-instance https://login.microsoftonline.com/tfp/ --domain fake-b2c-domain.onmicrosoft.com --client-id 64f31f76-2750-49e4-aab9-f5de105b5172 -ssp B2C_1_SiUpIn",
+ "Files": [
+ "appsettings.Development.json",
+ "appsettings.json",
+ "Program.cs",
+ "WeatherForecast.cs",
+ "Properties/launchSettings.json"
+ ],
+ "AuthOption": "IndividualB2C"
+ },
"MinimalSingleOrg": {
"Template": "webapi",
"Arguments": "new webapi -minimal -au SingleOrg --aad-instance https://login.microsoftonline.com/ --domain fake-aad-domain.onmicrosoft.com --client-id db33c356-12cc-4953-9167-00ad56c2e8b2 --tenant-id 7e511586-66ec-4108-bc9c-a68dee0dc2aa",
@@ -589,6 +640,18 @@
],
"AuthOption": "SingleOrg"
},
+ "MinimalSingleOrgProgramMain": {
+ "Template": "webapi",
+ "Arguments": "new webapi -minimal --use-program-main -au SingleOrg --aad-instance https://login.microsoftonline.com/ --domain fake-aad-domain.onmicrosoft.com --client-id db33c356-12cc-4953-9167-00ad56c2e8b2 --tenant-id 7e511586-66ec-4108-bc9c-a68dee0dc2aa",
+ "Files": [
+ "appsettings.Development.json",
+ "appsettings.json",
+ "Program.cs",
+ "WeatherForecast.cs",
+ "Properties/launchSettings.json"
+ ],
+ "AuthOption": "SingleOrg"
+ },
"Minimal": {
"Template": "webapi",
"Arguments": "new webapi -minimal -au None",
@@ -600,6 +663,18 @@
],
"AuthOption": "None"
},
+ "MinimalProgramMain": {
+ "Template": "webapi",
+ "Arguments": "new webapi -minimal --use-program-main -au None",
+ "Files": [
+ "appsettings.Development.json",
+ "appsettings.json",
+ "Program.cs",
+ "WeatherForecast.cs",
+ "Properties/launchSettings.json"
+ ],
+ "AuthOption": "None"
+ },
"Windows": {
"Template": "webapi",
"Arguments": "new webapi -au Windows",
@@ -613,6 +688,19 @@
],
"AuthOption": "Windows"
},
+ "WindowsProgramMain": {
+ "Template": "webapi",
+ "Arguments": "new webapi -au Windows --use-program-main",
+ "Files": [
+ "appsettings.Development.json",
+ "appsettings.json",
+ "Program.cs",
+ "WeatherForecast.cs",
+ "Controllers/WeatherForecastController.cs",
+ "Properties/launchSettings.json"
+ ],
+ "AuthOption": "Windows"
+ },
"MinimalWindows": {
"Template": "webapi",
"Arguments": "new webapi -minimal -au Windows",
@@ -624,6 +712,18 @@
],
"AuthOption": "Windows"
},
+ "MinimalWindowsProgramMain": {
+ "Template": "webapi",
+ "Arguments": "new webapi -minimal --use-program-main -au Windows",
+ "Files": [
+ "appsettings.Development.json",
+ "appsettings.json",
+ "Program.cs",
+ "WeatherForecast.cs",
+ "Properties/launchSettings.json"
+ ],
+ "AuthOption": "Windows"
+ },
"FSharp": {
"Template": "webapi",
"Arguments": "new webapi --language F#",
@@ -1569,6 +1669,7 @@
"ClientApp/src/custom.css",
"ClientApp/src/App.js",
"ClientApp/src/App.test.js",
+ "ClientApp/src/AppRoutes.js",
"ClientApp/src/index.js",
"ClientApp/src/reportWebVitals.js",
"ClientApp/src/serviceWorkerRegistration.js",
diff --git a/src/ProjectTemplates/test/yarn.lock b/src/ProjectTemplates/test/yarn.lock
index 136eccbe7f67..8eb6533d4475 100644
--- a/src/ProjectTemplates/test/yarn.lock
+++ b/src/ProjectTemplates/test/yarn.lock
@@ -254,9 +254,9 @@ mimic-response@^3.1.0:
integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
minimist@^1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
- integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
+ integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
mkdirp@^1.0.4:
version "1.0.4"
diff --git a/src/Servers/HttpSys/src/RequestProcessing/RequestStream.cs b/src/Servers/HttpSys/src/RequestProcessing/RequestStream.cs
index b4de879f24ba..d1971c53b026 100644
--- a/src/Servers/HttpSys/src/RequestProcessing/RequestStream.cs
+++ b/src/Servers/HttpSys/src/RequestProcessing/RequestStream.cs
@@ -102,11 +102,11 @@ private void ValidateReadBuffer(byte[] buffer, int offset, int size)
{
throw new ArgumentNullException(nameof(buffer));
}
- if (offset < 0 || offset > buffer.Length)
+ if ((uint)offset > (uint)buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset), offset, string.Empty);
}
- if (size <= 0 || size > buffer.Length - offset)
+ if ((uint)size > (uint)(buffer.Length - offset))
{
throw new ArgumentOutOfRangeException(nameof(size), size, string.Empty);
}
@@ -163,7 +163,14 @@ public override unsafe int Read([In, Out] byte[] buffer, int offset, int size)
dataRead += extraDataRead;
}
- if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF)
+
+ // Zero-byte reads
+ if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA && size == 0)
+ {
+ // extraDataRead returns 1 to let us know there's data available. Don't count it against the request body size yet.
+ dataRead = 0;
+ }
+ else if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF)
{
Exception exception = new IOException(string.Empty, new HttpSysException((int)statusCode));
Log.ErrorWhileRead(Logger, exception);
@@ -183,7 +190,8 @@ public override unsafe int Read([In, Out] byte[] buffer, int offset, int size)
internal void UpdateAfterRead(uint statusCode, uint dataRead)
{
- if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF || dataRead == 0)
+ if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF
+ || statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA && dataRead == 0)
{
Dispose();
}
@@ -244,7 +252,7 @@ public override unsafe Task ReadAsync(byte[] buffer, int offset, int size,
cancellationRegistration = RequestContext.RegisterForCancellation(cancellationToken);
}
- asyncResult = new RequestStreamAsyncResult(this, null, null, buffer, offset, dataRead, cancellationRegistration);
+ asyncResult = new RequestStreamAsyncResult(this, null, null, buffer, offset, size, dataRead, cancellationRegistration);
uint bytesReturned;
try
diff --git a/src/Servers/HttpSys/src/RequestProcessing/RequestStreamAsyncResult.cs b/src/Servers/HttpSys/src/RequestProcessing/RequestStreamAsyncResult.cs
index e5fbc69ba72d..e51128e9989a 100644
--- a/src/Servers/HttpSys/src/RequestProcessing/RequestStreamAsyncResult.cs
+++ b/src/Servers/HttpSys/src/RequestProcessing/RequestStreamAsyncResult.cs
@@ -17,38 +17,24 @@ internal unsafe class RequestStreamAsyncResult : IAsyncResult, IDisposable
private readonly SafeNativeOverlapped? _overlapped;
private readonly IntPtr _pinnedBuffer;
+ private readonly int _size;
private readonly uint _dataAlreadyRead;
private readonly TaskCompletionSource _tcs;
private readonly RequestStream _requestStream;
private readonly AsyncCallback? _callback;
private readonly CancellationTokenRegistration _cancellationRegistration;
- internal RequestStreamAsyncResult(RequestStream requestStream, object? userState, AsyncCallback? callback)
+ internal RequestStreamAsyncResult(RequestStream requestStream, object? userState, AsyncCallback? callback, byte[] buffer, int offset, int size, uint dataAlreadyRead, CancellationTokenRegistration cancellationRegistration)
{
_requestStream = requestStream;
_tcs = new TaskCompletionSource(userState);
_callback = callback;
- }
-
- internal RequestStreamAsyncResult(RequestStream requestStream, object? userState, AsyncCallback? callback, uint dataAlreadyRead)
- : this(requestStream, userState, callback)
- {
- _dataAlreadyRead = dataAlreadyRead;
- }
-
- internal RequestStreamAsyncResult(RequestStream requestStream, object? userState, AsyncCallback? callback, byte[] buffer, int offset, uint dataAlreadyRead)
- : this(requestStream, userState, callback, buffer, offset, dataAlreadyRead, new CancellationTokenRegistration())
- {
- }
-
- internal RequestStreamAsyncResult(RequestStream requestStream, object? userState, AsyncCallback? callback, byte[] buffer, int offset, uint dataAlreadyRead, CancellationTokenRegistration cancellationRegistration)
- : this(requestStream, userState, callback)
- {
_dataAlreadyRead = dataAlreadyRead;
var boundHandle = requestStream.RequestContext.Server.RequestQueue.BoundHandle;
_overlapped = new SafeNativeOverlapped(boundHandle,
boundHandle.AllocateNativeOverlapped(IOCallback, this, buffer));
_pinnedBuffer = (Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset));
+ _size = size;
_cancellationRegistration = cancellationRegistration;
}
@@ -87,7 +73,13 @@ private static void IOCompleted(RequestStreamAsyncResult asyncResult, uint error
{
try
{
- if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF)
+ // Zero-byte reads
+ if (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA && asyncResult._size == 0)
+ {
+ // numBytes returns 1 to let us know there's data available. Don't count it against the request body size yet.
+ asyncResult.Complete(0, errorCode);
+ }
+ else if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF)
{
asyncResult.Fail(new IOException(string.Empty, new HttpSysException((int)errorCode)));
}
diff --git a/src/Servers/HttpSys/test/FunctionalTests/RequestBodyTests.cs b/src/Servers/HttpSys/test/FunctionalTests/RequestBodyTests.cs
index f9817310f4cb..ba1bb65da674 100644
--- a/src/Servers/HttpSys/test/FunctionalTests/RequestBodyTests.cs
+++ b/src/Servers/HttpSys/test/FunctionalTests/RequestBodyTests.cs
@@ -39,6 +39,28 @@ public async Task RequestBody_ReadSync_Success()
}
}
+ [ConditionalFact]
+ public async Task RequestBody_Read0ByteSync_Success()
+ {
+ string address;
+ using (Utilities.CreateHttpServer(out address, httpContext =>
+ {
+ Assert.True(httpContext.Request.CanHaveBody());
+ byte[] input = new byte[100];
+ httpContext.Features.Get().AllowSynchronousIO = true;
+ int read = httpContext.Request.Body.Read(input, 0, 0);
+ Assert.Equal(0, read);
+ read = httpContext.Request.Body.Read(input, 0, input.Length);
+ httpContext.Response.ContentLength = read;
+ httpContext.Response.Body.Write(input, 0, read);
+ return Task.FromResult(0);
+ }))
+ {
+ string response = await SendRequestAsync(address, "Hello World");
+ Assert.Equal("Hello World", response);
+ }
+ }
+
[ConditionalFact]
public async Task RequestBody_ReadAsync_Success()
{
@@ -57,6 +79,29 @@ public async Task RequestBody_ReadAsync_Success()
}
}
+ [ConditionalFact]
+ public async Task RequestBody_Read0ByteAsync_Success()
+ {
+ string address;
+ using (Utilities.CreateHttpServer(out address, async httpContext =>
+ {
+ Assert.True(httpContext.Request.CanHaveBody());
+ byte[] input = new byte[100];
+ await Task.Delay(1000);
+ int read = await httpContext.Request.Body.ReadAsync(input, 0, 1);
+ Assert.Equal(1, read);
+ read = await httpContext.Request.Body.ReadAsync(input, 0, 0);
+ Assert.Equal(0, read);
+ read = await httpContext.Request.Body.ReadAsync(input, 1, input.Length - 1);
+ httpContext.Response.ContentLength = read + 1;
+ await httpContext.Response.Body.WriteAsync(input, 0, read + 1);
+ }))
+ {
+ string response = await SendRequestAsync(address, "Hello World");
+ Assert.Equal("Hello World", response);
+ }
+ }
+
[ConditionalFact]
public async Task RequestBody_ReadBeginEnd_Success()
{
@@ -87,7 +132,6 @@ public async Task RequestBody_InvalidBuffer_ArgumentException()
Assert.Throws("offset", () => httpContext.Request.Body.Read(input, -1, 1));
Assert.Throws("offset", () => httpContext.Request.Body.Read(input, input.Length + 1, 1));
Assert.Throws("size", () => httpContext.Request.Body.Read(input, 10, -1));
- Assert.Throws("size", () => httpContext.Request.Body.Read(input, 0, 0));
Assert.Throws("size", () => httpContext.Request.Body.Read(input, 1, input.Length));
Assert.Throws("size", () => httpContext.Request.Body.Read(input, 0, input.Length + 1));
return Task.FromResult(0);
diff --git a/src/Servers/IIS/IIS/samples/NativeIISSample/NativeIISSample.csproj b/src/Servers/IIS/IIS/samples/NativeIISSample/NativeIISSample.csproj
index fa97a75dd5b0..ecde817e707f 100644
--- a/src/Servers/IIS/IIS/samples/NativeIISSample/NativeIISSample.csproj
+++ b/src/Servers/IIS/IIS/samples/NativeIISSample/NativeIISSample.csproj
@@ -14,6 +14,7 @@
+
diff --git a/src/Servers/IIS/IIS/src/Core/IISHttpContext.IO.cs b/src/Servers/IIS/IIS/src/Core/IISHttpContext.IO.cs
index e8ca5be68676..9a456258161e 100644
--- a/src/Servers/IIS/IIS/src/Core/IISHttpContext.IO.cs
+++ b/src/Servers/IIS/IIS/src/Core/IISHttpContext.IO.cs
@@ -162,6 +162,11 @@ private async Task WriteBody(bool flush = false)
var buffer = result.Buffer;
try
{
+ if (_bodyOutput.Aborted)
+ {
+ break;
+ }
+
if (!buffer.IsEmpty)
{
await AsyncIO!.WriteAsync(buffer);
diff --git a/src/Servers/IIS/IIS/src/Core/OutputProducer.cs b/src/Servers/IIS/IIS/src/Core/OutputProducer.cs
index 8bf887d1b86a..3b52dc8e284d 100644
--- a/src/Servers/IIS/IIS/src/Core/OutputProducer.cs
+++ b/src/Servers/IIS/IIS/src/Core/OutputProducer.cs
@@ -13,9 +13,10 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
{
internal class OutputProducer
{
- // This locks access to _completed.
+ // This locks access to _completed and _aborted.
private readonly object _contextLock = new object();
private bool _completed;
+ private volatile bool _aborted;
private readonly Pipe _pipe;
@@ -32,6 +33,8 @@ public OutputProducer(Pipe pipe)
}
public PipeReader Reader => _pipe.Reader;
+
+ public bool Aborted => _aborted;
public Task FlushAsync(CancellationToken cancellationToken)
{
@@ -44,7 +47,7 @@ public void Complete()
{
lock (_contextLock)
{
- if (_completed)
+ if (_completed || _aborted)
{
return;
}
@@ -58,12 +61,12 @@ public void Abort(Exception error)
{
lock (_contextLock)
{
- if (_completed)
+ if (_completed || _aborted)
{
return;
}
- _completed = true;
+ _aborted = true;
_pipe.Reader.CancelPendingRead();
_pipe.Writer.Complete();
@@ -74,7 +77,7 @@ public Task WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellati
{
lock (_contextLock)
{
- if (_completed)
+ if (_completed || _aborted)
{
return Task.CompletedTask;
}
diff --git a/src/Servers/IIS/IIS/test/IIS.FunctionalTests/ShadowCopyTests.cs b/src/Servers/IIS/IIS/test/IIS.FunctionalTests/ShadowCopyTests.cs
index 375bf607eaed..cdf629494059 100644
--- a/src/Servers/IIS/IIS/test/IIS.FunctionalTests/ShadowCopyTests.cs
+++ b/src/Servers/IIS/IIS/test/IIS.FunctionalTests/ShadowCopyTests.cs
@@ -199,7 +199,7 @@ public async Task ShadowCopyE2EWorksWithOldFoldersPresent()
// Depending on timing, this could result in a shutdown failure, but sometimes it succeeds, handle both situations
if (!response.IsSuccessStatusCode)
{
- Assert.Equal("Application Shutting Down", response.ReasonPhrase);
+ Assert.True(response.ReasonPhrase == "Application Shutting Down" || response.ReasonPhrase == "Server has been shutdown");
}
// This shutdown should trigger a copy to the next highest directory, which will be 2
diff --git a/src/Servers/IIS/IIS/test/IIS.Tests/IIS.Tests.csproj b/src/Servers/IIS/IIS/test/IIS.Tests/IIS.Tests.csproj
index 1b54904dee94..befdb53d48fa 100644
--- a/src/Servers/IIS/IIS/test/IIS.Tests/IIS.Tests.csproj
+++ b/src/Servers/IIS/IIS/test/IIS.Tests/IIS.Tests.csproj
@@ -19,6 +19,7 @@
+
diff --git a/src/Servers/IIS/IIS/test/IIS.Tests/ResponseAbortTests.cs b/src/Servers/IIS/IIS/test/IIS.Tests/ResponseAbortTests.cs
index 1cec8d64149f..9f8c1dbb6f9f 100644
--- a/src/Servers/IIS/IIS/test/IIS.Tests/ResponseAbortTests.cs
+++ b/src/Servers/IIS/IIS/test/IIS.Tests/ResponseAbortTests.cs
@@ -33,7 +33,6 @@ public async Task ClosesWithoutSendingAnything()
}
[ConditionalFact]
- [QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/31404")]
public async Task ClosesAfterDataSent()
{
var bodyReceived = CreateTaskCompletionSource();
diff --git a/src/Servers/IIS/IIS/test/testassets/InProcessNewShimWebSite/InProcessNewShimWebSite.csproj b/src/Servers/IIS/IIS/test/testassets/InProcessNewShimWebSite/InProcessNewShimWebSite.csproj
index 1292ac7a3aa4..11fd5774a2f5 100644
--- a/src/Servers/IIS/IIS/test/testassets/InProcessNewShimWebSite/InProcessNewShimWebSite.csproj
+++ b/src/Servers/IIS/IIS/test/testassets/InProcessNewShimWebSite/InProcessNewShimWebSite.csproj
@@ -56,6 +56,9 @@
true
+
+ true
+
true
diff --git a/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/InProcessWebSite.csproj b/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/InProcessWebSite.csproj
index 4f4c84730d4b..2b92d81eaa09 100644
--- a/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/InProcessWebSite.csproj
+++ b/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/InProcessWebSite.csproj
@@ -29,6 +29,7 @@
+
diff --git a/src/Servers/IIS/IntegrationTesting.IIS/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj b/src/Servers/IIS/IntegrationTesting.IIS/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj
index c97ee26fab2e..ed716f84d993 100644
--- a/src/Servers/IIS/IntegrationTesting.IIS/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj
+++ b/src/Servers/IIS/IntegrationTesting.IIS/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj
@@ -61,6 +61,7 @@
+
diff --git a/src/Servers/Kestrel/Core/src/Internal/SniOptionsSelector.cs b/src/Servers/Kestrel/Core/src/Internal/SniOptionsSelector.cs
index 85cd5fa1bd70..aa62f1e6d3e4 100644
--- a/src/Servers/Kestrel/Core/src/Internal/SniOptionsSelector.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/SniOptionsSelector.cs
@@ -225,7 +225,17 @@ private LongestStringFirstComparer()
public int Compare(string? x, string? y)
{
// Flip x and y to put the longest instead of the shortest string first in the SortedList.
- return y!.Length.CompareTo(x!.Length);
+ // SortedList does not support duplicate entries, so fall back to
+ // StringComparison.OrdinalIgnoreCase behavior for equal length strings.
+ var lengthResult = y!.Length.CompareTo(x!.Length);
+ if (lengthResult != 0)
+ {
+ return lengthResult;
+ }
+ else
+ {
+ return string.Compare(x, y, StringComparison.OrdinalIgnoreCase);
+ }
}
}
}
diff --git a/src/Servers/Kestrel/Core/test/SniOptionsSelectorTests.cs b/src/Servers/Kestrel/Core/test/SniOptionsSelectorTests.cs
index 6c6cc977b8ee..203d5972bae6 100644
--- a/src/Servers/Kestrel/Core/test/SniOptionsSelectorTests.cs
+++ b/src/Servers/Kestrel/Core/test/SniOptionsSelectorTests.cs
@@ -186,6 +186,91 @@ public void ServerNameMatchingIsCaseInsensitive()
Assert.Equal("WildcardPrefix", pathDictionary[aSubdomainOptions.ServerCertificate]);
}
+ [Fact]
+ public void MultipleWildcardPrefixServerNamesOfSameLengthAreAllowed()
+ {
+ var sniDictionary = new Dictionary
+ {
+ {
+ "*.a.example.org",
+ new SniConfig
+ {
+ Certificate = new CertificateConfig
+ {
+ Path = "a"
+ }
+ }
+ },
+ {
+ "*.b.example.org",
+ new SniConfig
+ {
+ Certificate = new CertificateConfig
+ {
+ Path = "b"
+ }
+ }
+ }
+ };
+
+ var mockCertificateConfigLoader = new MockCertificateConfigLoader();
+ var pathDictionary = mockCertificateConfigLoader.CertToPathDictionary;
+
+ var sniOptionsSelector = new SniOptionsSelector(
+ "TestEndpointName",
+ sniDictionary,
+ mockCertificateConfigLoader,
+ fallbackHttpsOptions: new HttpsConnectionAdapterOptions(),
+ fallbackHttpProtocols: HttpProtocols.Http1AndHttp2,
+ logger: Mock.Of>());
+
+ var (aSubdomainOptions, _) = sniOptionsSelector.GetOptions(new MockConnectionContext(), "c.a.example.org");
+ Assert.Equal("a", pathDictionary[aSubdomainOptions.ServerCertificate]);
+
+ var (bSubdomainOptions, _) = sniOptionsSelector.GetOptions(new MockConnectionContext(), "c.b.example.org");
+ Assert.Equal("b", pathDictionary[bSubdomainOptions.ServerCertificate]);
+ }
+
+ [Fact]
+ public void DuplicateWildcardPrefixServerNamesThrowsArgumentException()
+ {
+ var sniDictionary = new Dictionary
+ {
+ {
+ "*.example.org",
+ new SniConfig
+ {
+ Certificate = new CertificateConfig
+ {
+ Path = "a"
+ }
+ }
+ },
+ {
+ "*.EXAMPLE.org",
+ new SniConfig
+ {
+ Certificate = new CertificateConfig
+ {
+ Path = "b"
+ }
+ }
+ }
+ };
+
+ var mockCertificateConfigLoader = new MockCertificateConfigLoader();
+ var pathDictionary = mockCertificateConfigLoader.CertToPathDictionary;
+
+ var exception = Assert.Throws(() => new SniOptionsSelector(
+ "TestEndpointName",
+ sniDictionary,
+ mockCertificateConfigLoader,
+ fallbackHttpsOptions: new HttpsConnectionAdapterOptions(),
+ fallbackHttpProtocols: HttpProtocols.Http1AndHttp2,
+ logger: Mock.Of>()));
+ Assert.Equal("An item with the same key has already been added. Key: .EXAMPLE.org (Parameter 'key')", exception.Message);
+ }
+
[Fact]
public void GetOptionsThrowsAnAuthenticationExceptionIfThereIsNoMatchingSniSection()
{
diff --git a/src/Shared/CertificateGeneration/CertificateManager.cs b/src/Shared/CertificateGeneration/CertificateManager.cs
index 99f8e446a7d3..987db2bba031 100644
--- a/src/Shared/CertificateGeneration/CertificateManager.cs
+++ b/src/Shared/CertificateGeneration/CertificateManager.cs
@@ -493,11 +493,11 @@ internal void ExportCertificate(X509Certificate2 certificate, string path, bool
// Export the key first to an encrypted PEM to avoid issues with System.Security.Cryptography.Cng indicating that the operation is not supported.
// This is likely by design to avoid exporting the key by mistake.
// To bypass it, we export the certificate to pem temporarily and then we import it and export it as unprotected PEM.
- keyBytes = key.ExportEncryptedPkcs8PrivateKey("", new PbeParameters(PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, 1));
+ keyBytes = key.ExportEncryptedPkcs8PrivateKey((ReadOnlySpan)"", new PbeParameters(PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, 1));
pem = PemEncoding.Write("ENCRYPTED PRIVATE KEY", keyBytes);
key.Dispose();
key = RSA.Create();
- key.ImportFromEncryptedPem(pem, "");
+ key.ImportFromEncryptedPem(pem, (ReadOnlySpan)"");
Array.Clear(keyBytes, 0, keyBytes.Length);
Array.Clear(pem, 0, pem.Length);
keyBytes = key.ExportPkcs8PrivateKey();
diff --git a/src/SignalR/clients/ts/FunctionalTests/yarn.lock b/src/SignalR/clients/ts/FunctionalTests/yarn.lock
index 83ff9d122a99..99e147bdf2b8 100644
--- a/src/SignalR/clients/ts/FunctionalTests/yarn.lock
+++ b/src/SignalR/clients/ts/FunctionalTests/yarn.lock
@@ -265,9 +265,9 @@ ajv@^6.12.3, ajv@^6.12.5:
uri-js "^4.2.2"
ansi-regex@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
- integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1"
+ integrity "sha1-Ej1keekq1FrYl9QFTjx8p9tJROE= sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw=="
ansi-styles@^3.2.1:
version "3.2.1"
@@ -341,9 +341,9 @@ async-limiter@~1.0.0:
integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
async@^2.0.0, async@^2.1.2, async@^2.6.2, async@^2.6.3:
- version "2.6.3"
- resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
- integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
+ version "2.6.4"
+ resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221"
+ integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==
dependencies:
lodash "^4.17.14"
@@ -1530,9 +1530,9 @@ minimatch@^3.0.2, minimatch@^3.0.4:
brace-expansion "^1.1.7"
minimist@^1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
- integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
+ integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
minimist@~0.0.1:
version "0.0.10"
diff --git a/src/SignalR/clients/ts/common/yarn.lock b/src/SignalR/clients/ts/common/yarn.lock
index 5f7e6ed679e1..833e599afde7 100644
--- a/src/SignalR/clients/ts/common/yarn.lock
+++ b/src/SignalR/clients/ts/common/yarn.lock
@@ -3366,9 +3366,9 @@ minimatch@^3.0.4:
brace-expansion "^1.1.7"
minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
- integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
+ integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
mixin-deep@^1.2.0:
version "1.3.2"
@@ -4415,9 +4415,9 @@ throat@^5.0.0:
integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==
tmpl@1.0.x:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
- integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc"
+ integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==
to-fast-properties@^2.0.0:
version "2.0.0"
diff --git a/src/Testing/src/xunit/HelixConstants.cs b/src/Testing/src/xunit/HelixConstants.cs
index 8ec6a086a7a0..a78e9e2b411b 100644
--- a/src/Testing/src/xunit/HelixConstants.cs
+++ b/src/Testing/src/xunit/HelixConstants.cs
@@ -6,6 +6,7 @@ namespace Microsoft.AspNetCore.Testing
public static class HelixConstants
{
public const string Windows10Arm64 = "Windows.10.Arm64v8.Open;";
+ public const string DebianAmd64 = "Debian.11.Amd64.Open;";
public const string DebianArm64 = "Debian.11.Arm64.Open;";
public const string RedhatAmd64 = "Redhat.7.Amd64.Open;";
}
diff --git a/src/Tools/Microsoft.dotnet-openapi/src/Microsoft.dotnet-openapi.csproj b/src/Tools/Microsoft.dotnet-openapi/src/Microsoft.dotnet-openapi.csproj
index 1248c3830880..58f97791a998 100644
--- a/src/Tools/Microsoft.dotnet-openapi/src/Microsoft.dotnet-openapi.csproj
+++ b/src/Tools/Microsoft.dotnet-openapi/src/Microsoft.dotnet-openapi.csproj
@@ -17,6 +17,7 @@
+
diff --git a/src/Tools/dotnet-sql-cache/src/dotnet-sql-cache.csproj b/src/Tools/dotnet-sql-cache/src/dotnet-sql-cache.csproj
index 24f2823009cf..ca9fb454c381 100644
--- a/src/Tools/dotnet-sql-cache/src/dotnet-sql-cache.csproj
+++ b/src/Tools/dotnet-sql-cache/src/dotnet-sql-cache.csproj
@@ -15,6 +15,7 @@
+
diff --git a/src/submodules/googletest b/src/submodules/googletest
index af29db7ec28d..8ded48c37be0 160000
--- a/src/submodules/googletest
+++ b/src/submodules/googletest
@@ -1 +1 @@
-Subproject commit af29db7ec28d6df1c7f0f745186884091e602e07
+Subproject commit 8ded48c37be09d8cc3665af1b414c5d53c0862e7
diff --git a/src/submodules/spa-templates b/src/submodules/spa-templates
index 08a4e743ccec..74e05a19dc83 160000
--- a/src/submodules/spa-templates
+++ b/src/submodules/spa-templates
@@ -1 +1 @@
-Subproject commit 08a4e743ccec97c24aec8b7a719655f08e827d8e
+Subproject commit 74e05a19dc83b736877cb2c5120456948d7799f1