From 87f13a19c085ab4b6006c9b388e36ac0e628af25 Mon Sep 17 00:00:00 2001
From: vseanreesermsft <78103370+vseanreesermsft@users.noreply.github.com>
Date: Tue, 5 Apr 2022 15:56:11 -0700
Subject: [PATCH 01/21] Update branding to 6.0.5 (#41049)
---
eng/Versions.props | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/eng/Versions.props b/eng/Versions.props
index 7677e2bb8248..bb2938612641 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -8,8 +8,8 @@
6
0
- 4
- true
+ 5
+ false
From d60e995e8c2023f34d42779765cb672434cd982d Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Tue, 5 Apr 2022 15:57:07 -0700
Subject: [PATCH 02/21] [release/6.0] Get richnav.yml building again (#40783)
* Get richnav.yml building again - correct build.cmd location - generally align richnav.yml with ci.yml - ignore signing, internal download args, and publish args
nit: correct name of one build step in ci.yml
* Disable pipeline in PR validation - also remove irrelevant trigger branches
* !fixup! Try doing native build w/o rich nav
nit: put `-no`s together
* !fixup! Disable rich nav explicitly - also remove installers build entirely; build will fail
nits:
- don't bother setting `$(EnableRichCodeNavigation)` or `$(OnlyPackPlatformSpecificPackages)` to `true`
- job.yml sets `$(EnableRichCodeNavigation)` variable and `msbuild` will find that in environment
- `$(OnlyPackPlatformSpecificPackages)` is not relevant in this pipeline; not packing
Co-authored-by: Doug Bunting <6431421+dougbu@users.noreply.github.com>
---
.azure/pipelines/richnav.yml | 48 ++++++++++++++++++++++--------------
1 file changed, 29 insertions(+), 19 deletions(-)
diff --git a/.azure/pipelines/richnav.yml b/.azure/pipelines/richnav.yml
index 46d8b9e3cb75..e5fe8756d315 100644
--- a/.azure/pipelines/richnav.yml
+++ b/.azure/pipelines/richnav.yml
@@ -6,59 +6,69 @@
trigger:
branches:
include:
- - blazor-wasm
- main
- release/*
- - internal/release/*
+
+# Do not run this pipeline for PR validation.
+pr: none
variables:
- name: _BuildArgs
value: '/p:SkipTestBuild=true'
-- name: Windows86LogArgs
+- name: WindowsNonX64LogArgs
value: -ExcludeCIBinaryLog
stages:
- stage: build
displayName: Build
jobs:
- # Build Windows (x64/x86)
+ # Build Windows (x64/x86/arm64)
- template: jobs/default-build.yml
parameters:
codeSign: false
jobName: Windows_build
- jobDisplayName: "Build: Windows x64/x86"
+ jobDisplayName: "Build: Windows x64/x86/arm64"
enableRichCodeNavigation: true
agentOs: Windows
steps:
- - script: ./build.cmd
+ - script: ./eng/build.cmd
-ci
- -all
-arch x64
- /p:EnableRichCodeNavigation=true
+ -buildNative
+ /p:EnableRichCodeNavigation=false
+ $(_BuildArgs)
+ displayName: Build x64 native assets
+
+ - script: ./eng/build.cmd
+ -ci
+ -arch x64
+ -all
+ -noBuildNative
+ -noBuildRepoTasks
$(_BuildArgs)
displayName: Build x64
# Build the x86 shared framework
# This is going to actually build x86 native assets.
- - script: ./build.cmd
+ - script: ./eng/build.cmd
-ci
- -noBuildRepoTasks
-arch x86
-all
-noBuildJava
-noBuildNative
- /p:EnableRichCodeNavigation=true
+ -noBuildRepoTasks
$(_BuildArgs)
- $(Windows86LogArgs)
+ $(WindowsNonX64LogArgs)
displayName: Build x86
- # Windows installers bundle both x86 and x64 assets
- - script: ./build.cmd
+ # Build the arm64 shared framework
+ - script: ./eng/build.cmd
-ci
- -noBuildRepoTasks
- -buildInstallers
+ -arch arm64
+ -noBuildJava
-noBuildNative
- /p:AssetManifestFileName=aspnetcore-win-x64-x86.xml
- /p:EnableRichCodeNavigation=true
+ -noBuildRepoTasks
$(_BuildArgs)
- displayName: Build Installers
+ $(WindowsNonX64LogArgs)
+ displayName: Build ARM64
+
From eb694ab14702d9ca683f5ed15ada4ab2f0bda7b9 Mon Sep 17 00:00:00 2001
From: Chris Ross
Date: Tue, 5 Apr 2022 15:58:37 -0700
Subject: [PATCH 03/21] Support falling back to ConnectionId when
RawConnectionId is 0 on HTTP.sys (#40760)
---
src/Servers/HttpSys/src/RequestProcessing/Request.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Servers/HttpSys/src/RequestProcessing/Request.cs b/src/Servers/HttpSys/src/RequestProcessing/Request.cs
index ffffc050672c..880beebf562d 100644
--- a/src/Servers/HttpSys/src/RequestProcessing/Request.cs
+++ b/src/Servers/HttpSys/src/RequestProcessing/Request.cs
@@ -120,7 +120,7 @@ internal Request(RequestContext requestContext)
internal ulong RawConnectionId { get; }
// No ulongs in public APIs...
- public long ConnectionId => (long)RawConnectionId;
+ public long ConnectionId => RawConnectionId != 0 ? (long)RawConnectionId : (long)UConnectionId;
internal ulong RequestId { get; }
From 8107aa5e6efd9c36a9da70353c8ece7339425659 Mon Sep 17 00:00:00 2001
From: Doug Bunting <6431421+dougbu@users.noreply.github.com>
Date: Tue, 5 Apr 2022 15:58:54 -0700
Subject: [PATCH 04/21] Cleanup logs after successful test runs (#40807)
- backport for #39038
- `cherry-pick` of 6958517ccd76
- update `AssemblyTestLog` to perform actual log directory cleanup
- add `ReportTestFailure()` method for tests to report failures, disabling cleanup
- add `IAcceptFailureReports` for `AspNetTestAssemblyRunner` to report failures to `AssemblyTestLog`
- extend `AspNetTestAssemblyRunner` to optionally create fixture instances using `static ForAssembly(Assembly)`
- add `AssemblyTestLogFixtureAttribute` to register `AssemblyTestLog` as an assembly fixture
- use `AssemblyTestLogFixtureAttribute` in all test projects
- disable log cleanup in three existing tests
- add tests of new cleanup features
- also cover a few existing methods
- do cleanup before creating new logger
- was deleting the just-created global.log file
nits:
- use `is [not] null` and `new()` more
- move `AssemblyTestLogTests` to same namespace as `AssemblyTestLog`
---
.../Mvc.FunctionalTests/ErrorPageTests.cs | 12 +-
src/Testing/src/AssemblyTestLog.cs | 72 ++++--
.../src/AssemblyTestLogFixtureAttribute.cs | 11 +
.../build/Microsoft.AspNetCore.Testing.props | 5 +-
.../src/xunit/AspNetTestAssemblyRunner.cs | 55 +++-
.../src/xunit/IAcceptFailureReports.cs | 9 +
.../test/AspNetTestAssemblyRunnerTest.cs | 219 ++++++++++++++++
src/Testing/test/AssemblyTestLogTests.cs | 243 +++++++++++++++---
.../test/TestableAspNetTestAssemblyRunner.cs | 105 ++++++++
src/Testing/test/TestableAssembly.cs | 95 +++++++
10 files changed, 755 insertions(+), 71 deletions(-)
create mode 100644 src/Testing/src/AssemblyTestLogFixtureAttribute.cs
create mode 100644 src/Testing/src/xunit/IAcceptFailureReports.cs
create mode 100644 src/Testing/test/AspNetTestAssemblyRunnerTest.cs
create mode 100644 src/Testing/test/TestableAspNetTestAssemblyRunner.cs
create mode 100644 src/Testing/test/TestableAssembly.cs
diff --git a/src/Mvc/test/Mvc.FunctionalTests/ErrorPageTests.cs b/src/Mvc/test/Mvc.FunctionalTests/ErrorPageTests.cs
index 11ff6b17d899..ccfb60a40bb4 100644
--- a/src/Mvc/test/Mvc.FunctionalTests/ErrorPageTests.cs
+++ b/src/Mvc/test/Mvc.FunctionalTests/ErrorPageTests.cs
@@ -1,14 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
-using System.IO;
-using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Encodings.Web;
-using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation;
using Microsoft.AspNetCore.TestHost;
@@ -16,7 +12,6 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
-using Xunit;
using Xunit.Abstractions;
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
@@ -24,7 +19,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
///
/// Functional test to verify the error reporting of Razor compilation by diagnostic middleware.
///
- public class ErrorPageTests : IClassFixture>, IDisposable
+ public class ErrorPageTests : IClassFixture>
{
private static readonly string PreserveCompilationContextMessage = HtmlEncoder.Default.Encode(
"One or more compilation references may be missing. " +
@@ -189,10 +184,5 @@ public async Task AggregateException_FlattensInnerExceptions()
Assert.Contains(nullReferenceException, content);
Assert.Contains(indexOutOfRangeException, content);
}
-
- public void Dispose()
- {
- _assemblyTestLog.Dispose();
- }
}
}
diff --git a/src/Testing/src/AssemblyTestLog.cs b/src/Testing/src/AssemblyTestLog.cs
index 0e3d06f2eb3e..4e03f7ca3035 100644
--- a/src/Testing/src/AssemblyTestLog.cs
+++ b/src/Testing/src/AssemblyTestLog.cs
@@ -7,10 +7,8 @@
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
-using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
-using System.Text;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Serilog;
@@ -22,20 +20,21 @@
namespace Microsoft.AspNetCore.Testing
{
- public class AssemblyTestLog : IDisposable
+ public class AssemblyTestLog : IAcceptFailureReports, IDisposable
{
private const string MaxPathLengthEnvironmentVariableName = "ASPNETCORE_TEST_LOG_MAXPATH";
private const string LogFileExtension = ".log";
private static readonly int MaxPathLength = GetMaxPathLength();
- private static readonly object _lock = new object();
- private static readonly Dictionary _logs = new Dictionary();
+ private static readonly object _lock = new();
+ private static readonly Dictionary _logs = new();
private readonly ILoggerFactory _globalLoggerFactory;
private readonly ILogger _globalLogger;
private readonly string _baseDirectory;
private readonly Assembly _assembly;
private readonly IServiceProvider _serviceProvider;
+ private bool _testFailureReported;
private static int GetMaxPathLength()
{
@@ -53,6 +52,9 @@ private AssemblyTestLog(ILoggerFactory globalLoggerFactory, ILogger globalLogger
_serviceProvider = serviceProvider;
}
+ // internal for testing
+ internal bool OnCI { get; set; } = SkipOnCIAttribute.OnCI();
+
[SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")]
public IDisposable StartTestLog(ITestOutputHelper output, string className, out ILoggerFactory loggerFactory, [CallerMemberName] string testName = null) =>
StartTestLog(output, className, out loggerFactory, LogLevel.Debug, testName);
@@ -178,11 +180,8 @@ public IServiceProvider CreateLoggerServices(ITestOutputHelper output, string cl
return serviceCollection.BuildServiceProvider();
}
- // For back compat
- public static AssemblyTestLog Create(string assemblyName, string baseDirectory)
- => Create(Assembly.Load(new AssemblyName(assemblyName)), baseDirectory);
-
- public static AssemblyTestLog Create(Assembly assembly, string baseDirectory)
+ // internal for testing. Expectation is AspNetTestAssembly runner calls ForAssembly() first for every Assembly.
+ internal static AssemblyTestLog Create(Assembly assembly, string baseDirectory)
{
var logStart = DateTimeOffset.UtcNow;
SerilogLoggerProvider serilogLoggerProvider = null;
@@ -224,26 +223,46 @@ public static AssemblyTestLog ForAssembly(Assembly assembly)
{
if (!_logs.TryGetValue(assembly, out var log))
{
- var baseDirectory = TestFileOutputContext.GetOutputDirectory(assembly);
+ var stackTrace = Environment.StackTrace;
+ if (!stackTrace.Contains(
+ "Microsoft.AspNetCore.Testing"
+#if NETCOREAPP
+ , StringComparison.Ordinal
+#endif
+ ))
+ {
+ throw new InvalidOperationException($"Unexpected initial {nameof(ForAssembly)} caller.");
+ }
- log = Create(assembly, baseDirectory);
- _logs[assembly] = log;
+ var baseDirectory = TestFileOutputContext.GetOutputDirectory(assembly);
- // Try to clear previous logs, continue if it fails.
+ // Try to clear previous logs, continue if it fails. Do this before creating new global logger.
var assemblyBaseDirectory = TestFileOutputContext.GetAssemblyBaseDirectory(assembly);
- if (!string.IsNullOrEmpty(assemblyBaseDirectory) && !TestFileOutputContext.GetPreserveExistingLogsInOutput(assembly))
+ if (!string.IsNullOrEmpty(assemblyBaseDirectory) &&
+ !TestFileOutputContext.GetPreserveExistingLogsInOutput(assembly))
{
try
{
Directory.Delete(assemblyBaseDirectory, recursive: true);
}
- catch { }
+ catch
+ {
+ }
}
+
+ log = Create(assembly, baseDirectory);
+ _logs[assembly] = log;
}
+
return log;
}
}
+ public void ReportTestFailure()
+ {
+ _testFailureReported = true;
+ }
+
private static TestFrameworkFileLoggerAttribute GetFileLoggerAttribute(Assembly assembly)
=> assembly.GetCustomAttribute()
?? throw new InvalidOperationException($"No {nameof(TestFrameworkFileLoggerAttribute)} found on the assembly {assembly.GetName().Name}. "
@@ -269,13 +288,32 @@ private static SerilogLoggerProvider ConfigureFileLogging(string fileName, DateT
.MinimumLevel.Verbose()
.WriteTo.File(fileName, outputTemplate: "[{TimestampOffset}] [{SourceContext}] [{Level}] {Message:l}{NewLine}{Exception}", flushToDiskInterval: TimeSpan.FromSeconds(1), shared: true)
.CreateLogger();
+
return new SerilogLoggerProvider(serilogger, dispose: true);
}
- public void Dispose()
+ void IDisposable.Dispose()
{
(_serviceProvider as IDisposable)?.Dispose();
_globalLoggerFactory.Dispose();
+
+ // Clean up if no tests failed and we're not running local tests. (Ignoring tests of this class, OnCI is
+ // true on both build and Helix agents.) In particular, remove the directory containing the global.log
+ // file. All test class log files for this assembly are in subdirectories of this location.
+ if (!_testFailureReported &&
+ OnCI &&
+ _baseDirectory is not null &&
+ Directory.Exists(_baseDirectory))
+ {
+ try
+ {
+ Directory.Delete(_baseDirectory, recursive: true);
+ }
+ catch
+ {
+ // Best effort. Ignore problems deleting locked logged files.
+ }
+ }
}
private class AssemblyLogTimestampOffsetEnricher : ILogEventEnricher
diff --git a/src/Testing/src/AssemblyTestLogFixtureAttribute.cs b/src/Testing/src/AssemblyTestLogFixtureAttribute.cs
new file mode 100644
index 000000000000..e4a4452cd458
--- /dev/null
+++ b/src/Testing/src/AssemblyTestLogFixtureAttribute.cs
@@ -0,0 +1,11 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Microsoft.AspNetCore.Testing;
+
+public class AssemblyTestLogFixtureAttribute : AssemblyFixtureAttribute
+{
+ public AssemblyTestLogFixtureAttribute() : base(typeof(AssemblyTestLog))
+ {
+ }
+}
diff --git a/src/Testing/src/build/Microsoft.AspNetCore.Testing.props b/src/Testing/src/build/Microsoft.AspNetCore.Testing.props
index 063e9094d172..47d06dfef7a7 100644
--- a/src/Testing/src/build/Microsoft.AspNetCore.Testing.props
+++ b/src/Testing/src/build/Microsoft.AspNetCore.Testing.props
@@ -11,8 +11,8 @@
+ BeforeTargets="GetAssemblyAttributes"
+ Condition="'$(GenerateLoggingTestingAssemblyAttributes)' != 'false'">
true
false
@@ -24,6 +24,7 @@
<_Parameter2>Microsoft.AspNetCore.Testing
+
<_Parameter1>$(PreserveExistingLogsInOutput)
<_Parameter2>$(TargetFramework)
diff --git a/src/Testing/src/xunit/AspNetTestAssemblyRunner.cs b/src/Testing/src/xunit/AspNetTestAssemblyRunner.cs
index a83446375ddd..1d71bdf939be 100644
--- a/src/Testing/src/xunit/AspNetTestAssemblyRunner.cs
+++ b/src/Testing/src/xunit/AspNetTestAssemblyRunner.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
@@ -14,7 +15,7 @@ namespace Microsoft.AspNetCore.Testing
{
public class AspNetTestAssemblyRunner : XunitTestAssemblyRunner
{
- private readonly Dictionary _assemblyFixtureMappings = new Dictionary();
+ private readonly Dictionary _assemblyFixtureMappings = new();
public AspNetTestAssemblyRunner(
ITestAssembly testAssembly,
@@ -26,6 +27,9 @@ public AspNetTestAssemblyRunner(
{
}
+ // internal for testing
+ internal IEnumerable
+
+
+
+
+
+
diff --git a/src/Components/WebAssembly/WebAssembly.Authentication/src/Microsoft.AspNetCore.Components.WebAssembly.Authentication.csproj b/src/Components/WebAssembly/WebAssembly.Authentication/src/Microsoft.AspNetCore.Components.WebAssembly.Authentication.csproj
index 8d6a000d74f0..35c79a73eb8b 100644
--- a/src/Components/WebAssembly/WebAssembly.Authentication/src/Microsoft.AspNetCore.Components.WebAssembly.Authentication.csproj
+++ b/src/Components/WebAssembly/WebAssembly.Authentication/src/Microsoft.AspNetCore.Components.WebAssembly.Authentication.csproj
@@ -1,6 +1,6 @@
-
+
$(DefaultNetCoreTargetFramework)
@@ -26,6 +26,7 @@
$(MSBuildThisFileDirectory)Interop\
+ CheckForSourceBuild;
CompileInterop;
IncludeCompileInteropOutput;
$(ResolveStaticWebAssetsInputsDependsOn)
@@ -93,4 +94,10 @@
+
+
+
+
+
+
From a8ed5610fef2f9d6394d014d5775e047ac5cc222 Mon Sep 17 00:00:00 2001
From: Aditya Mandaleeka
Date: Tue, 5 Apr 2022 15:59:44 -0700
Subject: [PATCH 06/21] Allow leading CR/LF in HTTP request lines in Kestrel.
(#40859)
---
.../Core/src/Internal/Http/HttpParser.cs | 8 +++
.../Kestrel/Core/test/StartLineTests.cs | 50 +++++++++++++++++++
2 files changed, 58 insertions(+)
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/HttpParser.cs b/src/Servers/Kestrel/Core/src/Internal/Http/HttpParser.cs
index 064da12cb634..3c66964cafd4 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http/HttpParser.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http/HttpParser.cs
@@ -38,6 +38,14 @@ public HttpParser(bool showErrorDetails)
public bool ParseRequestLine(TRequestHandler handler, ref SequenceReader reader)
{
+ // Skip any leading \r or \n on the request line. This is not technically allowed,
+ // but apparently there are enough clients relying on this that it's worth allowing.
+ // Peek first as a minor performance optimization; it's a quick inlined check.
+ if (reader.TryPeek(out byte b) && (b == ByteCR || b == ByteLF))
+ {
+ reader.AdvancePastAny(ByteCR, ByteLF);
+ }
+
if (reader.TryReadTo(out ReadOnlySpan requestLine, ByteLF, advancePastDelimiter: true))
{
ParseRequestLine(handler, requestLine);
diff --git a/src/Servers/Kestrel/Core/test/StartLineTests.cs b/src/Servers/Kestrel/Core/test/StartLineTests.cs
index 4c65611e95e4..59fdf6dd0cc1 100644
--- a/src/Servers/Kestrel/Core/test/StartLineTests.cs
+++ b/src/Servers/Kestrel/Core/test/StartLineTests.cs
@@ -6,6 +6,7 @@
using System.IO.Pipelines;
using System.Text;
using Microsoft.AspNetCore.Connections;
+using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
@@ -516,6 +517,55 @@ public void AuthorityForms(string rawTarget, string path, string query)
DifferentFormsWorkTogether();
}
+ public static IEnumerable GetCrLfAndMethodCombinations()
+ {
+ // HTTP methods to test
+ var methods = new string[] {
+ HttpMethods.Connect,
+ HttpMethods.Delete,
+ HttpMethods.Get,
+ HttpMethods.Head,
+ HttpMethods.Options,
+ HttpMethods.Patch,
+ HttpMethods.Post,
+ HttpMethods.Put,
+ HttpMethods.Trace
+ };
+
+ // Prefixes to test
+ var crLfPrefixes = new string[] {
+ "\r",
+ "\n",
+ "\r\r\r\r\r",
+ "\r\n",
+ "\n\r"
+ };
+
+ foreach (var method in methods)
+ {
+ foreach (var prefix in crLfPrefixes)
+ {
+ yield return new object[] { prefix, method };
+ }
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(GetCrLfAndMethodCombinations))]
+ public void LeadingCrLfAreAllowed(string startOfRequestLine, string httpMethod)
+ {
+ var rawTarget = "http://localhost/path1?q=123&w=xyzw";
+ Http1Connection.Reset();
+ // RawTarget, Path, QueryString are null after reset
+ Assert.Null(Http1Connection.RawTarget);
+ Assert.Null(Http1Connection.Path);
+ Assert.Null(Http1Connection.QueryString);
+
+ var ros = new ReadOnlySequence(Encoding.ASCII.GetBytes($"{startOfRequestLine}{httpMethod} {rawTarget} HTTP/1.1\r\n"));
+ var reader = new SequenceReader(ros);
+ Assert.True(Parser.ParseRequestLine(ParsingHandler, ref reader));
+ }
+
public StartLineTests()
{
MemoryPool = PinnedBlockMemoryPoolFactory.Create();
From bc1c2ada2265a0f26f2400a428f07cb739af9407 Mon Sep 17 00:00:00 2001
From: Hao Kung
Date: Tue, 5 Apr 2022 16:00:10 -0700
Subject: [PATCH 07/21] Unquarantine test (#40888)
---
src/Servers/IIS/IIS/test/Common.FunctionalTests/StartupTests.cs | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/StartupTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/StartupTests.cs
index e0b0ab828131..e6acee1a6d43 100644
--- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/StartupTests.cs
+++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/StartupTests.cs
@@ -468,7 +468,6 @@ public async Task RemoveInProcessReference_FailedToFindRequestHandler()
[ConditionalFact]
[RequiresNewHandler]
- [QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/40036")]
public async Task StartupTimeoutIsApplied()
{
// From what we can tell, this failure is due to ungraceful shutdown.
From 7363a6c6a188f01d013de33fcc7ff9fdc159c028 Mon Sep 17 00:00:00 2001
From: Nolan Glore
Date: Tue, 5 Apr 2022 16:02:07 -0700
Subject: [PATCH 08/21] Fix DelegationRule to work after receiver restarts
(#40967)
---
src/Servers/HttpSys/HttpSysServer.slnf | 2 +
src/Servers/HttpSys/src/DelegationRule.cs | 8 +--
.../HttpSys/src/NativeInterop/RequestQueue.cs | 27 +++----
.../HttpSys/src/NativeInterop/UrlGroup.cs | 18 -----
.../src/RequestProcessing/RequestContext.cs | 5 +-
.../src/ServerDelegationPropertyFeature.cs | 13 ++--
.../test/FunctionalTests/DelegateTests.cs | 72 +++++++++++++++++--
7 files changed, 101 insertions(+), 44 deletions(-)
diff --git a/src/Servers/HttpSys/HttpSysServer.slnf b/src/Servers/HttpSys/HttpSysServer.slnf
index 3990e33925cb..c546d5797a4a 100644
--- a/src/Servers/HttpSys/HttpSysServer.slnf
+++ b/src/Servers/HttpSys/HttpSysServer.slnf
@@ -4,9 +4,11 @@
"projects": [
"src\\DefaultBuilder\\src\\Microsoft.AspNetCore.csproj",
"src\\Extensions\\Features\\src\\Microsoft.Extensions.Features.csproj",
+ "src\\FileProviders\\Embedded\\src\\Microsoft.Extensions.FileProviders.Embedded.csproj",
"src\\Hosting\\Abstractions\\src\\Microsoft.AspNetCore.Hosting.Abstractions.csproj",
"src\\Hosting\\Hosting\\src\\Microsoft.AspNetCore.Hosting.csproj",
"src\\Hosting\\Server.Abstractions\\src\\Microsoft.AspNetCore.Hosting.Server.Abstractions.csproj",
+ "src\\Hosting\\Server.IntegrationTesting\\src\\Microsoft.AspNetCore.Server.IntegrationTesting.csproj",
"src\\Http\\Authentication.Abstractions\\src\\Microsoft.AspNetCore.Authentication.Abstractions.csproj",
"src\\Http\\Authentication.Core\\src\\Microsoft.AspNetCore.Authentication.Core.csproj",
"src\\Http\\Headers\\src\\Microsoft.Net.Http.Headers.csproj",
diff --git a/src/Servers/HttpSys/src/DelegationRule.cs b/src/Servers/HttpSys/src/DelegationRule.cs
index 1f57f8298558..c454952eea9e 100644
--- a/src/Servers/HttpSys/src/DelegationRule.cs
+++ b/src/Servers/HttpSys/src/DelegationRule.cs
@@ -13,17 +13,19 @@ namespace Microsoft.AspNetCore.Server.HttpSys
public class DelegationRule : IDisposable
{
private readonly ILogger _logger;
- private readonly UrlGroup _urlGroup;
private readonly UrlGroup _sourceQueueUrlGroup;
private bool _disposed;
+
///
/// The name of the Http.Sys request queue
///
public string QueueName { get; }
+
///
/// The URL of the Http.Sys Url Prefix
///
public string UrlPrefix { get; }
+
internal RequestQueue Queue { get; }
internal DelegationRule(UrlGroup sourceQueueUrlGroup, string queueName, string urlPrefix, ILogger logger)
@@ -32,8 +34,7 @@ internal DelegationRule(UrlGroup sourceQueueUrlGroup, string queueName, string u
_logger = logger;
QueueName = queueName;
UrlPrefix = urlPrefix;
- Queue = new RequestQueue(queueName, UrlPrefix, _logger, receiver: true);
- _urlGroup = Queue.UrlGroup;
+ Queue = new RequestQueue(queueName, _logger);
}
///
@@ -51,7 +52,6 @@ public void Dispose()
_sourceQueueUrlGroup.UnSetDelegationProperty(Queue, throwOnError: false);
}
catch (ObjectDisposedException) { /* Server may have been shutdown */ }
- _urlGroup.Dispose();
Queue.Dispose();
}
}
diff --git a/src/Servers/HttpSys/src/NativeInterop/RequestQueue.cs b/src/Servers/HttpSys/src/NativeInterop/RequestQueue.cs
index 8e25a8c21c37..89638a222575 100644
--- a/src/Servers/HttpSys/src/NativeInterop/RequestQueue.cs
+++ b/src/Servers/HttpSys/src/NativeInterop/RequestQueue.cs
@@ -19,25 +19,16 @@ internal class RequestQueue
private readonly ILogger _logger;
private bool _disposed;
- internal RequestQueue(string requestQueueName, string urlPrefix, ILogger logger, bool receiver)
- : this(urlGroup: null!, requestQueueName, RequestQueueMode.Attach, logger, receiver)
+ internal RequestQueue(string requestQueueName, ILogger logger)
+ : this(urlGroup: null, requestQueueName, RequestQueueMode.Attach, logger, receiver: true)
{
- try
- {
- UrlGroup = new UrlGroup(this, UrlPrefix.Create(urlPrefix), logger);
- }
- catch
- {
- Dispose();
- throw;
- }
}
internal RequestQueue(UrlGroup urlGroup, string? requestQueueName, RequestQueueMode mode, ILogger logger)
: this(urlGroup, requestQueueName, mode, logger, false)
{ }
- private RequestQueue(UrlGroup urlGroup, string? requestQueueName, RequestQueueMode mode, ILogger logger, bool receiver)
+ private RequestQueue(UrlGroup? urlGroup, string? requestQueueName, RequestQueueMode mode, ILogger logger, bool receiver)
{
_mode = mode;
UrlGroup = urlGroup;
@@ -117,10 +108,15 @@ private RequestQueue(UrlGroup urlGroup, string? requestQueueName, RequestQueueMo
internal SafeHandle Handle { get; }
internal ThreadPoolBoundHandle BoundHandle { get; }
- internal UrlGroup UrlGroup { get; }
+ internal UrlGroup? UrlGroup { get; }
internal unsafe void AttachToUrlGroup()
{
+ if (UrlGroup == null)
+ {
+ throw new NotSupportedException("Can't attach when UrlGroup is null");
+ }
+
Debug.Assert(Created);
CheckDisposed();
// Set the association between request queue and url group. After this, requests for registered urls will
@@ -138,6 +134,11 @@ internal unsafe void AttachToUrlGroup()
internal unsafe void DetachFromUrlGroup()
{
+ if (UrlGroup == null)
+ {
+ throw new NotSupportedException("Can't detach when UrlGroup is null");
+ }
+
Debug.Assert(Created);
CheckDisposed();
// Break the association between request queue and url group. After this, requests for registered urls
diff --git a/src/Servers/HttpSys/src/NativeInterop/UrlGroup.cs b/src/Servers/HttpSys/src/NativeInterop/UrlGroup.cs
index d13264889ddd..59a67ca43195 100644
--- a/src/Servers/HttpSys/src/NativeInterop/UrlGroup.cs
+++ b/src/Servers/HttpSys/src/NativeInterop/UrlGroup.cs
@@ -41,24 +41,6 @@ internal unsafe UrlGroup(ServerSession serverSession, ILogger logger)
Id = urlGroupId;
}
- internal unsafe UrlGroup(RequestQueue requestQueue, UrlPrefix url, ILogger logger)
- {
- _logger = logger;
-
- ulong urlGroupId = 0;
- _created = false;
- var statusCode = HttpApi.HttpFindUrlGroupId(
- url.FullPrefix, requestQueue.Handle, &urlGroupId);
-
- if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS)
- {
- throw new HttpSysException((int)statusCode);
- }
-
- Debug.Assert(urlGroupId != 0, "Invalid id returned by HttpCreateUrlGroup");
- Id = urlGroupId;
- }
-
internal ulong Id { get; private set; }
internal unsafe void SetMaxConnections(long maxConnections)
diff --git a/src/Servers/HttpSys/src/RequestProcessing/RequestContext.cs b/src/Servers/HttpSys/src/RequestProcessing/RequestContext.cs
index fabae04d35e5..9c45a262dac8 100644
--- a/src/Servers/HttpSys/src/RequestProcessing/RequestContext.cs
+++ b/src/Servers/HttpSys/src/RequestProcessing/RequestContext.cs
@@ -289,10 +289,13 @@ internal unsafe void Delegate(DelegationRule destination)
PropertyInfoLength = (uint)System.Text.Encoding.Unicode.GetByteCount(destination.UrlPrefix)
};
+ // Passing 0 for delegateUrlGroupId allows http.sys to find the right group for the
+ // URL passed in via the property above. If we passed in the receiver's URL group id
+ // instead of 0, then delegation would fail if the receiver restarted.
statusCode = HttpApi.HttpDelegateRequestEx(source.Handle,
destination.Queue.Handle,
Request.RequestId,
- destination.Queue.UrlGroup.Id,
+ delegateUrlGroupId: 0,
propertyInfoSetSize: 1,
&property);
}
diff --git a/src/Servers/HttpSys/src/ServerDelegationPropertyFeature.cs b/src/Servers/HttpSys/src/ServerDelegationPropertyFeature.cs
index 14aee50615c9..a97520a837d7 100644
--- a/src/Servers/HttpSys/src/ServerDelegationPropertyFeature.cs
+++ b/src/Servers/HttpSys/src/ServerDelegationPropertyFeature.cs
@@ -14,18 +14,23 @@ namespace Microsoft.AspNetCore.Server.HttpSys
internal class ServerDelegationPropertyFeature : IServerDelegationFeature
{
private readonly ILogger _logger;
- private readonly RequestQueue _queue;
+ private readonly UrlGroup _urlGroup;
public ServerDelegationPropertyFeature(RequestQueue queue, ILogger logger)
{
- _queue = queue;
+ if (queue.UrlGroup == null)
+ {
+ throw new ArgumentException($"{nameof(queue)}.UrlGroup can't be null");
+ }
+
+ _urlGroup = queue.UrlGroup;
_logger = logger;
}
public DelegationRule CreateDelegationRule(string queueName, string uri)
{
- var rule = new DelegationRule(_queue.UrlGroup, queueName, uri, _logger);
- _queue.UrlGroup.SetDelegationProperty(rule.Queue);
+ var rule = new DelegationRule(_urlGroup, queueName, uri, _logger);
+ _urlGroup.SetDelegationProperty(rule.Queue);
return rule;
}
}
diff --git a/src/Servers/HttpSys/test/FunctionalTests/DelegateTests.cs b/src/Servers/HttpSys/test/FunctionalTests/DelegateTests.cs
index ca9dcf3a0736..9e38c7da8b06 100644
--- a/src/Servers/HttpSys/test/FunctionalTests/DelegateTests.cs
+++ b/src/Servers/HttpSys/test/FunctionalTests/DelegateTests.cs
@@ -1,13 +1,11 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
-using System.IO;
using System.Net.Http;
-using System.Threading.Tasks;
+using System.Runtime.InteropServices;
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.HttpSys.Internal;
using Microsoft.AspNetCore.Testing;
-using Xunit;
namespace Microsoft.AspNetCore.Server.HttpSys.FunctionalTests
{
@@ -198,6 +196,72 @@ public async Task UpdateDelegationRuleTest()
destination?.Dispose();
}
+ [ConditionalFact]
+ [DelegateSupportedCondition(true)]
+ public async Task DelegateAfterReceiverRestart()
+ {
+ var queueName = Guid.NewGuid().ToString();
+ using var receiver = Utilities.CreateHttpServer(out var receiverAddress, async httpContext =>
+ {
+ await httpContext.Response.WriteAsync(_expectedResponseString);
+ },
+ options =>
+ {
+ options.RequestQueueName = queueName;
+ });
+
+ DelegationRule destination = default;
+ using var delegator = Utilities.CreateHttpServer(out var delegatorAddress, httpContext =>
+ {
+ var delegateFeature = httpContext.Features.Get();
+ delegateFeature.DelegateRequest(destination);
+ return Task.CompletedTask;
+ });
+
+ var delegationProperty = delegator.Features.Get();
+ destination = delegationProperty.CreateDelegationRule(queueName, receiverAddress);
+
+ var responseString = await SendRequestAsync(delegatorAddress);
+ Assert.Equal(_expectedResponseString, responseString);
+
+ // Stop the receiver
+ receiver?.Dispose();
+
+ // Start the receiver again but this time we need to attach to the existing queue.
+ // Due to https://github.com/dotnet/aspnetcore/issues/40359, we have to manually
+ // register URL prefixes and attach the server's queue to them.
+ using var receiverRestarted = (MessagePump)Utilities.CreateHttpServer(out receiverAddress, async httpContext =>
+ {
+ await httpContext.Response.WriteAsync(_expectedResponseString);
+ },
+ options =>
+ {
+ options.RequestQueueName = queueName;
+ options.RequestQueueMode = RequestQueueMode.Attach;
+ options.UrlPrefixes.Clear();
+ options.UrlPrefixes.Add(receiverAddress);
+ });
+ AttachToUrlGroup(receiverRestarted.Listener.RequestQueue);
+ receiverRestarted.Listener.Options.UrlPrefixes.RegisterAllPrefixes(receiverRestarted.Listener.UrlGroup);
+
+ responseString = await SendRequestAsync(delegatorAddress);
+ Assert.Equal(_expectedResponseString, responseString);
+
+ destination?.Dispose();
+ }
+
+ private unsafe void AttachToUrlGroup(RequestQueue requestQueue)
+ {
+ var info = new HttpApiTypes.HTTP_BINDING_INFO();
+ info.Flags = HttpApiTypes.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT;
+ info.RequestQueueHandle = requestQueue.Handle.DangerousGetHandle();
+
+ var infoptr = new IntPtr(&info);
+
+ requestQueue.UrlGroup.SetProperty(HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerBindingProperty,
+ infoptr, (uint)Marshal.SizeOf());
+ }
+
private async Task SendRequestAsync(string uri)
{
using var client = new HttpClient();
From 40c035ddd937fa5d507ad2726b62f17b59f43831 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 5 Apr 2022 16:06:46 -0700
Subject: [PATCH 09/21] [release/6.0] (deps): Bump src/submodules/googletest
(#41000)
Bumps [src/submodules/googletest](https://github.com/google/googletest) from `c9461a9` to `af29db7`.
- [Release notes](https://github.com/google/googletest/releases)
- [Commits](https://github.com/google/googletest/compare/c9461a9b55ba954df0489bab6420eb297bed846b...af29db7ec28d6df1c7f0f745186884091e602e07)
---
updated-dependencies:
- dependency-name: src/submodules/googletest
dependency-type: direct:production
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
src/submodules/googletest | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/submodules/googletest b/src/submodules/googletest
index c9461a9b55ba..af29db7ec28d 160000
--- a/src/submodules/googletest
+++ b/src/submodules/googletest
@@ -1 +1 @@
-Subproject commit c9461a9b55ba954df0489bab6420eb297bed846b
+Subproject commit af29db7ec28d6df1c7f0f745186884091e602e07
From de41c582fe8c0ed3afb53ebfc59086251c9da554 Mon Sep 17 00:00:00 2001
From: "dotnet-maestro[bot]"
<42748379+dotnet-maestro[bot]@users.noreply.github.com>
Date: Tue, 5 Apr 2022 16:07:24 -0700
Subject: [PATCH 10/21] Update dependencies from
https://github.com/dotnet/arcade build 20220328.5 (#41052)
Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Helix.Sdk
From Version 6.0.0-beta.22161.1 -> To Version 6.0.0-beta.22178.5
Co-authored-by: dotnet-maestro[bot]
---
eng/Version.Details.xml | 16 ++++++++--------
eng/Versions.props | 4 ++--
eng/common/templates/steps/source-build.yml | 4 ++--
global.json | 4 ++--
4 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index f3e02194d096..1be6aca6040b 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -280,22 +280,22 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
c24d9a9c91c5d04b7b4de71f1a9f33ac35e09663
-
+
https://github.com/dotnet/arcade
- 879df783283dfb44c7653493fdf7fd7b07ba6b01
+ f8c0d51185208227e582f76ac3c5003db237b689
-
+
https://github.com/dotnet/arcade
- 879df783283dfb44c7653493fdf7fd7b07ba6b01
+ f8c0d51185208227e582f76ac3c5003db237b689
-
+
https://github.com/dotnet/arcade
- 879df783283dfb44c7653493fdf7fd7b07ba6b01
+ f8c0d51185208227e582f76ac3c5003db237b689
-
+
https://github.com/dotnet/arcade
- 879df783283dfb44c7653493fdf7fd7b07ba6b01
+ f8c0d51185208227e582f76ac3c5003db237b689
diff --git a/eng/Versions.props b/eng/Versions.props
index bb2938612641..c88cf62def19 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -131,8 +131,8 @@
6.0.3
6.0.3
- 6.0.0-beta.22161.1
- 6.0.0-beta.22161.1
+ 6.0.0-beta.22178.5
+ 6.0.0-beta.22178.5
- <_TarArchiveOutputPath>$(TarArchiveOutputPath)
- <_TarArchiveOutputPath
- Condition="Exists('$(repoRoot)\.tools\tar.fromGit')">/$(TarArchiveOutputPath.Replace('\','/').Replace(':',''))
-
-
+ Outputs="$(ArchiveOutputPath)">
-
-
-
-
-
-
+ DestinationFile="$(ArchiveOutputPath)"
+ Overwrite="true"
+ Condition="'$(ArchiveExtension)' == '.zip'" />
+
+
- $(TargetingPackInstallerBaseName)-$(TargetingPackVersion).deb
+ $(TargetingPackInstallerBaseName)-$(TargetingPackVersion)-$(TargetArchitecture).deb
$(TargetDir)$(TargetFileName)
$(TargetingPackVersionPrefix)
diff --git a/src/Installers/Windows/TargetingPack/TargetingPack.wixproj b/src/Installers/Windows/TargetingPack/TargetingPack.wixproj
index 27894df71808..dc20b17662f0 100644
--- a/src/Installers/Windows/TargetingPack/TargetingPack.wixproj
+++ b/src/Installers/Windows/TargetingPack/TargetingPack.wixproj
@@ -66,7 +66,7 @@
$(InstallersOutputPath)
$(TargetingPackVersionPrefix)
$(TargetingPackZipVersion)-$(VersionSuffix)
- $(TargetingPackHarvestRoot)aspnetcore-targeting-pack-$(TargetingPackZipVersion).zip
+ $(TargetingPackHarvestRoot)aspnetcore-targeting-pack-$(TargetingPackZipVersion)-$(TargetRuntimeIdentifier).zip
From 8ca8c2cd7c96e03b2c41f07573cfa86de9cd6cc9 Mon Sep 17 00:00:00 2001
From: DotNet Bot
Date: Wed, 6 Apr 2022 05:43:12 +0000
Subject: [PATCH 13/21] [internal/release/6.0] Update dependencies from
dnceng/internal/dotnet-runtime
---
NuGet.config | 12 ++++++++++++
eng/Version.Details.xml | 28 ++++++++++++++--------------
eng/Versions.props | 14 +++++++-------
3 files changed, 33 insertions(+), 21 deletions(-)
diff --git a/NuGet.config b/NuGet.config
index 76ccfd79eeee..74d2f8b546d3 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -4,9 +4,15 @@
+
+
+
+
+
+
@@ -28,9 +34,15 @@
+
+
+
+
+
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 640bbfa0defb..0c2de08f4a17 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -177,9 +177,9 @@
https://github.com/dotnet/runtime
4822e3c3aa77eb82b2fb33c9321f923cf11ddde6
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- be98e88c760526452df94ef452fff4602fb5bded
+ d66e32ff6f54236c5bea85ca4e0d99f0fc7293e7
https://github.com/dotnet/runtime
@@ -245,33 +245,33 @@
https://github.com/dotnet/runtime
4822e3c3aa77eb82b2fb33c9321f923cf11ddde6
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- be98e88c760526452df94ef452fff4602fb5bded
+ d66e32ff6f54236c5bea85ca4e0d99f0fc7293e7
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- be98e88c760526452df94ef452fff4602fb5bded
+ d66e32ff6f54236c5bea85ca4e0d99f0fc7293e7
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- be98e88c760526452df94ef452fff4602fb5bded
+ d66e32ff6f54236c5bea85ca4e0d99f0fc7293e7
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- be98e88c760526452df94ef452fff4602fb5bded
+ d66e32ff6f54236c5bea85ca4e0d99f0fc7293e7
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- be98e88c760526452df94ef452fff4602fb5bded
+ d66e32ff6f54236c5bea85ca4e0d99f0fc7293e7
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- be98e88c760526452df94ef452fff4602fb5bded
+ d66e32ff6f54236c5bea85ca4e0d99f0fc7293e7
diff --git a/eng/Versions.props b/eng/Versions.props
index 72ca8c5f0047..a6cf369374e3 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -63,12 +63,12 @@
6.0.0
- 6.0.4
- 6.0.4
- 6.0.4
- 6.0.4
- 6.0.4
- 6.0.4-servicing.22164.4
+ 6.0.5
+ 6.0.5
+ 6.0.5
+ 6.0.5
+ 6.0.5
+ 6.0.5-servicing.22205.9
6.0.0
6.0.1
6.0.0
@@ -103,7 +103,7 @@
6.0.0
6.0.0
6.0.0
- 6.0.4-servicing.22164.4
+ 6.0.5-servicing.22205.9
6.0.0
6.0.0
6.0.1
From 29e093cf1b89e2b43b4dc752ff52c50cf8ec4996 Mon Sep 17 00:00:00 2001
From: Damian Edwards
Date: Wed, 6 Apr 2022 11:46:12 -0700
Subject: [PATCH 14/21] Backport UseProgramMain template option (#40945)
* Add option to project templates to use Program.Main instead of top-level statements (#40886)
Fixes #40944
* Update spa templates submodule
---
.editorconfig | 6 +-
.../.template.config/dotnetcli.host.json | 4 +
.../.template.config/ide.host.json | 6 +
.../.template.config/template.json | 22 ++
.../BlazorServerWeb-CSharp/Program.Main.cs | 169 ++++++++++++++
.../.template.config/dotnetcli.host.json | 4 +
.../.template.config/ide.host.json | 4 +
.../.template.config/template.json | 25 ++
.../Client/Program.Main.cs | 69 ++++++
.../Server/Program.Main.cs | 125 ++++++++++
.../.template.config/dotnetcli.host.json | 4 +
.../.template.config/ide.host.json | 6 +
.../.template.config/template.json | 22 ++
.../content/EmptyWeb-CSharp/Program.Main.cs | 14 ++
.../.template.config/dotnetcli.host.json | 4 +
.../.template.config/ide.host.json | 8 +-
.../.template.config/template.json | 22 ++
.../GrpcService-CSharp/Program.Main.cs | 25 ++
.../.template.config/dotnetcli.host.json | 4 +
.../.template.config/ide.host.json | 5 +-
.../.template.config/template.json | 22 ++
.../RazorPagesWeb-CSharp/Program.Main.cs | 155 +++++++++++++
.../.template.config/dotnetcli.host.json | 4 +
.../.template.config/ide.host.json | 5 +-
.../.template.config/template.json | 22 ++
.../content/StarterWeb-CSharp/Program.Main.cs | 159 +++++++++++++
.../.template.config/dotnetcli.host.json | 4 +
.../.template.config/ide.host.json | 4 +
.../.template.config/template.json | 22 ++
.../content/WebApi-CSharp/Program.Main.cs | 95 ++++++++
.../.template.config/dotnetcli.host.json | 4 +
.../.template.config/ide.host.json | 6 +
.../.template.config/template.json | 22 ++
.../content/Worker-CSharp/Program.Main.cs | 18 ++
.../Run-AngularProgramMain-Locally.ps1 | 12 +
.../scripts/Run-BlazorProgramMain-Locally.ps1 | 13 ++
.../Run-BlazorWasmProgramMain-Locally.ps1 | 13 ++
.../Run-EmptyWebProgramMain-Locally.ps1 | 12 +
.../scripts/Run-RazorProgramMain-Locally.ps1 | 9 +
.../scripts/Run-ReactProgramMain-Locally.ps1 | 12 +
.../Run-StarterwebProgramMain-Locally.ps1 | 12 +
.../scripts/Run-WebApiProgamMain-Locally.ps1 | 12 +
.../scripts/Run-WorkerProgramMain-Locally.ps1 | 12 +
.../scripts/Test-Template.ps1 | 4 +-
.../test/BlazorServerTemplateTest.cs | 14 +-
.../test/BlazorWasmTemplateTest.cs | 3 +
.../test/EmptyWebTemplateTest.cs | 11 +-
src/ProjectTemplates/test/GrpcTemplateTest.cs | 9 +-
src/ProjectTemplates/test/MvcTemplateTest.cs | 218 ++++++++----------
.../test/RazorPagesTemplateTest.cs | 23 +-
.../test/WebApiTemplateTest.cs | 22 +-
.../test/WorkerTemplateTest.cs | 9 +-
src/submodules/spa-templates | 2 +-
53 files changed, 1365 insertions(+), 147 deletions(-)
create mode 100644 src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/Program.Main.cs
create mode 100644 src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Program.Main.cs
create mode 100644 src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Program.Main.cs
create mode 100644 src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/Program.Main.cs
create mode 100644 src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Program.Main.cs
create mode 100644 src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/Program.Main.cs
create mode 100644 src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/Program.Main.cs
create mode 100644 src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.Main.cs
create mode 100644 src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/Program.Main.cs
create mode 100644 src/ProjectTemplates/scripts/Run-AngularProgramMain-Locally.ps1
create mode 100644 src/ProjectTemplates/scripts/Run-BlazorProgramMain-Locally.ps1
create mode 100644 src/ProjectTemplates/scripts/Run-BlazorWasmProgramMain-Locally.ps1
create mode 100644 src/ProjectTemplates/scripts/Run-EmptyWebProgramMain-Locally.ps1
create mode 100644 src/ProjectTemplates/scripts/Run-RazorProgramMain-Locally.ps1
create mode 100644 src/ProjectTemplates/scripts/Run-ReactProgramMain-Locally.ps1
create mode 100644 src/ProjectTemplates/scripts/Run-StarterwebProgramMain-Locally.ps1
create mode 100644 src/ProjectTemplates/scripts/Run-WebApiProgamMain-Locally.ps1
create mode 100644 src/ProjectTemplates/scripts/Run-WorkerProgramMain-Locally.ps1
diff --git a/.editorconfig b/.editorconfig
index d7ec0b83dec4..8583569cfc7d 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -208,7 +208,7 @@ dotnet_diagnostic.IDE0044.severity = warning
dotnet_diagnostic.IDE0073.severity = warning
file_header_template = Licensed to the .NET Foundation under one or more agreements.\nThe .NET Foundation licenses this file to you under the MIT license.
-[**/{test,samples,perf}/**.{cs,vb}]
+[{eng/tools/**.cs,**/{test,testassets,samples,Samples,perf,scripts}/**.cs}]
# CA1018: Mark attributes with AttributeUsageAttribute
dotnet_diagnostic.CA1018.severity = suggestion
# CA1507: Use nameof to express symbol names
@@ -241,6 +241,10 @@ dotnet_diagnostic.CA1844.severity = suggestion
dotnet_diagnostic.CA1845.severity = suggestion
# CA1846: Prefer AsSpan over Substring
dotnet_diagnostic.CA1846.severity = suggestion
+# CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters
+dotnet_diagnostic.CA1847.severity = suggestion
+# CA2007: Consider calling ConfigureAwait on the awaited task
+dotnet_diagnostic.CA2007.severity = suggestion
# CA2008: Do not create tasks without passing a TaskScheduler
dotnet_diagnostic.CA2008.severity = suggestion
# CA2012: Use ValueTask correctly
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/dotnetcli.host.json
index 3c34f96f85e3..02abad32e7eb 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/dotnetcli.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/dotnetcli.host.json
@@ -85,6 +85,10 @@
"CallsMicrosoftGraph": {
"longName": "calls-graph",
"shortName": ""
+ },
+ "UseProgramMain": {
+ "longName": "use-program-main",
+ "shortName": ""
}
},
"usageExamples": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/ide.host.json
index e891e5f2df97..947fd0caa52b 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/ide.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/ide.host.json
@@ -43,6 +43,12 @@
"useHttps": true
}
],
+ "symbolInfo": [
+ {
+ "id": "UseProgramMain",
+ "isVisible": true
+ }
+ ],
"disableHttpsSymbol": "NoHttps",
"supportsDocker": true
}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/template.json
index 254598a9cfe2..4b203fdd52b6 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/template.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/.template.config/template.json
@@ -34,6 +34,21 @@
"wwwroot/**"
],
"modifiers": [
+ {
+ "condition": "(!UseProgramMain)",
+ "exclude": [
+ "Program.Main.cs"
+ ]
+ },
+ {
+ "condition": "(UseProgramMain)",
+ "exclude": [
+ "Program.cs"
+ ],
+ "rename": {
+ "Program.Main.cs": "Program.cs"
+ }
+ },
{
"condition": "(!IndividualLocalAuth || UseLocalDB)",
"exclude": [
@@ -490,6 +505,13 @@
"datatype": "bool",
"description": "If specified, skips the automatic restore of the project on create.",
"defaultValue": "false"
+ },
+ "UseProgramMain": {
+ "type": "parameter",
+ "datatype": "bool",
+ "defaultValue": "false",
+ "displayName": "Do not use top-level statements",
+ "description": "Whether to generate an explicit Program class and Main method instead of top-level statements."
}
},
"primaryOutputs": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/Program.Main.cs
new file mode 100644
index 000000000000..92eb45d80a91
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/Program.Main.cs
@@ -0,0 +1,169 @@
+#if (OrganizationalAuth || IndividualB2CAuth)
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.OpenIdConnect;
+using Microsoft.Identity.Web;
+using Microsoft.Identity.Web.UI;
+#endif
+#if (WindowsAuth)
+using Microsoft.AspNetCore.Authentication.Negotiate;
+#endif
+#if (OrganizationalAuth)
+#if (MultiOrgAuth)
+using Microsoft.AspNetCore.Authentication.OpenIdConnect;
+#endif
+using Microsoft.AspNetCore.Authorization;
+#endif
+using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Components.Web;
+#if (IndividualLocalAuth)
+using Microsoft.AspNetCore.Components.Authorization;
+using Microsoft.AspNetCore.Identity;
+using Microsoft.AspNetCore.Identity.UI;
+#endif
+#if (OrganizationalAuth)
+using Microsoft.AspNetCore.Mvc.Authorization;
+#endif
+#if (IndividualLocalAuth)
+using Microsoft.EntityFrameworkCore;
+#endif
+#if (GenerateGraph)
+using Graph = Microsoft.Graph;
+#endif
+#if(MultiOrgAuth)
+using Microsoft.IdentityModel.Tokens;
+#endif
+#if (IndividualLocalAuth)
+using BlazorServerWeb_CSharp.Areas.Identity;
+#endif
+using BlazorServerWeb_CSharp.Data;
+
+namespace Company.WebApplication1;
+
+public class Program
+{
+ public static void Main(string[] args)
+ {
+ var builder = WebApplication.CreateBuilder(args);
+
+ // Add services to the container.
+ #if (IndividualLocalAuth)
+ var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
+ builder.Services.AddDbContext(options =>
+ #if (UseLocalDB)
+ options.UseSqlServer(connectionString));
+ #else
+ options.UseSqlite(connectionString));
+ #endif
+ builder.Services.AddDatabaseDeveloperPageExceptionFilter();
+ builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true)
+ .AddEntityFrameworkStores();
+ #elif (OrganizationalAuth)
+ #if (GenerateApiOrGraph)
+ var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' ');
+
+ #endif
+ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
+ #if (GenerateApiOrGraph)
+ .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
+ .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
+ #if (GenerateApi)
+ .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
+ #endif
+ #if (GenerateGraph)
+ .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
+ #endif
+ .AddInMemoryTokenCaches();
+ #else
+ .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
+ #endif
+ #elif (IndividualB2CAuth)
+ #if (GenerateApi)
+ var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' ');
+
+ #endif
+ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
+ #if (GenerateApi)
+ .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C"))
+ .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
+ .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
+ .AddInMemoryTokenCaches();
+ #else
+ .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C"));
+ #endif
+ #endif
+ #if (OrganizationalAuth || IndividualB2CAuth)
+ builder.Services.AddControllersWithViews()
+ .AddMicrosoftIdentityUI();
+
+ builder.Services.AddAuthorization(options =>
+ {
+ // By default, all incoming requests will be authorized according to the default policy
+ options.FallbackPolicy = options.DefaultPolicy;
+ });
+
+ #elif (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
+ builder.Services.AddRazorPages();
+ #if (OrganizationalAuth || IndividualB2CAuth)
+ builder.Services.AddServerSideBlazor()
+ .AddMicrosoftIdentityConsentHandler();
+ #else
+ builder.Services.AddServerSideBlazor();
+ #endif
+ #if (IndividualLocalAuth)
+ builder.Services.AddScoped>();
+ #endif
+ builder.Services.AddSingleton();
+
+ var app = builder.Build();
+
+ // Configure the HTTP request pipeline.
+ #if (IndividualLocalAuth)
+ if (app.Environment.IsDevelopment())
+ {
+ app.UseMigrationsEndPoint();
+ }
+ else
+ #else
+ if (!app.Environment.IsDevelopment())
+ #endif
+ {
+ app.UseExceptionHandler("/Error");
+ #if (RequiresHttps)
+ // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
+ app.UseHsts();
+ }
+
+ app.UseHttpsRedirection();
+ #else
+ }
+
+ #endif
+
+ app.UseStaticFiles();
+
+ app.UseRouting();
+
+ #if (OrganizationalAuth || IndividualAuth || WindowsAuth)
+ app.UseAuthentication();
+ app.UseAuthorization();
+
+ #endif
+ #if (OrganizationalAuth || IndividualAuth)
+ app.MapControllers();
+ #endif
+ app.MapBlazorHub();
+ app.MapFallbackToPage("/_Host");
+
+ app.Run();
+ }
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/dotnetcli.host.json
index 93b2c5a3bc03..3d2007dc5868 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/dotnetcli.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/dotnetcli.host.json
@@ -95,6 +95,10 @@
"CallsMicrosoftGraph": {
"longName": "calls-graph",
"shortName": ""
+ },
+ "UseProgramMain": {
+ "longName": "use-program-main",
+ "shortName": ""
}
}
}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/ide.host.json
index 9005a4d171a3..2ed03203a457 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/ide.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/ide.host.json
@@ -47,6 +47,10 @@
"text": "_Progressive Web Application"
},
"isVisible": "true"
+ },
+ {
+ "id": "UseProgramMain",
+ "isVisible": true
}
]
}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/template.json
index cd44728a4894..9b261b76d232 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/template.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/.template.config/template.json
@@ -94,6 +94,24 @@
"Client/wwwroot/icon-512.png"
]
},
+ {
+ "condition": "(!UseProgramMain)",
+ "exclude": [
+ "Server/Program.Main.cs",
+ "Client/Program.Main.cs"
+ ]
+ },
+ {
+ "condition": "(UseProgramMain)",
+ "exclude": [
+ "Server/Program.cs",
+ "Client/Program.cs"
+ ],
+ "rename": {
+ "Server/Program.Main.cs": "Server/Program.cs",
+ "Client/Program.Main.cs": "Client/Program.cs"
+ }
+ },
{
"condition": "(!IndividualLocalAuth || UseLocalDB)",
"exclude": [
@@ -591,6 +609,13 @@
"GenerateApiOrGraph": {
"type": "computed",
"value": "(GenerateApi || GenerateGraph)"
+ },
+ "UseProgramMain": {
+ "type": "parameter",
+ "datatype": "bool",
+ "defaultValue": "false",
+ "displayName": "Do not use top-level statements",
+ "description": "Whether to generate an explicit Program class and Main method instead of top-level statements."
}
},
"tags": {
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
new file mode 100644
index 000000000000..8b870e5dc9d3
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Program.Main.cs
@@ -0,0 +1,69 @@
+using Microsoft.AspNetCore.Components.Web;
+#if (!NoAuth && Hosted)
+using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
+#endif
+using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
+#if (Hosted)
+using ComponentsWebAssembly_CSharp.Client;
+#else
+using ComponentsWebAssembly_CSharp;
+#endif
+
+namespace Company.WebApplication1;
+
+public class Program
+{
+ public static async Task Main(string[] args)
+ {
+ var builder = WebAssemblyHostBuilder.CreateDefault(args);
+ builder.RootComponents.Add("#app");
+ builder.RootComponents.Add("head::after");
+
+ #if (!Hosted || NoAuth)
+ builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
+ #else
+ builder.Services.AddHttpClient("ComponentsWebAssembly_CSharp.ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
+ .AddHttpMessageHandler();
+
+ // Supply HttpClient instances that include access tokens when making requests to the server project
+ builder.Services.AddScoped(sp => sp.GetRequiredService().CreateClient("ComponentsWebAssembly_CSharp.ServerAPI"));
+ #endif
+ #if(!NoAuth)
+
+ #endif
+ #if (IndividualLocalAuth)
+ #if (Hosted)
+ builder.Services.AddApiAuthorization();
+ #else
+ builder.Services.AddOidcAuthentication(options =>
+ {
+ #if(MissingAuthority)
+ // Configure your authentication provider options here.
+ // For more information, see https://aka.ms/blazor-standalone-auth
+ #endif
+ builder.Configuration.Bind("Local", options.ProviderOptions);
+ });
+ #endif
+ #endif
+ #if (IndividualB2CAuth)
+ builder.Services.AddMsalAuthentication(options =>
+ {
+ builder.Configuration.Bind("AzureAdB2C", options.ProviderOptions.Authentication);
+ #if (Hosted)
+ options.ProviderOptions.DefaultAccessTokenScopes.Add("https://qualified.domain.name/api.id.uri/api-scope");
+ #endif
+ });
+ #endif
+ #if(OrganizationalAuth)
+ builder.Services.AddMsalAuthentication(options =>
+ {
+ builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
+ #if (Hosted)
+ options.ProviderOptions.DefaultAccessTokenScopes.Add("api://api.id.uri/api-scope");
+ #endif
+ });
+ #endif
+
+ await builder.Build().RunAsync();
+ }
+}
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
new file mode 100644
index 000000000000..31835439cd28
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Program.Main.cs
@@ -0,0 +1,125 @@
+#if (OrganizationalAuth || IndividualB2CAuth || IndividualLocalAuth)
+using Microsoft.AspNetCore.Authentication;
+#endif
+#if (OrganizationalAuth || IndividualB2CAuth)
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+#endif
+using Microsoft.AspNetCore.ResponseCompression;
+#if (IndividualLocalAuth)
+using Microsoft.EntityFrameworkCore;
+#endif
+#if (GenerateGraph)
+using Graph = Microsoft.Graph;
+#endif
+#if (OrganizationalAuth || IndividualB2CAuth)
+using Microsoft.Identity.Web;
+#endif
+#if (IndividualLocalAuth)
+using ComponentsWebAssembly_CSharp.Server.Data;
+using ComponentsWebAssembly_CSharp.Server.Models;
+#endif
+
+namespace Company.WebApplication1;
+
+public class Program
+{
+ public static void Main(string[] args)
+ {
+ var builder = WebApplication.CreateBuilder(args);
+
+ // Add services to the container.
+ #if (IndividualLocalAuth)
+ var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
+ builder.Services.AddDbContext(options =>
+ #if (UseLocalDB)
+ options.UseSqlServer(connectionString));
+ #else
+ options.UseSqlite(connectionString));
+ #endif
+ builder.Services.AddDatabaseDeveloperPageExceptionFilter();
+
+ builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true)
+ .AddEntityFrameworkStores();
+
+ builder.Services.AddIdentityServer()
+ .AddApiAuthorization();
+
+ builder.Services.AddAuthentication()
+ .AddIdentityServerJwt();
+ #endif
+ #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.AddControllersWithViews();
+ builder.Services.AddRazorPages();
+
+ var app = builder.Build();
+
+ // Configure the HTTP request pipeline.
+ if (app.Environment.IsDevelopment())
+ {
+ #if (IndividualLocalAuth)
+ app.UseMigrationsEndPoint();
+ #endif
+ app.UseWebAssemblyDebugging();
+ }
+ else
+ {
+ app.UseExceptionHandler("/Error");
+ #if (RequiresHttps)
+ // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
+ app.UseHsts();
+ #endif
+ }
+
+ #if (RequiresHttps)
+ app.UseHttpsRedirection();
+
+ #endif
+ app.UseBlazorFrameworkFiles();
+ app.UseStaticFiles();
+
+ app.UseRouting();
+
+ #if (IndividualLocalAuth)
+ app.UseIdentityServer();
+ #endif
+ #if (OrganizationalAuth || IndividualAuth)
+ app.UseAuthentication();
+ #endif
+ #if (!NoAuth)
+ app.UseAuthorization();
+
+ #endif
+
+ app.MapRazorPages();
+ app.MapControllers();
+ app.MapFallbackToFile("index.html");
+
+ app.Run();
+ }
+}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/dotnetcli.host.json
index d97858472b80..6f4f4fb8936d 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/dotnetcli.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/dotnetcli.host.json
@@ -27,6 +27,10 @@
"NoHttps": {
"longName": "no-https",
"shortName": ""
+ },
+ "UseProgramMain": {
+ "longName": "use-program-main",
+ "shortName": ""
}
},
"usageExamples": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/ide.host.json
index 751a95c5b2ff..f30c4753e2a8 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/ide.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/ide.host.json
@@ -20,5 +20,11 @@
"useHttps": true
}
],
+ "symbolInfo": [
+ {
+ "id": "UseProgramMain",
+ "isVisible": true
+ }
+ ],
"disableHttpsSymbol": "NoHttps"
}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/template.json
index 3b7edb411a86..c85130f420f9 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/template.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/.template.config/template.json
@@ -29,6 +29,21 @@
"exclude": [
"Properties/launchSettings.json"
]
+ },
+ {
+ "condition": "(!UseProgramMain)",
+ "exclude": [
+ "Program.Main.cs"
+ ]
+ },
+ {
+ "condition": "(UseProgramMain)",
+ "exclude": [
+ "Program.cs"
+ ],
+ "rename": {
+ "Program.Main.cs": "Program.cs"
+ }
}
]
}
@@ -156,6 +171,13 @@
"datatype": "bool",
"defaultValue": "false",
"description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth."
+ },
+ "UseProgramMain": {
+ "type": "parameter",
+ "datatype": "bool",
+ "defaultValue": "false",
+ "displayName": "Do not use top-level statements",
+ "description": "Whether to generate an explicit Program class and Main method instead of top-level statements."
}
},
"primaryOutputs": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/Program.Main.cs
new file mode 100644
index 000000000000..6a106499828e
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWeb-CSharp/Program.Main.cs
@@ -0,0 +1,14 @@
+namespace Company.WebApplication1;
+
+public class Program
+{
+ public static void Main(string[] args)
+ {
+ var builder = WebApplication.CreateBuilder(args);
+ var app = builder.Build();
+
+ app.MapGet("/", () => "Hello World!");
+
+ app.Run();
+ }
+}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/dotnetcli.host.json
index 684bc1e734f3..ded3cbf35f23 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/dotnetcli.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/dotnetcli.host.json
@@ -14,6 +14,10 @@
"ExcludeLaunchSettings": {
"longName": "exclude-launch-settings",
"shortName": ""
+ },
+ "UseProgramMain": {
+ "longName": "use-program-main",
+ "shortName": ""
}
},
"usageExamples": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/ide.host.json
index 2cb41909519c..5c3a869512fd 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/ide.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/ide.host.json
@@ -2,5 +2,11 @@
"$schema": "http://json.schemastore.org/vs-2017.3.host",
"order": 500,
"icon": "ide/gRPC.png",
- "supportsDocker": true
+ "supportsDocker": true,
+ "symbolInfo": [
+ {
+ "id": "UseProgramMain",
+ "isVisible": true
+ }
+ ]
}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/template.json
index 2fd14ec9251f..fc4288d87384 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/template.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/.template.config/template.json
@@ -26,6 +26,21 @@
"exclude": [
"Properties/launchSettings.json"
]
+ },
+ {
+ "condition": "(!UseProgramMain)",
+ "exclude": [
+ "Program.Main.cs"
+ ]
+ },
+ {
+ "condition": "(UseProgramMain)",
+ "exclude": [
+ "Program.cs"
+ ],
+ "rename": {
+ "Program.Main.cs": "Program.cs"
+ }
}
]
}
@@ -102,6 +117,13 @@
"fallbackVariableName": "kestrelHttpsPortGenerated"
},
"replaces": "5001"
+ },
+ "UseProgramMain": {
+ "type": "parameter",
+ "datatype": "bool",
+ "defaultValue": "false",
+ "displayName": "Do not use top-level statements",
+ "description": "Whether to generate an explicit Program class and Main method instead of top-level statements."
}
},
"primaryOutputs": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Program.Main.cs
new file mode 100644
index 000000000000..ec1af1a7e9c6
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/GrpcService-CSharp/Program.Main.cs
@@ -0,0 +1,25 @@
+using GrpcService_CSharp.Services;
+
+namespace Company.WebApplication1;
+
+public class Program
+{
+ public static void Main(string[] args)
+ {
+ var builder = WebApplication.CreateBuilder(args);
+
+ // Additional configuration is required to successfully run gRPC on macOS.
+ // For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
+
+ // Add services to the container.
+ builder.Services.AddGrpc();
+
+ var app = builder.Build();
+
+ // Configure the HTTP request pipeline.
+ app.MapGrpcService();
+ app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
+
+ app.Run();
+ }
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/dotnetcli.host.json
index 6ce1fbe6eb27..a00ae64f281e 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/dotnetcli.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/dotnetcli.host.json
@@ -85,6 +85,10 @@
"CallsMicrosoftGraph": {
"longName": "calls-graph",
"shortName": ""
+ },
+ "UseProgramMain": {
+ "longName": "use-program-main",
+ "shortName": ""
}
},
"usageExamples": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/ide.host.json
index f176b8df2a9c..0dc542e09b82 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/ide.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/ide.host.json
@@ -45,7 +45,10 @@
}
],
"symbolInfo": [
-
+ {
+ "id": "UseProgramMain",
+ "isVisible": true
+ }
],
"disableHttpsSymbol": "NoHttps"
}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/template.json
index d7226586d37d..989dbb8ab86b 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/template.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/.template.config/template.json
@@ -94,6 +94,21 @@
"exclude": [
"Data/SqlServer/**"
]
+ },
+ {
+ "condition": "(!UseProgramMain)",
+ "exclude": [
+ "Program.Main.cs"
+ ]
+ },
+ {
+ "condition": "(UseProgramMain)",
+ "exclude": [
+ "Program.cs"
+ ],
+ "rename": {
+ "Program.Main.cs": "Program.cs"
+ }
}
]
}
@@ -406,6 +421,13 @@
"GenerateApiOrGraph": {
"type": "computed",
"value": "(GenerateApi || GenerateGraph)"
+ },
+ "UseProgramMain": {
+ "type": "parameter",
+ "datatype": "bool",
+ "defaultValue": "false",
+ "displayName": "Do not use top-level statements",
+ "description": "Whether to generate an explicit Program class and Main method instead of top-level statements."
}
},
"primaryOutputs": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/Program.Main.cs
new file mode 100644
index 000000000000..3a1a1d68cc06
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/Program.Main.cs
@@ -0,0 +1,155 @@
+#if (OrganizationalAuth || IndividualB2CAuth)
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.OpenIdConnect;
+using Microsoft.AspNetCore.Authorization;
+#endif
+#if (WindowsAuth)
+using Microsoft.AspNetCore.Authentication.Negotiate;
+#endif
+#if (IndividualLocalAuth)
+using Microsoft.AspNetCore.Identity;
+#endif
+#if (OrganizationalAuth)
+using Microsoft.AspNetCore.Mvc.Authorization;
+#endif
+#if (IndividualLocalAuth)
+using Microsoft.EntityFrameworkCore;
+#endif
+#if (OrganizationalAuth || IndividualB2CAuth)
+using Microsoft.Identity.Web;
+using Microsoft.Identity.Web.UI;
+#endif
+#if (MultiOrgAuth)
+using Microsoft.IdentityModel.Tokens;
+#endif
+#if (GenerateGraph)
+using Graph = Microsoft.Graph;
+#endif
+#if (IndividualLocalAuth)
+using Company.WebApplication1.Data;
+#endif
+#if (OrganizationalAuth || IndividualB2CAuth || IndividualLocalAuth || MultiOrgAuth || GenerateGraph || WindowsAuth)
+
+#endif
+namespace Company.WebApplication1;
+
+public class Program
+{
+ public static void Main(string[] args)
+ {
+ var builder = WebApplication.CreateBuilder(args);
+
+ // Add services to the container.
+ #if (IndividualLocalAuth)
+ var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
+ builder.Services.AddDbContext(options =>
+ #if (UseLocalDB)
+ options.UseSqlServer(connectionString));
+ #else
+ options.UseSqlite(connectionString));
+ #endif
+ builder.Services.AddDatabaseDeveloperPageExceptionFilter();
+
+ builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true)
+ .AddEntityFrameworkStores();
+ #elif (OrganizationalAuth)
+ #if (GenerateApiOrGraph)
+ var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' ');
+
+ #endif
+ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
+ #if (GenerateApiOrGraph)
+ .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
+ .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
+ #if (GenerateApi)
+ .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
+ #endif
+ #if (GenerateGraph)
+ .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
+ #endif
+ .AddInMemoryTokenCaches();
+ #else
+ .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
+ #endif
+ #elif (IndividualB2CAuth)
+ #if (GenerateApi)
+ var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' ');
+
+ #endif
+ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
+ #if (GenerateApi)
+ .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C"))
+ .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
+ .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
+ .AddInMemoryTokenCaches();
+ #else
+ .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C"));
+ #endif
+ #endif
+ #if (OrganizationalAuth)
+
+ builder.Services.AddAuthorization(options =>
+ {
+ // By default, all incoming requests will be authorized according to the default policy.
+ options.FallbackPolicy = options.DefaultPolicy;
+ });
+ builder.Services.AddRazorPages()
+ .AddMicrosoftIdentityUI();
+ #elif (IndividualB2CAuth)
+ builder.Services.AddRazorPages()
+ .AddMicrosoftIdentityUI();
+ #elif (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;
+ });
+ builder.Services.AddRazorPages();
+ #else
+ builder.Services.AddRazorPages();
+ #endif
+
+ var app = builder.Build();
+
+ // Configure the HTTP request pipeline.
+ #if (IndividualLocalAuth)
+ if (app.Environment.IsDevelopment())
+ {
+ app.UseMigrationsEndPoint();
+ }
+ else
+ #else
+ if (!app.Environment.IsDevelopment())
+ #endif
+ {
+ app.UseExceptionHandler("/Error");
+ #if (RequiresHttps)
+ // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
+ app.UseHsts();
+ }
+
+ app.UseHttpsRedirection();
+ #else
+ }
+ #endif
+ app.UseStaticFiles();
+
+ app.UseRouting();
+
+ #if (OrganizationalAuth || IndividualAuth || WindowsAuth)
+ app.UseAuthentication();
+ #endif
+ app.UseAuthorization();
+
+ app.MapRazorPages();
+ #if (IndividualB2CAuth || OrganizationalAuth)
+ app.MapControllers();
+ #endif
+
+ app.Run();
+ }
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/dotnetcli.host.json
index 3c34f96f85e3..02abad32e7eb 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/dotnetcli.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/dotnetcli.host.json
@@ -85,6 +85,10 @@
"CallsMicrosoftGraph": {
"longName": "calls-graph",
"shortName": ""
+ },
+ "UseProgramMain": {
+ "longName": "use-program-main",
+ "shortName": ""
}
},
"usageExamples": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/ide.host.json
index 12bb6ec5db17..995a75bea9a0 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/ide.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/ide.host.json
@@ -45,7 +45,10 @@
}
],
"symbolInfo": [
-
+ {
+ "id": "UseProgramMain",
+ "isVisible": true
+ }
],
"disableHttpsSymbol": "NoHttps"
}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/template.json
index b67fe4f719ef..558a4e818d35 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/template.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/.template.config/template.json
@@ -90,6 +90,21 @@
"exclude": [
"Data/SqlServer/**"
]
+ },
+ {
+ "condition": "(!UseProgramMain)",
+ "exclude": [
+ "Program.Main.cs"
+ ]
+ },
+ {
+ "condition": "(UseProgramMain)",
+ "exclude": [
+ "Program.cs"
+ ],
+ "rename": {
+ "Program.Main.cs": "Program.cs"
+ }
}
]
}
@@ -402,6 +417,13 @@
"GenerateApiOrGraph": {
"type": "computed",
"value": "(GenerateApi || GenerateGraph)"
+ },
+ "UseProgramMain": {
+ "type": "parameter",
+ "datatype": "bool",
+ "defaultValue": "false",
+ "displayName": "Do not use top-level statements",
+ "description": "Whether to generate an explicit Program class and Main method instead of top-level statements."
}
},
"primaryOutputs": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/Program.Main.cs
new file mode 100644
index 000000000000..5fda9092d06a
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/Program.Main.cs
@@ -0,0 +1,159 @@
+#if (OrganizationalAuth || IndividualB2CAuth)
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Authentication.OpenIdConnect;
+#endif
+#if (WindowsAuth)
+using Microsoft.AspNetCore.Authentication.Negotiate;
+#endif
+#if (IndividualLocalAuth)
+using Microsoft.AspNetCore.Identity;
+#endif
+#if (OrganizationalAuth)
+using Microsoft.AspNetCore.Mvc.Authorization;
+#endif
+#if (IndividualLocalAuth)
+using Microsoft.EntityFrameworkCore;
+#endif
+#if (OrganizationalAuth || IndividualB2CAuth)
+using Microsoft.Identity.Web;
+using Microsoft.Identity.Web.UI;
+#endif
+#if (MultiOrgAuth)
+using Microsoft.IdentityModel.Tokens;
+#endif
+#if (GenerateGraph)
+using Graph = Microsoft.Graph;
+#endif
+#if (IndividualLocalAuth)
+using Company.WebApplication1.Data;
+#endif
+#if (OrganizationalAuth || IndividualB2CAuth || IndividualLocalAuth || MultiOrgAuth || GenerateGraph || WindowsAuth)
+
+#endif
+namespace Company.WebApplication1;
+
+public class Program
+{
+ public static void Main(string[] args)
+ {
+ var builder = WebApplication.CreateBuilder(args);
+
+ // Add services to the container.
+ #if (IndividualLocalAuth)
+ var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
+ builder.Services.AddDbContext(options =>
+ #if (UseLocalDB)
+ options.UseSqlServer(connectionString));
+ #else
+ options.UseSqlite(connectionString));
+ #endif
+ builder.Services.AddDatabaseDeveloperPageExceptionFilter();
+
+ builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true)
+ .AddEntityFrameworkStores();
+ #elif (OrganizationalAuth)
+ #if (GenerateApiOrGraph)
+ var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' ');
+
+ #endif
+ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
+ #if (GenerateApiOrGraph)
+ .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
+ .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
+ #if (GenerateApi)
+ .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
+ #endif
+ #if (GenerateGraph)
+ .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
+ #endif
+ .AddInMemoryTokenCaches();
+ #else
+ .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
+ #endif
+ #elif (IndividualB2CAuth)
+ #if (GenerateApi)
+ var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' ');
+
+ #endif
+ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
+ #if (GenerateApi)
+ .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C"))
+ .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
+ .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
+ .AddInMemoryTokenCaches();
+ #else
+ .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C"));
+ #endif
+ #endif
+ #if (OrganizationalAuth)
+
+ builder.Services.AddControllersWithViews(options =>
+ {
+ var policy = new AuthorizationPolicyBuilder()
+ .RequireAuthenticatedUser()
+ .Build();
+ options.Filters.Add(new AuthorizeFilter(policy));
+ });
+ #else
+ builder.Services.AddControllersWithViews();
+ #endif
+ #if (OrganizationalAuth || IndividualB2CAuth)
+ builder.Services.AddRazorPages()
+ .AddMicrosoftIdentityUI();
+ #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;
+ });
+ builder.Services.AddRazorPages();
+ #endif
+
+ var app = builder.Build();
+
+ // Configure the HTTP request pipeline.
+ #if (IndividualLocalAuth)
+ if (app.Environment.IsDevelopment())
+ {
+ app.UseMigrationsEndPoint();
+ }
+ else
+ #else
+ if (!app.Environment.IsDevelopment())
+ #endif
+ {
+ app.UseExceptionHandler("/Home/Error");
+ #if (RequiresHttps)
+ // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
+ app.UseHsts();
+ }
+
+ app.UseHttpsRedirection();
+ #else
+ }
+ #endif
+ app.UseStaticFiles();
+
+ app.UseRouting();
+
+ #if (OrganizationalAuth || IndividualAuth || WindowsAuth)
+ app.UseAuthentication();
+ #endif
+ app.UseAuthorization();
+
+ app.MapControllerRoute(
+ name: "default",
+ pattern: "{controller=Home}/{action=Index}/{id?}");
+ #if (OrganizationalAuth || IndividualAuth)
+ app.MapRazorPages();
+ #endif
+
+ app.Run();
+ }
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/dotnetcli.host.json
index 9b97a6182066..79217f16803f 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/dotnetcli.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/dotnetcli.host.json
@@ -85,6 +85,10 @@
"DisableOpenAPI": {
"longName": "no-openapi",
"shortName": ""
+ },
+ "UseProgramMain": {
+ "longName": "use-program-main",
+ "shortName": ""
}
},
"usageExamples": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/ide.host.json
index c8fdd64b6acd..19355a4eecac 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/ide.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/ide.host.json
@@ -55,6 +55,10 @@
"invertBoolean": true,
"isVisible": true,
"defaultValue": true
+ },
+ {
+ "id": "UseProgramMain",
+ "isVisible": true
}
],
"disableHttpsSymbol": "NoHttps"
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 ee1f9c886b38..5c9b53aedcd1 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
@@ -37,6 +37,21 @@
"Properties/launchSettings.json"
]
},
+ {
+ "condition": "(!UseProgramMain)",
+ "exclude": [
+ "Program.Main.cs"
+ ]
+ },
+ {
+ "condition": "(UseProgramMain && !UseMinimalAPIs)",
+ "exclude": [
+ "Program.cs"
+ ],
+ "rename": {
+ "Program.Main.cs": "Program.cs"
+ }
+ },
{
"condition": "(UseMinimalAPIs)",
"exclude": [
@@ -364,6 +379,13 @@
"UseControllers": {
"type": "computed",
"value": "(!UseMinimalAPIs)"
+ },
+ "UseProgramMain": {
+ "type": "parameter",
+ "datatype": "bool",
+ "defaultValue": "false",
+ "displayName": "Do not use top-level statements",
+ "description": "Whether to generate an explicit Program class and Main method instead of top-level statements."
}
},
"primaryOutputs": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.Main.cs
new file mode 100644
index 000000000000..a0c9ad67e817
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Program.Main.cs
@@ -0,0 +1,95 @@
+#if (OrganizationalAuth || IndividualB2CAuth)
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+#endif
+#if (WindowsAuth)
+using Microsoft.AspNetCore.Authentication.Negotiate;
+#endif
+#if (GenerateGraph)
+using Graph = Microsoft.Graph;
+#endif
+#if (OrganizationalAuth || IndividualB2CAuth)
+using Microsoft.Identity.Web;
+#endif
+#if (OrganizationalAuth || IndividualB2CAuth || GenerateGraph || WindowsAuth)
+
+#endif
+namespace Company.WebApplication1;
+
+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 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();
+
+ app.MapControllers();
+
+ app.Run();
+ }
+}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/dotnetcli.host.json
index b1cf98e39bb8..36493a3a4ac7 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/dotnetcli.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/dotnetcli.host.json
@@ -11,6 +11,10 @@
"ExcludeLaunchSettings": {
"longName": "exclude-launch-settings",
"shortName": ""
+ },
+ "UseProgramMain": {
+ "longName": "use-program-main",
+ "shortName": ""
}
},
"usageExamples": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/ide.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/ide.host.json
index 13a025d034fa..59f260a583df 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/ide.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/ide.host.json
@@ -3,4 +3,10 @@
"order": 300,
"icon": "ide/Worker.png",
"supportsDocker": true,
+ "symbolInfo": [
+ {
+ "id": "UseProgramMain",
+ "isVisible": true
+ }
+ ]
}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/template.json
index 19358bf86a30..d2789afed3ff 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/template.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/.template.config/template.json
@@ -30,6 +30,21 @@
"exclude": [
"Properties/launchSettings.json"
]
+ },
+ {
+ "condition": "(!UseProgramMain)",
+ "exclude": [
+ "Program.Main.cs"
+ ]
+ },
+ {
+ "condition": "(UseProgramMain)",
+ "exclude": [
+ "Program.cs"
+ ],
+ "rename": {
+ "Program.Main.cs": "Program.cs"
+ }
}
]
}
@@ -67,6 +82,13 @@
"datatype": "bool",
"description": "If specified, skips the automatic restore of the project on create.",
"defaultValue": "false"
+ },
+ "UseProgramMain": {
+ "type": "parameter",
+ "datatype": "bool",
+ "defaultValue": "false",
+ "displayName": "Do not use top-level statements",
+ "description": "Whether to generate an explicit Program class and Main method instead of top-level statements."
}
},
"primaryOutputs": [
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/Program.Main.cs
new file mode 100644
index 000000000000..d69747f38d51
--- /dev/null
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/Worker-CSharp/Program.Main.cs
@@ -0,0 +1,18 @@
+using Company.Application1;
+
+namespace Company.WebApplication1;
+
+public class Program
+{
+ public static void Main(string[] args)
+ {
+ IHost host = Host.CreateDefaultBuilder(args)
+ .ConfigureServices(services =>
+ {
+ services.AddHostedService();
+ })
+ .Build();
+
+ host.Run();
+ }
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/scripts/Run-AngularProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-AngularProgramMain-Locally.ps1
new file mode 100644
index 000000000000..93127bb08be0
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-AngularProgramMain-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 "angular" "angular --use-program-main" "Microsoft.DotNet.Web.Spa.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-BlazorProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-BlazorProgramMain-Locally.ps1
new file mode 100644
index 000000000000..3d9fdd64a70d
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-BlazorProgramMain-Locally.ps1
@@ -0,0 +1,13 @@
+#!/usr/bin/env pwsh
+#requires -version 4
+
+# This script packages, installs and creates a template to help with rapid iteration in the templating area.
+[CmdletBinding(PositionalBinding = $false)]
+param()
+
+Set-StrictMode -Version 2
+$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
diff --git a/src/ProjectTemplates/scripts/Run-BlazorWasmProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-BlazorWasmProgramMain-Locally.ps1
new file mode 100644
index 000000000000..7c8755a8bba3
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-BlazorWasmProgramMain-Locally.ps1
@@ -0,0 +1,13 @@
+#!/usr/bin/env pwsh
+#requires -version 4
+
+# This script packages, installs and creates a template to help with rapid iteration in the templating area.
+[CmdletBinding(PositionalBinding = $false)]
+param()
+
+Set-StrictMode -Version 2
+$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
diff --git a/src/ProjectTemplates/scripts/Run-EmptyWebProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-EmptyWebProgramMain-Locally.ps1
new file mode 100644
index 000000000000..7453063baf21
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-EmptyWebProgramMain-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 "web" "web --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-RazorProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-RazorProgramMain-Locally.ps1
new file mode 100644
index 000000000000..4224cf985dd2
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-RazorProgramMain-Locally.ps1
@@ -0,0 +1,9 @@
+#!/usr/bin/env powershell
+#requires -version 4
+
+[CmdletBinding(PositionalBinding = $false)]
+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
diff --git a/src/ProjectTemplates/scripts/Run-ReactProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-ReactProgramMain-Locally.ps1
new file mode 100644
index 000000000000..df61a5a11740
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-ReactProgramMain-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 "react" "react --use-program-main" "Microsoft.DotNet.Web.Spa.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-StarterwebProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-StarterwebProgramMain-Locally.ps1
new file mode 100644
index 000000000000..076106d3e861
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-StarterwebProgramMain-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 "mvc" "mvc -au Individual --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-WebApiProgamMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-WebApiProgamMain-Locally.ps1
new file mode 100644
index 000000000000..41f794b7eaaf
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-WebApiProgamMain-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" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Run-WorkerProgramMain-Locally.ps1 b/src/ProjectTemplates/scripts/Run-WorkerProgramMain-Locally.ps1
new file mode 100644
index 000000000000..9e0aa3d4607b
--- /dev/null
+++ b/src/ProjectTemplates/scripts/Run-WorkerProgramMain-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 "worker" "worker --use-program-main" "Microsoft.DotNet.Web.ProjectTemplates.6.0.6.0.0-dev.nupkg" $false
diff --git a/src/ProjectTemplates/scripts/Test-Template.ps1 b/src/ProjectTemplates/scripts/Test-Template.ps1
index 349174ad3d06..05cf0ef7128b 100644
--- a/src/ProjectTemplates/scripts/Test-Template.ps1
+++ b/src/ProjectTemplates/scripts/Test-Template.ps1
@@ -64,7 +64,9 @@ function Test-Template($templateName, $templateArgs, $templateNupkg, $isBlazorWa
if ($isBlazorWasmHosted) {
Push-Location Server
}
- dotnet.exe ef migrations add mvc
+ if ($templateArgs -match '-au') {
+ dotnet.exe ef migrations add mvc
+ }
dotnet.exe publish --configuration Release
Set-Location .\bin\Release\net6.0\publish
if ($isBlazorWasm -eq $false) {
diff --git a/src/ProjectTemplates/test/BlazorServerTemplateTest.cs b/src/ProjectTemplates/test/BlazorServerTemplateTest.cs
index 432c85043bd7..104f2304020d 100644
--- a/src/ProjectTemplates/test/BlazorServerTemplateTest.cs
+++ b/src/ProjectTemplates/test/BlazorServerTemplateTest.cs
@@ -26,18 +26,26 @@ public BlazorServerTemplateTest(ProjectFactoryFixture projectFactory)
[Fact]
public Task BlazorServerTemplateWorks_NoAuth() => CreateBuildPublishAsync("blazorservernoauth");
+ [Fact]
+ public Task BlazorServerTemplateWorks_ProgamMainNoAuth() => CreateBuildPublishAsync("blazorservernoauth", args: new [] { "--use-program-main" });
+
[Theory]
- [InlineData(true)]
- [InlineData(false)]
+ [InlineData(true, null)]
+ [InlineData(true, new string[] { "--use-program-main" })]
+ [InlineData(false, null)]
+ [InlineData(false, new string[] { "--use-program-main" })]
[SkipOnHelix("https://github.com/dotnet/aspnetcore/issues/30825", Queues = "All.OSX")]
- public Task BlazorServerTemplateWorks_IndividualAuth(bool useLocalDB) => CreateBuildPublishAsync("blazorserverindividual" + (useLocalDB ? "uld" : ""));
+ public Task BlazorServerTemplateWorks_IndividualAuth(bool useLocalDB, string[] args) => CreateBuildPublishAsync("blazorserverindividual" + (useLocalDB ? "uld" : "", 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);
diff --git a/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs b/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs
index 97a580dddd8b..dae6148d213a 100644
--- a/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs
+++ b/src/ProjectTemplates/test/BlazorWasmTemplateTest.cs
@@ -37,6 +37,9 @@ public async Task BlazorWasmStandaloneTemplateCanCreateBuildPublish()
[Fact]
public Task BlazorWasmHostedTemplateCanCreateBuildPublish() => CreateBuildPublishAsync("blazorhosted", args: new[] { "--hosted" }, serverProject: true);
+ [Fact]
+ public Task BlazorWasmHostedTemplateWithProgamMainCanCreateBuildPublish() => CreateBuildPublishAsync("blazorhosted", args: new[] { "--use-program-main", "--hosted" }, serverProject: true);
+
[Fact]
public Task BlazorWasmStandalonePwaTemplateCanCreateBuildPublish() => CreateBuildPublishAsync("blazorstandalonepwa", args: new[] { "--pwa" });
diff --git a/src/ProjectTemplates/test/EmptyWebTemplateTest.cs b/src/ProjectTemplates/test/EmptyWebTemplateTest.cs
index e90ccbf5b94c..7468a587b41e 100644
--- a/src/ProjectTemplates/test/EmptyWebTemplateTest.cs
+++ b/src/ProjectTemplates/test/EmptyWebTemplateTest.cs
@@ -38,17 +38,24 @@ public async Task EmptyWebTemplateCSharp()
await EmtpyTemplateCore(languageOverride: null);
}
+ [ConditionalFact]
+ [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" });
+ }
+
[Fact]
public async Task EmptyWebTemplateFSharp()
{
await EmtpyTemplateCore("F#");
}
- private async Task EmtpyTemplateCore(string languageOverride)
+ private async Task EmtpyTemplateCore(string languageOverride, string[] args = null)
{
var project = await ProjectFactory.GetOrCreateProject("empty" + (languageOverride == "F#" ? "fsharp" : "csharp"), Output);
- var createResult = await project.RunDotNetNewAsync("web", language: languageOverride);
+ var createResult = await project.RunDotNetNewAsync("web", args: args, language: languageOverride);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
// Avoid the F# compiler. See https://github.com/dotnet/aspnetcore/issues/14022
diff --git a/src/ProjectTemplates/test/GrpcTemplateTest.cs b/src/ProjectTemplates/test/GrpcTemplateTest.cs
index 585ac0bfb457..d26d0f8623a6 100644
--- a/src/ProjectTemplates/test/GrpcTemplateTest.cs
+++ b/src/ProjectTemplates/test/GrpcTemplateTest.cs
@@ -34,14 +34,17 @@ public ITestOutputHelper Output
}
}
- [ConditionalFact]
+ [ConditionalTheory]
[SkipOnHelix("Not supported queues", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
[SkipOnAlpine("https://github.com/grpc/grpc/issues/18338")]
- public async Task GrpcTemplate()
+ [InlineData(true)]
+ [InlineData(false)]
+ public async Task GrpcTemplate(bool useProgramMain)
{
var project = await ProjectFactory.GetOrCreateProject("grpc", Output);
- var createResult = await project.RunDotNetNewAsync("grpc");
+ var args = useProgramMain ? new [] { "--use-program-main" } : null;
+ var createResult = await project.RunDotNetNewAsync("grpc", args: args);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
var publishResult = await project.RunDotNetPublishAsync();
diff --git a/src/ProjectTemplates/test/MvcTemplateTest.cs b/src/ProjectTemplates/test/MvcTemplateTest.cs
index 47045d6972aa..a5d6bec38066 100644
--- a/src/ProjectTemplates/test/MvcTemplateTest.cs
+++ b/src/ProjectTemplates/test/MvcTemplateTest.cs
@@ -43,11 +43,15 @@ public ITestOutputHelper Output
[SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
public async Task MvcTemplate_NoAuthCSharp() => await MvcTemplateCore(languageOverride: null);
- private async Task MvcTemplateCore(string languageOverride)
+ [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" });
+
+ private async Task MvcTemplateCore(string languageOverride, string[] args = null)
{
var project = await ProjectFactory.GetOrCreateProject("mvcnoauth" + (languageOverride == "F#" ? "fsharp" : "csharp"), Output);
- var createResult = await project.RunDotNetNewAsync("mvc", language: languageOverride);
+ var createResult = await project.RunDotNetNewAsync("mvc", language: languageOverride, args: args);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
var projectExtension = languageOverride == "F#" ? "fsproj" : "csproj";
@@ -75,10 +79,10 @@ private async Task MvcTemplateCore(string languageOverride)
Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", project, buildResult));
IEnumerable menuLinks = new List {
- PageUrls.HomeUrl,
- PageUrls.HomeUrl,
- PageUrls.PrivacyFullUrl
- };
+ PageUrls.HomeUrl,
+ PageUrls.HomeUrl,
+ PageUrls.PrivacyFullUrl
+ };
var footerLinks = new string[] { PageUrls.PrivacyFullUrl };
@@ -116,14 +120,17 @@ private async Task MvcTemplateCore(string languageOverride)
}
[ConditionalTheory]
- [InlineData(true)]
- [InlineData(false)]
+ [InlineData(true, false)]
+ [InlineData(true, true)]
+ [InlineData(false, false)]
+ [InlineData(false, 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)
+ public async Task MvcTemplate_IndividualAuth(bool useLocalDB, bool useProgramMain)
{
var project = await ProjectFactory.GetOrCreateProject("mvcindividual" + (useLocalDB ? "uld" : ""), Output);
- var createResult = await project.RunDotNetNewAsync("mvc", auth: "Individual", useLocalDB: useLocalDB);
+ var args = useProgramMain ? new [] { "--use-program-main" } : null;
+ var createResult = await project.RunDotNetNewAsync("mvc", auth: "Individual", useLocalDB: useLocalDB, args: args);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
var projectFileContents = project.ReadFile($"{project.ProjectName}.csproj");
@@ -148,72 +155,72 @@ public async Task MvcTemplate_IndividualAuth(bool useLocalDB)
// Note: if any links are updated here, RazorPagesTemplateTest.cs should be updated as well
var pages = new List {
- new Page
- {
- Url = PageUrls.ForgotPassword,
- Links = new string [] {
- PageUrls.HomeUrl,
- PageUrls.HomeUrl,
- PageUrls.PrivacyUrl,
- PageUrls.RegisterUrl,
- PageUrls.LoginUrl,
- PageUrls.PrivacyUrl
- }
- },
- new Page
- {
- Url = PageUrls.HomeUrl,
- Links = new string[] {
- PageUrls.HomeUrl,
- PageUrls.HomeUrl,
- PageUrls.PrivacyUrl,
- PageUrls.RegisterUrl,
- PageUrls.LoginUrl,
- PageUrls.DocsUrl,
- PageUrls.PrivacyUrl
- }
- },
- new Page
- {
- Url = PageUrls.PrivacyFullUrl,
- Links = new string[] {
- PageUrls.HomeUrl,
- PageUrls.HomeUrl,
- PageUrls.PrivacyUrl,
- PageUrls.RegisterUrl,
- PageUrls.LoginUrl,
- PageUrls.PrivacyUrl
- }
- },
- new Page
- {
- Url = PageUrls.LoginUrl,
- Links = new string[] {
- PageUrls.HomeUrl,
- PageUrls.HomeUrl,
- PageUrls.PrivacyUrl,
- PageUrls.RegisterUrl,
- PageUrls.LoginUrl,
- PageUrls.ForgotPassword,
- PageUrls.RegisterUrl,
- PageUrls.ResendEmailConfirmation,
- PageUrls.ExternalArticle,
- PageUrls.PrivacyUrl }
- },
- new Page
- {
- Url = PageUrls.RegisterUrl,
- Links = new string [] {
- PageUrls.HomeUrl,
- PageUrls.HomeUrl,
- PageUrls.PrivacyUrl,
- PageUrls.RegisterUrl,
- PageUrls.LoginUrl,
- PageUrls.ExternalArticle,
- PageUrls.PrivacyUrl
+ new Page
+ {
+ Url = PageUrls.ForgotPassword,
+ Links = new string [] {
+ PageUrls.HomeUrl,
+ PageUrls.HomeUrl,
+ PageUrls.PrivacyUrl,
+ PageUrls.RegisterUrl,
+ PageUrls.LoginUrl,
+ PageUrls.PrivacyUrl
+ }
+ },
+ new Page
+ {
+ Url = PageUrls.HomeUrl,
+ Links = new string[] {
+ PageUrls.HomeUrl,
+ PageUrls.HomeUrl,
+ PageUrls.PrivacyUrl,
+ PageUrls.RegisterUrl,
+ PageUrls.LoginUrl,
+ PageUrls.DocsUrl,
+ PageUrls.PrivacyUrl
+ }
+ },
+ new Page
+ {
+ Url = PageUrls.PrivacyFullUrl,
+ Links = new string[] {
+ PageUrls.HomeUrl,
+ PageUrls.HomeUrl,
+ PageUrls.PrivacyUrl,
+ PageUrls.RegisterUrl,
+ PageUrls.LoginUrl,
+ PageUrls.PrivacyUrl
+ }
+ },
+ new Page
+ {
+ Url = PageUrls.LoginUrl,
+ Links = new string[] {
+ PageUrls.HomeUrl,
+ PageUrls.HomeUrl,
+ PageUrls.PrivacyUrl,
+ PageUrls.RegisterUrl,
+ PageUrls.LoginUrl,
+ PageUrls.ForgotPassword,
+ PageUrls.RegisterUrl,
+ PageUrls.ResendEmailConfirmation,
+ PageUrls.ExternalArticle,
+ PageUrls.PrivacyUrl }
+ },
+ new Page
+ {
+ Url = PageUrls.RegisterUrl,
+ Links = new string [] {
+ PageUrls.HomeUrl,
+ PageUrls.HomeUrl,
+ PageUrls.PrivacyUrl,
+ PageUrls.RegisterUrl,
+ PageUrls.LoginUrl,
+ PageUrls.ExternalArticle,
+ PageUrls.PrivacyUrl
+ }
}
- }
- };
+ };
using (var aspNetProcess = project.StartBuiltProjectAsync())
{
@@ -234,67 +241,44 @@ public async Task MvcTemplate_IndividualAuth(bool useLocalDB)
}
}
- [ConditionalFact(Skip = "https://github.com/dotnet/aspnetcore/issues/25103")]
- [SkipOnHelix("cert failure", Queues = "All.OSX")]
+ [ConditionalFact]
+ [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] // Running these requires the rid-specific runtime pack to be available which is not consistent in all our platform builds.
+ [SkipOnHelix("cert failure", Queues = "All.OSX;" + HelixConstants.Windows10Arm64)]
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.
- string runtimeIdentifer;
- if (OperatingSystem.IsWindows())
- {
- runtimeIdentifer = "win-x64";
- }
- else if (OperatingSystem.IsLinux())
- {
- runtimeIdentifer = "linux-x64";
- }
- else
- {
- return;
- }
-
+ var runtimeIdentifer = "win-x64";
var project = await ProjectFactory.GetOrCreateProject("mvcsinglefileexe", Output);
project.RuntimeIdentifier = runtimeIdentifer;
- var createResult = await project.RunDotNetNewAsync("mvc", auth: "Individual", useLocalDB: true);
+ 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);
Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", project, publishResult));
- var pages = new[]
+ var menuLinks = new[]
+ {
+ PageUrls.HomeUrl,
+ PageUrls.HomeUrl,
+ PageUrls.PrivacyFullUrl
+ };
+
+ var footerLinks = new[] { PageUrls.PrivacyFullUrl };
+
+ var pages = new List
{
new Page
{
- // Verify a view from the app works
Url = PageUrls.HomeUrl,
- Links = new []
- {
- PageUrls.HomeUrl,
- PageUrls.RegisterUrl,
- PageUrls.LoginUrl,
- PageUrls.HomeUrl,
- PageUrls.PrivacyUrl,
- PageUrls.DocsUrl,
- PageUrls.PrivacyUrl
- }
+ Links = menuLinks.Append(PageUrls.DocsUrl).Concat(footerLinks),
},
new Page
{
- // Verify a view from a RCL (in this case IdentityUI) works
- Url = PageUrls.RegisterUrl,
- Links = new []
- {
- PageUrls.HomeUrl,
- PageUrls.RegisterUrl,
- PageUrls.LoginUrl,
- PageUrls.HomeUrl,
- PageUrls.PrivacyUrl,
- PageUrls.ExternalArticle,
- PageUrls.PrivacyUrl
- }
- },
+ Url = PageUrls.PrivacyFullUrl,
+ Links = menuLinks.Concat(footerLinks),
+ }
};
using var aspNetProcess = project.StartPublishedProjectAsync(usePublishedAppHost: true);
diff --git a/src/ProjectTemplates/test/RazorPagesTemplateTest.cs b/src/ProjectTemplates/test/RazorPagesTemplateTest.cs
index 1af0a68366ff..3412233f5dd5 100644
--- a/src/ProjectTemplates/test/RazorPagesTemplateTest.cs
+++ b/src/ProjectTemplates/test/RazorPagesTemplateTest.cs
@@ -34,13 +34,16 @@ public ITestOutputHelper Output
}
}
- [ConditionalFact]
+ [ConditionalTheory]
[SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
- public async Task RazorPagesTemplate_NoAuth()
+ [InlineData(true)]
+ [InlineData(false)]
+ public async Task RazorPagesTemplate_NoAuth(bool useProgramMain)
{
var project = await ProjectFactory.GetOrCreateProject("razorpagesnoauth", Output);
- var createResult = await project.RunDotNetNewAsync("razor");
+ var args = useProgramMain ? new [] { "--use-program-main" } : null;
+ var createResult = await project.RunDotNetNewAsync("razor", args: args);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("razor", project, createResult));
var projectFileContents = ReadFile(project.TemplateOutputDir, $"{project.ProjectName}.csproj");
@@ -104,14 +107,17 @@ public async Task RazorPagesTemplate_NoAuth()
}
[ConditionalTheory]
- [InlineData(false)]
- [InlineData(true)]
+ [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)
+ public async Task RazorPagesTemplate_IndividualAuth(bool useLocalDB, bool useProgramMain)
{
var project = await ProjectFactory.GetOrCreateProject("razorpagesindividual" + (useLocalDB ? "uld" : ""), Output);
- var createResult = await project.RunDotNetNewAsync("razor", auth: "Individual", useLocalDB: useLocalDB);
+ var args = useProgramMain ? new [] { "--use-program-main" } : null;
+ var createResult = await project.RunDotNetNewAsync("razor", auth: "Individual", useLocalDB: useLocalDB, args: args);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
var projectFileContents = ReadFile(project.TemplateOutputDir, $"{project.ProjectName}.csproj");
@@ -226,12 +232,15 @@ public async Task RazorPagesTemplate_IndividualAuth(bool useLocalDB)
[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("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);
[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);
private async Task BuildAndPublishRazorPagesTemplate(string auth, string[] args)
diff --git a/src/ProjectTemplates/test/WebApiTemplateTest.cs b/src/ProjectTemplates/test/WebApiTemplateTest.cs
index ddc6e185320e..f727abcc92c0 100644
--- a/src/ProjectTemplates/test/WebApiTemplateTest.cs
+++ b/src/ProjectTemplates/test/WebApiTemplateTest.cs
@@ -35,10 +35,15 @@ 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("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);
[Fact]
@@ -50,11 +55,18 @@ public ITestOutputHelper Output
[ConditionalFact]
[SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
- public async Task WebApiTemplateCSharp_WithoutOpenAPI()
+ public Task WebApiTemplateProgramMainCSharp() => WebApiTemplateCore(languageOverride: null, args: new [] { "--use-program-main" });
+
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ [SkipOnHelix("Cert failure, https://github.com/dotnet/aspnetcore/issues/28090", Queues = "All.OSX;" + HelixConstants.Windows10Arm64 + HelixConstants.DebianArm64)]
+ public async Task WebApiTemplateCSharp_WithoutOpenAPI(bool useProgramMain)
{
var project = await FactoryFixture.GetOrCreateProject("webapinoopenapi", Output);
- var createResult = await project.RunDotNetNewAsync("webapi", args: new[] { "--no-openapi" });
+ var args = useProgramMain ? new[] { "--use-program-main --no-openapi" } : new[] { "--no-openapi" };
+ var createResult = await project.RunDotNetNewAsync("webapi", args: args);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
var buildResult = await project.RunDotNetBuildAsync();
@@ -68,7 +80,7 @@ public async Task WebApiTemplateCSharp_WithoutOpenAPI()
await aspNetProcess.AssertNotFound("swagger");
}
- private async Task PublishAndBuildWebApiTemplate(string languageOverride, string auth, string[] args)
+ private async Task PublishAndBuildWebApiTemplate(string languageOverride, string auth, string[] args = null)
{
var project = await FactoryFixture.GetOrCreateProject("webapi" + (languageOverride == "F#" ? "fsharp" : "csharp") + Guid.NewGuid().ToString().Substring(0, 10).ToLowerInvariant(), Output);
@@ -94,9 +106,9 @@ private async Task PublishAndBuildWebApiTemplate(string languageOverrid
return project;
}
- private async Task WebApiTemplateCore(string languageOverride)
+ private async Task WebApiTemplateCore(string languageOverride, string[] args = null)
{
- var project = await PublishAndBuildWebApiTemplate(languageOverride, null, null);
+ var project = await PublishAndBuildWebApiTemplate(languageOverride, null, args);
// Avoid the F# compiler. See https://github.com/dotnet/aspnetcore/issues/14022
if (languageOverride != null)
diff --git a/src/ProjectTemplates/test/WorkerTemplateTest.cs b/src/ProjectTemplates/test/WorkerTemplateTest.cs
index 80e67c18738e..ba82b5073c0e 100644
--- a/src/ProjectTemplates/test/WorkerTemplateTest.cs
+++ b/src/ProjectTemplates/test/WorkerTemplateTest.cs
@@ -32,16 +32,17 @@ public ITestOutputHelper Output
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux, SkipReason = "https://github.com/dotnet/sdk/issues/12831")]
- [InlineData("C#")]
- [InlineData("F#")]
+ [InlineData("C#", null)]
+ [InlineData("C#", new string[] { "--use-program-main" })]
+ [InlineData("F#", null)]
[QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/25404")]
- public async Task WorkerTemplateAsync(string language)
+ public async Task WorkerTemplateAsync(string language, string[] args)
{
var project = await ProjectFactory.GetOrCreateProject(
$"worker-{ language.ToLowerInvariant()[0] }sharp",
Output);
- var createResult = await project.RunDotNetNewAsync("worker", language: language);
+ var createResult = await project.RunDotNetNewAsync("worker", language: language, args: args);
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
var publishResult = await project.RunDotNetPublishAsync();
diff --git a/src/submodules/spa-templates b/src/submodules/spa-templates
index 3d16ec44cf4b..08a4e743ccec 160000
--- a/src/submodules/spa-templates
+++ b/src/submodules/spa-templates
@@ -1 +1 @@
-Subproject commit 3d16ec44cf4bc171531cefb0a81ae72b8bf0c478
+Subproject commit 08a4e743ccec97c24aec8b7a719655f08e827d8e
From 1e1c891386335c31f25f54b378976407749af928 Mon Sep 17 00:00:00 2001
From: "Chris Ross (ASP.NET)"
Date: Wed, 6 Apr 2022 21:55:49 +0000
Subject: [PATCH 15/21] Merged PR 21247: Fix partial chunked cookies 70242
# Fix partial chunked cookies
MSRC # 70242: Fix exceptions and allocations when the cookie chunk count is not accurate
## Description
Browsers have limits on how long cookies can be, as low as 4kb. It's common for TempData and CookieAuth to get above that limit, so cookies are split into chunks with the following format:
MyCookie=chunks-3
MyCookieC1=(Base64EncodedData)
MyCookieC2=(Base64EncodedData)
MyCookieC3=(Base64EncodedData)
Fixes MSRC # 70242
## Customer Impact
A malicious client could send `MyCookie=chunks-2147483647` without the actual cookie chunks and cause large allocations, exceptions, and excess CPU utilization on the server when it tried to read or delete that many chunks.
This flaw comes from the original implementation in Microsoft.Owin, but is much worse in AspNetCore when adopted by TempData due to it automatically calling Delete if reading the cookie fails.
I'll backport this to 5.0, 3.1, 2.1, and Microsoft.Owin once reviewed.
## Regression?
- [ ] Yes
- [x] No
## Risk
- [ ] High
- [ ] Medium
- [x] Low
Easy to reproduce and test.
## Verification
- [x] Manual (required)
- [x] Automated
## Packaging changes reviewed?
- [ ] Yes
- [ ] No
- [x] N/A
---
.../CookiePolicy/test/CookieChunkingTests.cs | 35 ++++++++++++++++++-
.../ChunkingCookieManager.cs | 17 ++++++---
2 files changed, 47 insertions(+), 5 deletions(-)
diff --git a/src/Security/CookiePolicy/test/CookieChunkingTests.cs b/src/Security/CookiePolicy/test/CookieChunkingTests.cs
index 735d7e23d554..5c958fe0abcd 100644
--- a/src/Security/CookiePolicy/test/CookieChunkingTests.cs
+++ b/src/Security/CookiePolicy/test/CookieChunkingTests.cs
@@ -129,7 +129,7 @@ public void GetLargeChunkedCookieWithMissingChunk_ThrowingDisabled_NotReassemble
public void DeleteChunkedCookieWithOptions_AllDeleted()
{
HttpContext context = new DefaultHttpContext();
- context.Request.Headers.Append("Cookie", "TestCookie=chunks-7");
+ context.Request.Headers.Append("Cookie", "TestCookie=chunks-7;TestCookieC1=1;TestCookieC2=2;TestCookieC3=3;TestCookieC4=4;TestCookieC5=5;TestCookieC6=6;TestCookieC7=7");
new ChunkingCookieManager().DeleteCookie(context, "TestCookie", new CookieOptions() { Domain = "foo.com", Secure = true });
var cookies = context.Response.Headers["Set-Cookie"];
@@ -147,7 +147,40 @@ public void DeleteChunkedCookieWithOptions_AllDeleted()
}, cookies);
}
+ [Fact]
+ public void DeleteChunkedCookieWithMissingRequestCookies_OnlyPresentCookiesDeleted()
+ {
+ HttpContext context = new DefaultHttpContext();
+ context.Request.Headers.Append("Cookie", "TestCookie=chunks-7;TestCookieC1=1;TestCookieC2=2");
+
+ new ChunkingCookieManager().DeleteCookie(context, "TestCookie", new CookieOptions() { Domain = "foo.com", Secure = true });
+ var cookies = context.Response.Headers["Set-Cookie"];
+ Assert.Equal(3, cookies.Count);
+ Assert.Equal(new[]
+ {
+ "TestCookie=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/; secure",
+ "TestCookieC1=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/; secure",
+ "TestCookieC2=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/; secure",
+ }, cookies);
+ }
+ [Fact]
+ public void DeleteChunkedCookieWithMissingRequestCookies_StopsAtMissingChunk()
+ {
+ HttpContext context = new DefaultHttpContext();
+ // C3 is missing so we don't try to delete C4 either.
+ context.Request.Headers.Append("Cookie", "TestCookie=chunks-7;TestCookieC1=1;TestCookieC2=2;TestCookieC4=4");
+
+ new ChunkingCookieManager().DeleteCookie(context, "TestCookie", new CookieOptions() { Domain = "foo.com", Secure = true });
+ var cookies = context.Response.Headers["Set-Cookie"];
+ Assert.Equal(3, cookies.Count);
+ Assert.Equal(new[]
+ {
+ "TestCookie=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/; secure",
+ "TestCookieC1=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/; secure",
+ "TestCookieC2=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/; secure",
+ }, cookies);
+ }
[Fact]
public void DeleteChunkedCookieWithOptionsAndResponseCookies_AllDeleted()
diff --git a/src/Shared/ChunkingCookieManager/ChunkingCookieManager.cs b/src/Shared/ChunkingCookieManager/ChunkingCookieManager.cs
index 30ec3c66ed63..9a66071ee5d4 100644
--- a/src/Shared/ChunkingCookieManager/ChunkingCookieManager.cs
+++ b/src/Shared/ChunkingCookieManager/ChunkingCookieManager.cs
@@ -103,7 +103,7 @@ private static int ParseChunksCount(string? value)
var chunksCount = ParseChunksCount(value);
if (chunksCount > 0)
{
- var chunks = new string[chunksCount];
+ var chunks = new List(10); // chunksCount may be wrong, don't trust it.
for (var chunkId = 1; chunkId <= chunksCount; chunkId++)
{
var chunk = requestCookies[key + ChunkKeySuffix + chunkId.ToString(CultureInfo.InvariantCulture)];
@@ -128,7 +128,7 @@ private static int ParseChunksCount(string? value)
return value;
}
- chunks[chunkId - 1] = chunk;
+ chunks.Add(chunk);
}
return string.Join(string.Empty, chunks);
@@ -254,13 +254,22 @@ public void DeleteCookie(HttpContext context, string key, CookieOptions options)
key + "="
};
- var requestCookie = context.Request.Cookies[key];
- var chunks = ParseChunksCount(requestCookie);
+ var requestCookies = context.Request.Cookies;
+ var requestCookie = requestCookies[key];
+ long chunks = ParseChunksCount(requestCookie);
if (chunks > 0)
{
for (var i = 1; i <= chunks + 1; i++)
{
var subkey = key + ChunkKeySuffix + i.ToString(CultureInfo.InvariantCulture);
+
+ // Only delete cookies we received. We received the chunk count cookie so we should have received the others too.
+ if (string.IsNullOrEmpty(requestCookies[subkey]))
+ {
+ chunks = i - 1;
+ break;
+ }
+
keys.Add(subkey + "=");
}
}
From 108c22182e1ada7052e969add7d2d128f786c37b Mon Sep 17 00:00:00 2001
From: Will Godbe
Date: Fri, 8 Apr 2022 01:40:24 +0000
Subject: [PATCH 16/21] Merged PR 21240: [6.0] MSRC 70023 - ASP.Net
FormFeature.cs - DenialOfService
# ASP.Net FormFeature.cs - DenialOfService
When parsing multi-part form data with FormFeature.cs, we do not honor ValueCountLimit when the content disposition is of an unknown type. Therefore an attacker could send multi-part form data where very part has invalid content disposition, and make us read indefinitely.
## Description
When parsing multi-part form data with FormFeature.cs, we do not honor ValueCountLimit when the content disposition is of an unknown type. Therefore an attacker could send multi-part form data where very part has invalid content disposition, and make us read indefinitely.
## Customer Impact
Prevents a potential Denial-of-service attack.
## Regression?
- [ ] Yes
- [x] No
## Risk
- [ ] High
- [x] Medium
- [ ] Low
We could have missed another potential version of this vulnerability
## Verification
- [x] Manual (required)
- [x] Automated
Added a test, plus confirmed with a local repro that the pre-existing slowdown goes away after the change.
## Packaging changes reviewed?
- [ ] Yes
- [ ] No
- [x] N/A
----
## When servicing release/2.1
- [ ] Make necessary changes in eng/PatchConfig.props
---
src/Http/Http/src/Features/FormFeature.cs | 7 ++++-
.../Http/test/Features/FormFeatureTests.cs | 30 +++++++++++++++++++
2 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/src/Http/Http/src/Features/FormFeature.cs b/src/Http/Http/src/Features/FormFeature.cs
index e758b1b0354c..173904e8c194 100644
--- a/src/Http/Http/src/Features/FormFeature.cs
+++ b/src/Http/Http/src/Features/FormFeature.cs
@@ -184,6 +184,7 @@ private async Task InnerReadFormAsync(CancellationToken cancell
else if (HasMultipartFormContentType(contentType))
{
var formAccumulator = new KeyValueAccumulator();
+ var nonFormOrFileContentDispositionCount = 0;
var boundary = GetBoundary(contentType, _options.MultipartBoundaryLengthLimit);
var multipartReader = new MultipartReader(boundary, _request.Body)
@@ -259,7 +260,11 @@ private async Task InnerReadFormAsync(CancellationToken cancell
}
else
{
- System.Diagnostics.Debug.Assert(false, "Unrecognized content-disposition for this section: " + section.ContentDisposition);
+ if (nonFormOrFileContentDispositionCount++ >= _options.ValueCountLimit)
+ {
+ throw new InvalidDataException($"Unrecognized Content-Disposition. Form value count limit {_options.ValueCountLimit} exceeded.");
+
+ }
}
section = await multipartReader.ReadNextSectionAsync(cancellationToken);
diff --git a/src/Http/Http/test/Features/FormFeatureTests.cs b/src/Http/Http/test/Features/FormFeatureTests.cs
index 9426ce6dd1b2..67873e223c4d 100644
--- a/src/Http/Http/test/Features/FormFeatureTests.cs
+++ b/src/Http/Http/test/Features/FormFeatureTests.cs
@@ -165,6 +165,12 @@ private class MockRequestBodyPipeFeature : IRequestBodyPipeFeature
InvalidContentDispositionValue +
"\r\n" +
"\r\n" +
+"Foo\r\n";
+
+ private const string MultipartFormFileNonFormOrFileContentDispositionValue = "--WebKitFormBoundary5pDRpGheQXaM8k3T\r\n" +
+"Content-Disposition:x" +
+"\r\n" +
+"\r\n" +
"Foo\r\n";
private const string MultipartFormWithField =
@@ -468,6 +474,30 @@ public async Task ReadFormAsync_ValueCountLimitExceeded_Throw(bool bufferRequest
Assert.Equal("Form value count limit 2 exceeded.", exception.Message);
}
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public async Task ReadFormAsync_NonFormOrFieldContentDisposition_ValueCountLimitExceeded_Throw(bool bufferRequest)
+ {
+ var formContent = new List();
+ formContent.AddRange(Encoding.UTF8.GetBytes(MultipartFormFileNonFormOrFileContentDispositionValue));
+ formContent.AddRange(Encoding.UTF8.GetBytes(MultipartFormFileNonFormOrFileContentDispositionValue));
+ formContent.AddRange(Encoding.UTF8.GetBytes(MultipartFormFileNonFormOrFileContentDispositionValue));
+ formContent.AddRange(Encoding.UTF8.GetBytes(MultipartFormEnd));
+
+ var context = new DefaultHttpContext();
+ var responseFeature = new FakeResponseFeature();
+ context.Features.Set(responseFeature);
+ context.Request.ContentType = MultipartContentType;
+ context.Request.Body = new NonSeekableReadStream(formContent.ToArray());
+
+ IFormFeature formFeature = new FormFeature(context.Request, new FormOptions() { BufferBody = bufferRequest, ValueCountLimit = 2 });
+ context.Features.Set(formFeature);
+
+ var exception = await Assert.ThrowsAsync(() => context.Request.ReadFormAsync());
+ Assert.Equal("Unrecognized Content-Disposition. Form value count limit 2 exceeded.", exception.Message);
+ }
+
[Theory]
[InlineData(true)]
[InlineData(false)]
From e71384f9b8d0f950d88adbdcc49d85f54b949107 Mon Sep 17 00:00:00 2001
From: "dotnet-maestro[bot]"
<42748379+dotnet-maestro[bot]@users.noreply.github.com>
Date: Mon, 11 Apr 2022 09:53:04 -0700
Subject: [PATCH 17/21] Update dependencies from
https://github.com/dotnet/arcade build 20220406.7 (#41090)
Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Helix.Sdk
From Version 6.0.0-beta.22178.5 -> To Version 6.0.0-beta.22206.7
Co-authored-by: dotnet-maestro[bot]
---
eng/Version.Details.xml | 16 ++++++++--------
eng/Versions.props | 4 ++--
global.json | 4 ++--
3 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 1be6aca6040b..4e4a2e201fa0 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -280,22 +280,22 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
c24d9a9c91c5d04b7b4de71f1a9f33ac35e09663
-
+
https://github.com/dotnet/arcade
- f8c0d51185208227e582f76ac3c5003db237b689
+ 254113fd7c3ee04f832c165d6aec1a6077de0d63
-
+
https://github.com/dotnet/arcade
- f8c0d51185208227e582f76ac3c5003db237b689
+ 254113fd7c3ee04f832c165d6aec1a6077de0d63
-
+
https://github.com/dotnet/arcade
- f8c0d51185208227e582f76ac3c5003db237b689
+ 254113fd7c3ee04f832c165d6aec1a6077de0d63
-
+
https://github.com/dotnet/arcade
- f8c0d51185208227e582f76ac3c5003db237b689
+ 254113fd7c3ee04f832c165d6aec1a6077de0d63
diff --git a/eng/Versions.props b/eng/Versions.props
index c88cf62def19..5fc7bdc4148a 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -131,8 +131,8 @@
6.0.3
6.0.3
- 6.0.0-beta.22178.5
- 6.0.0-beta.22178.5
+ 6.0.0-beta.22206.7
+ 6.0.0-beta.22206.7
- 6.0.0-beta.22206.7
- 6.0.0-beta.22206.7
+ 6.0.0-beta.22212.5
+ 6.0.0-beta.22212.5
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
-
-
-
+
+
+
@@ -34,120 +34,120 @@
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
-
-
+
+
- 6.0.3
+ 6.0.4
-
-
+
+
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
-
+
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
@@ -155,114 +155,114 @@
- 6.0.3
+ 6.0.4
-
+
-
+
-
+
- 6.0.3
+ 6.0.4
-
+
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
-
+
- 6.0.3
+ 6.0.4
-
-
+
+
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
-
-
+
+
- 6.0.3
+ 6.0.4
-
+
- 6.0.3
+ 6.0.4
-
-
-
+
+
+
- 6.0.3
+ 6.0.4
-
-
+
+
- 6.0.3
+ 6.0.4
-
-
+
+
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
-
-
+
+
@@ -270,7 +270,7 @@
- 6.0.3
+ 6.0.4
@@ -278,50 +278,50 @@
- 6.0.3
+ 6.0.4
-
+
-
+
-
+
-
+
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
-
+
-
+
-
+
- 6.0.3
+ 6.0.4
-
-
+
+
@@ -331,8 +331,8 @@
-
-
+
+
@@ -340,8 +340,8 @@
-
-
+
+
@@ -352,58 +352,58 @@
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
-
-
+
+
- 6.0.3
+ 6.0.4
-
+
-
+
-
+
- 6.0.3
+ 6.0.4
-
+
-
+
-
+
- 6.0.3
+ 6.0.4
-
+
- 6.0.3
+ 6.0.4
@@ -411,71 +411,71 @@
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
-
+
-
+
-
+
-
+
- 6.0.3
+ 6.0.4
-
-
+
+
-
+
-
-
+
+
- 6.0.3
+ 6.0.4
-
-
+
+
- 6.0.3
+ 6.0.4
-
-
+
+
- 6.0.3
+ 6.0.4
@@ -491,195 +491,195 @@
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
-
+
- 6.0.3
+ 6.0.4
-
-
+
+
- 6.0.3
+ 6.0.4
-
-
+
+
- 6.0.3
+ 6.0.4
-
+
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
-
+
- 6.0.3
+ 6.0.4
-
-
+
+
-
-
+
+
-
-
+
+
- 6.0.3
+ 6.0.4
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
- 6.0.3
+ 6.0.4
-
+
-
+
-
+
-
+
-
+
- 6.0.3
+ 6.0.4
-
+
-
+
-
+
- 6.0.3
+ 6.0.4
-
+
-
+
-
+
- 6.0.3
+ 6.0.4
-
+
-
+
-
+
- 6.0.3
+ 6.0.4
-
-
-
-
+
+
+
+
- 6.0.3
+ 6.0.4
@@ -688,69 +688,69 @@
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
-
+
- 6.0.3
+ 6.0.4
-
+
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
@@ -769,7 +769,7 @@
- 6.0.3
+ 6.0.4
@@ -788,7 +788,7 @@
- 6.0.3
+ 6.0.4
@@ -804,46 +804,46 @@
- 6.0.3
+ 6.0.4
-
+
-
+
-
+
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
-
-
-
+
+
+
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
@@ -853,7 +853,7 @@
- 6.0.3
+ 6.0.4
@@ -862,73 +862,73 @@
- 6.0.3
+ 6.0.4
-
+
-
+
-
+
- 6.0.3
+ 6.0.4
-
+
-
+
-
+
- 6.0.3
+ 6.0.4
-
+
-
+
-
+
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
@@ -957,11 +957,11 @@
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
@@ -979,13 +979,13 @@
- 6.0.3
+ 6.0.4
- 6.0.3
+ 6.0.4
-
+
\ No newline at end of file
diff --git a/eng/Baseline.xml b/eng/Baseline.xml
index 903713249197..e20bb4bb51a8 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/Versions.props b/eng/Versions.props
index ffd24731dff1..b8bce19da302 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -9,7 +9,7 @@
6
0
5
- false
+ true
@@ -212,10 +212,10 @@
2.1.1
2.2.0
- 3.1.23-servicing-22123-12
+ 3.1.24-servicing-22180-6
$(MicrosoftAspNetCoreAzureAppServicesSiteExtension31Version)
$(MicrosoftAspNetCoreAzureAppServicesSiteExtension31Version)
- 5.0.15-servicing-22116-16
+ 5.0.16-servicing-22167-6
$(MicrosoftAspNetCoreAzureAppServicesSiteExtension50Version)
$(MicrosoftAspNetCoreAzureAppServicesSiteExtension50Version)
diff --git a/eng/helix/helix.proj b/eng/helix/helix.proj
index f1f7e4a3d42e..b9b16f9f858f 100644
--- a/eng/helix/helix.proj
+++ b/eng/helix/helix.proj
@@ -10,7 +10,7 @@
not HelixCorrelationPayload.
-->
- false
+ true
diff --git a/global.json b/global.json
index 9dd54a00ab2a..30a17d2cce7a 100644
--- a/global.json
+++ b/global.json
@@ -13,7 +13,7 @@
"$(MicrosoftNETCoreBrowserDebugHostTransportVersion)"
],
"aspnetcore/x64": [
- "3.1.23"
+ "3.1.24"
]
},
"Git": "2.22.0",
From dd34abdadac5668452e0496cfadb6cf985ec3d3f Mon Sep 17 00:00:00 2001
From: DotNet Bot
Date: Fri, 15 Apr 2022 00:21:07 +0000
Subject: [PATCH 20/21] [internal/release/6.0] Update dependencies from
dnceng/internal/dotnet-efcore dnceng/internal/dotnet-runtime
- Updated helix.proj to IsPublicRuntime=false
---
NuGet.config | 20 +++----------
eng/Version.Details.xml | 64 ++++++++++++++++++++---------------------
eng/Versions.props | 26 ++++++++---------
eng/helix/helix.proj | 2 +-
4 files changed, 50 insertions(+), 62 deletions(-)
diff --git a/NuGet.config b/NuGet.config
index 74d2f8b546d3..f2c2ca6dd386 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -4,16 +4,10 @@
-
-
-
-
+
-
-
-
-
+
@@ -33,16 +27,10 @@
-
-
-
-
+
-
-
-
-
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index c43656f4f296..83ba53dc8a68 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -9,37 +9,37 @@
-->
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- aca50aef8604cc23910d18edce820e0fa7c61910
+ 4fb38f68c827f1264dd4bad0799ce4db26cca470
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- aca50aef8604cc23910d18edce820e0fa7c61910
+ 4fb38f68c827f1264dd4bad0799ce4db26cca470
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- aca50aef8604cc23910d18edce820e0fa7c61910
+ 4fb38f68c827f1264dd4bad0799ce4db26cca470
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- aca50aef8604cc23910d18edce820e0fa7c61910
+ 4fb38f68c827f1264dd4bad0799ce4db26cca470
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- aca50aef8604cc23910d18edce820e0fa7c61910
+ 4fb38f68c827f1264dd4bad0799ce4db26cca470
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- aca50aef8604cc23910d18edce820e0fa7c61910
+ 4fb38f68c827f1264dd4bad0799ce4db26cca470
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- aca50aef8604cc23910d18edce820e0fa7c61910
+ 4fb38f68c827f1264dd4bad0799ce4db26cca470
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- aca50aef8604cc23910d18edce820e0fa7c61910
+ 4fb38f68c827f1264dd4bad0799ce4db26cca470
https://github.com/dotnet/runtime
@@ -177,9 +177,9 @@
https://github.com/dotnet/runtime
4822e3c3aa77eb82b2fb33c9321f923cf11ddde6
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- d66e32ff6f54236c5bea85ca4e0d99f0fc7293e7
+ 70ae3df4a6f3c92fb6b315afc405edd10ff38579
https://github.com/dotnet/runtime
@@ -193,9 +193,9 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
839cdfb0ecca5e0be3dbccd926e7651ef50fdf10
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 839cdfb0ecca5e0be3dbccd926e7651ef50fdf10
+ 70ae3df4a6f3c92fb6b315afc405edd10ff38579
https://github.com/dotnet/runtime
@@ -217,9 +217,9 @@
https://github.com/dotnet/runtime
4822e3c3aa77eb82b2fb33c9321f923cf11ddde6
-
- https://github.com/dotnet/runtime
- 4822e3c3aa77eb82b2fb33c9321f923cf11ddde6
+
+ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
+ 70ae3df4a6f3c92fb6b315afc405edd10ff38579
https://github.com/dotnet/runtime
@@ -233,9 +233,9 @@
https://github.com/dotnet/runtime
4822e3c3aa77eb82b2fb33c9321f923cf11ddde6
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- be98e88c760526452df94ef452fff4602fb5bded
+ 70ae3df4a6f3c92fb6b315afc405edd10ff38579
https://github.com/dotnet/runtime
@@ -247,15 +247,15 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- d66e32ff6f54236c5bea85ca4e0d99f0fc7293e7
+ 70ae3df4a6f3c92fb6b315afc405edd10ff38579
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- d66e32ff6f54236c5bea85ca4e0d99f0fc7293e7
+ 70ae3df4a6f3c92fb6b315afc405edd10ff38579
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- d66e32ff6f54236c5bea85ca4e0d99f0fc7293e7
+ 70ae3df4a6f3c92fb6b315afc405edd10ff38579
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- d66e32ff6f54236c5bea85ca4e0d99f0fc7293e7
+ 70ae3df4a6f3c92fb6b315afc405edd10ff38579
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- d66e32ff6f54236c5bea85ca4e0d99f0fc7293e7
+ 70ae3df4a6f3c92fb6b315afc405edd10ff38579
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- d66e32ff6f54236c5bea85ca4e0d99f0fc7293e7
+ 70ae3df4a6f3c92fb6b315afc405edd10ff38579
diff --git a/eng/Versions.props b/eng/Versions.props
index e0556d31d601..2ba62764d9b6 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -68,7 +68,7 @@
6.0.5
6.0.5
6.0.5
- 6.0.5-servicing.22205.9
+ 6.0.5-servicing.22213.9
6.0.0
6.0.1
6.0.0
@@ -103,33 +103,33 @@
6.0.0
6.0.0
6.0.0
- 6.0.5-servicing.22205.9
+ 6.0.5-servicing.22213.9
6.0.0
6.0.0
6.0.1
- 6.0.2
+ 6.0.3
6.0.0
6.0.1
6.0.1
6.0.0
6.0.0
- 6.0.0
+ 6.0.1
6.0.0
6.0.0
6.0.0
- 6.0.3
+ 6.0.4
6.0.0
6.0.3
- 6.0.4
- 6.0.4
- 6.0.4
- 6.0.4
- 6.0.4
- 6.0.4
- 6.0.4
- 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.0-beta.22212.5
6.0.0-beta.22212.5
diff --git a/eng/helix/helix.proj b/eng/helix/helix.proj
index b9b16f9f858f..f1f7e4a3d42e 100644
--- a/eng/helix/helix.proj
+++ b/eng/helix/helix.proj
@@ -10,7 +10,7 @@
not HelixCorrelationPayload.
-->
- true
+ false
From e5f183b656a0e8bc087108130a5a9b54ae94494e Mon Sep 17 00:00:00 2001
From: DotNet Bot
Date: Mon, 18 Apr 2022 11:47:19 +0000
Subject: [PATCH 21/21] [internal/release/6.0] Update dependencies from
dnceng/internal/dotnet-efcore
---
NuGet.config | 4 ++--
eng/Version.Details.xml | 16 ++++++++--------
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/NuGet.config b/NuGet.config
index f2c2ca6dd386..06e49041de2f 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -7,7 +7,7 @@
-
+
@@ -27,7 +27,7 @@
-
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 83ba53dc8a68..67ad201ccdf6 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -11,35 +11,35 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 4fb38f68c827f1264dd4bad0799ce4db26cca470
+ 9b03633bb18b617088b32260065ee385bf9c4491
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 4fb38f68c827f1264dd4bad0799ce4db26cca470
+ 9b03633bb18b617088b32260065ee385bf9c4491
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 4fb38f68c827f1264dd4bad0799ce4db26cca470
+ 9b03633bb18b617088b32260065ee385bf9c4491
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 4fb38f68c827f1264dd4bad0799ce4db26cca470
+ 9b03633bb18b617088b32260065ee385bf9c4491
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 4fb38f68c827f1264dd4bad0799ce4db26cca470
+ 9b03633bb18b617088b32260065ee385bf9c4491
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 4fb38f68c827f1264dd4bad0799ce4db26cca470
+ 9b03633bb18b617088b32260065ee385bf9c4491
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 4fb38f68c827f1264dd4bad0799ce4db26cca470
+ 9b03633bb18b617088b32260065ee385bf9c4491
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 4fb38f68c827f1264dd4bad0799ce4db26cca470
+ 9b03633bb18b617088b32260065ee385bf9c4491
https://github.com/dotnet/runtime