diff --git a/.azure/pipelines/jobs/default-build.yml b/.azure/pipelines/jobs/default-build.yml
index f3eb0197a617..2908d5bb869a 100644
--- a/.azure/pipelines/jobs/default-build.yml
+++ b/.azure/pipelines/jobs/default-build.yml
@@ -94,7 +94,7 @@ jobs:
# See https://github.com/dotnet/arcade/blob/master/Documentation/ChoosingAMachinePool.md
pool:
${{ if eq(parameters.agentOs, 'macOS') }}:
- vmImage: macOS-10.15
+ vmImage: macOS-11
${{ if eq(parameters.agentOs, 'Linux') }}:
${{ if and(eq(parameters.useHostedUbuntu, true), or(ne(variables['System.TeamProject'], 'internal'), in(variables['Build.Reason'], 'Manual', 'PullRequest', 'Schedule'))) }}:
vmImage: ubuntu-18.04
@@ -151,8 +151,8 @@ jobs:
- script: df -h
displayName: Disk size
- ${{ if eq(parameters.agentOs, 'macOS') }}:
- - script: sudo xcode-select -s /Applications/Xcode_12.2.app/Contents/Developer
- displayName: Use XCode 12.2
+ - script: sudo xcode-select -s /Applications/Xcode_12.5.1.app/Contents/Developer
+ displayName: Use XCode 12.5.1
- checkout: self
clean: true
- ${{ if and(eq(parameters.agentOs, 'Windows'), eq(parameters.isTestingJob, true)) }}:
diff --git a/NuGet.config b/NuGet.config
index 0057e5ff395f..63330d10bbf3 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -4,10 +4,10 @@
-
+
-
+
@@ -27,10 +27,10 @@
-
+
-
+
diff --git a/eng/Baseline.Designer.props b/eng/Baseline.Designer.props
index dc5385edc181..28042e9d0222 100644
--- a/eng/Baseline.Designer.props
+++ b/eng/Baseline.Designer.props
@@ -2,28 +2,28 @@
$(MSBuildAllProjects);$(MSBuildThisFileFullPath)
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
-
-
-
+
+
+
@@ -34,120 +34,120 @@
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
-
-
+
+
- 6.0.7
+ 6.0.8
-
-
+
+
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
-
+
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
@@ -155,114 +155,114 @@
- 6.0.7
+ 6.0.8
-
+
-
+
-
+
- 6.0.7
+ 6.0.8
-
+
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
-
+
- 6.0.7
+ 6.0.8
-
-
+
+
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
-
-
+
+
- 6.0.7
+ 6.0.8
-
+
- 6.0.7
+ 6.0.8
-
-
-
+
+
+
- 6.0.7
+ 6.0.8
-
-
+
+
- 6.0.7
+ 6.0.8
-
-
+
+
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
-
-
+
+
@@ -270,7 +270,7 @@
- 6.0.7
+ 6.0.8
@@ -278,132 +278,132 @@
- 6.0.7
+ 6.0.8
-
+
-
+
-
+
-
+
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
-
+
-
+
-
+
- 6.0.7
+ 6.0.8
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
-
-
+
+
- 6.0.7
+ 6.0.8
-
+
-
+
-
+
- 6.0.7
+ 6.0.8
-
+
-
+
-
+
- 6.0.7
+ 6.0.8
-
+
- 6.0.7
+ 6.0.8
@@ -411,71 +411,71 @@
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
-
+
-
+
-
+
-
+
- 6.0.7
+ 6.0.8
-
+
-
+
-
+
- 6.0.7
+ 6.0.8
-
-
+
+
- 6.0.7
+ 6.0.8
-
-
+
+
- 6.0.7
+ 6.0.8
@@ -491,195 +491,195 @@
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
-
+
- 6.0.7
+ 6.0.8
-
-
+
+
- 6.0.7
+ 6.0.8
-
-
+
+
- 6.0.7
+ 6.0.8
-
+
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
-
+
- 6.0.7
+ 6.0.8
-
-
+
+
-
-
+
+
-
-
+
+
- 6.0.7
+ 6.0.8
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
- 6.0.7
+ 6.0.8
-
+
-
+
-
+
- 6.0.7
+ 6.0.8
-
+
-
+
-
+
- 6.0.7
+ 6.0.8
-
+
-
+
-
+
- 6.0.7
+ 6.0.8
-
+
-
+
-
+
- 6.0.7
+ 6.0.8
-
-
-
-
+
+
+
+
- 6.0.7
+ 6.0.8
@@ -688,69 +688,69 @@
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
-
+
- 6.0.7
+ 6.0.8
-
+
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
@@ -769,7 +769,7 @@
- 6.0.7
+ 6.0.8
@@ -788,7 +788,7 @@
- 6.0.7
+ 6.0.8
@@ -804,46 +804,46 @@
- 6.0.7
+ 6.0.8
-
+
-
+
-
+
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
-
-
-
+
+
+
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
@@ -853,7 +853,7 @@
- 6.0.7
+ 6.0.8
@@ -862,73 +862,73 @@
- 6.0.7
+ 6.0.8
-
+
-
+
-
+
- 6.0.7
+ 6.0.8
-
+
-
+
-
+
- 6.0.7
+ 6.0.8
-
+
-
+
-
+
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
@@ -957,11 +957,11 @@
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
@@ -979,13 +979,13 @@
- 6.0.7
+ 6.0.8
- 6.0.7
+ 6.0.8
-
+
\ No newline at end of file
diff --git a/eng/Baseline.xml b/eng/Baseline.xml
index 79b54e2ee34d..549d55431ba9 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/Version.Details.xml b/eng/Version.Details.xml
index 2036ca3cb2d8..bf05f45e33d6 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -9,37 +9,37 @@
-->
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 62e1b2f494af376a4588bf3d365f7be5443d4a5d
+ 33e3c950af2eb996c0b3c48e30eb4471138da675
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 62e1b2f494af376a4588bf3d365f7be5443d4a5d
+ 33e3c950af2eb996c0b3c48e30eb4471138da675
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 62e1b2f494af376a4588bf3d365f7be5443d4a5d
+ 33e3c950af2eb996c0b3c48e30eb4471138da675
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 62e1b2f494af376a4588bf3d365f7be5443d4a5d
+ 33e3c950af2eb996c0b3c48e30eb4471138da675
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 62e1b2f494af376a4588bf3d365f7be5443d4a5d
+ 33e3c950af2eb996c0b3c48e30eb4471138da675
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 62e1b2f494af376a4588bf3d365f7be5443d4a5d
+ 33e3c950af2eb996c0b3c48e30eb4471138da675
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 62e1b2f494af376a4588bf3d365f7be5443d4a5d
+ 33e3c950af2eb996c0b3c48e30eb4471138da675
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 62e1b2f494af376a4588bf3d365f7be5443d4a5d
+ 33e3c950af2eb996c0b3c48e30eb4471138da675
https://github.com/dotnet/runtime
@@ -129,9 +129,9 @@
https://github.com/dotnet/runtime
4822e3c3aa77eb82b2fb33c9321f923cf11ddde6
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- c24d9a9c91c5d04b7b4de71f1a9f33ac35e09663
+ 163a63591cf9e9b682063cf3995948c2b885a042
https://github.com/dotnet/runtime
@@ -177,9 +177,9 @@
https://github.com/dotnet/runtime
4822e3c3aa77eb82b2fb33c9321f923cf11ddde6
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 55fb7ef977e7d120dc12f0960edcff0739d7ee0e
+ 163a63591cf9e9b682063cf3995948c2b885a042
https://github.com/dotnet/runtime
@@ -233,9 +233,9 @@
https://github.com/dotnet/runtime
4822e3c3aa77eb82b2fb33c9321f923cf11ddde6
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 7cca709db2944a09b4db6ca7b20c457ff260fb5a
+ 163a63591cf9e9b682063cf3995948c2b885a042
https://github.com/dotnet/runtime
@@ -245,33 +245,33 @@
https://github.com/dotnet/runtime
4822e3c3aa77eb82b2fb33c9321f923cf11ddde6
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 55fb7ef977e7d120dc12f0960edcff0739d7ee0e
+ 163a63591cf9e9b682063cf3995948c2b885a042
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 55fb7ef977e7d120dc12f0960edcff0739d7ee0e
+ 163a63591cf9e9b682063cf3995948c2b885a042
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 55fb7ef977e7d120dc12f0960edcff0739d7ee0e
+ 163a63591cf9e9b682063cf3995948c2b885a042
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 55fb7ef977e7d120dc12f0960edcff0739d7ee0e
+ 163a63591cf9e9b682063cf3995948c2b885a042
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 55fb7ef977e7d120dc12f0960edcff0739d7ee0e
+ 163a63591cf9e9b682063cf3995948c2b885a042
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 55fb7ef977e7d120dc12f0960edcff0739d7ee0e
+ 163a63591cf9e9b682063cf3995948c2b885a042
diff --git a/eng/Versions.props b/eng/Versions.props
index c2703b08cf0b..bc3e57278226 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -8,7 +8,7 @@
6
0
- 8
+ 9
true
6.0.0
- 6.0.8
- 6.0.8
- 6.0.8
- 6.0.8
- 6.0.8
- 6.0.8-servicing.22363.6
+ 6.0.9
+ 6.0.9
+ 6.0.9
+ 6.0.9
+ 6.0.9
+ 6.0.9-servicing.22419.5
6.0.0
6.0.1
6.0.0
@@ -91,7 +91,7 @@
6.0.0
6.0.1
6.0.0
- 6.0.1
+ 6.0.2
6.0.0
6.0.0
6.0.0
@@ -103,7 +103,7 @@
6.0.0
6.0.0
6.0.0
- 6.0.8-servicing.22363.6
+ 6.0.9-servicing.22419.5
6.0.0
6.0.0
6.0.1
@@ -117,19 +117,19 @@
6.0.1
6.0.0
6.0.0
- 6.0.5
+ 6.0.6
6.0.0
6.0.5
- 6.0.8
- 6.0.8
- 6.0.8
- 6.0.8
- 6.0.8
- 6.0.8
- 6.0.8
- 6.0.8
+ 6.0.9
+ 6.0.9
+ 6.0.9
+ 6.0.9
+ 6.0.9
+ 6.0.9
+ 6.0.9
+ 6.0.9
6.0.0-beta.22314.7
6.0.0-beta.22314.7
@@ -214,7 +214,7 @@
2.1.1
2.2.0
- 3.1.27-servicing-22316-11
+ 3.1.28-servicing-22364-2
$(MicrosoftAspNetCoreAzureAppServicesSiteExtension31Version)
$(MicrosoftAspNetCoreAzureAppServicesSiteExtension31Version)
5.0.17-servicing-22215-7
diff --git a/eng/test-configuration.json b/eng/test-configuration.json
index 6f8c5e36aaf1..02a918bc9f4d 100644
--- a/eng/test-configuration.json
+++ b/eng/test-configuration.json
@@ -1,6 +1,6 @@
{
"version" : 1,
- "defaultOnFailure": "fail",
+ "defaultOnFailure": "retry",
"localRerunCount" : 3,
"retryOnRules": [
{"testName": {"contains": "AppOfflineDroppedWhileSiteStarting_SiteShutsDown_InProcess"}},
@@ -15,4 +15,4 @@
],
"quarantineRules": [
]
-}
\ No newline at end of file
+}
diff --git a/global.json b/global.json
index bbd837de7707..fe757ec1255f 100644
--- a/global.json
+++ b/global.json
@@ -1,9 +1,9 @@
{
"sdk": {
- "version": "6.0.107"
+ "version": "6.0.108"
},
"tools": {
- "dotnet": "6.0.107",
+ "dotnet": "6.0.108",
"runtimes": {
"dotnet/x64": [
"2.1.30",
@@ -13,7 +13,7 @@
"$(MicrosoftNETCoreBrowserDebugHostTransportVersion)"
],
"aspnetcore/x64": [
- "3.1.27"
+ "3.1.28"
]
},
"Git": "2.22.0",
diff --git a/src/DefaultBuilder/src/WebApplication.cs b/src/DefaultBuilder/src/WebApplication.cs
index 9d0a837c8300..2c1fb9d17925 100644
--- a/src/DefaultBuilder/src/WebApplication.cs
+++ b/src/DefaultBuilder/src/WebApplication.cs
@@ -27,7 +27,7 @@ public sealed class WebApplication : IHost, IApplicationBuilder, IEndpointRouteB
internal WebApplication(IHost host)
{
_host = host;
- ApplicationBuilder = new ApplicationBuilder(host.Services);
+ ApplicationBuilder = new ApplicationBuilder(host.Services, ServerFeatures);
Logger = host.Services.GetRequiredService().CreateLogger(Environment.ApplicationName);
Properties[GlobalEndpointRouteBuilderKey] = this;
diff --git a/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebApplicationTests.cs b/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebApplicationTests.cs
index d487d2594939..7be67edb239f 100644
--- a/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebApplicationTests.cs
+++ b/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebApplicationTests.cs
@@ -31,6 +31,16 @@ namespace Microsoft.AspNetCore.Tests
{
public class WebApplicationTests
{
+ [Fact]
+ public async Task WebApplicationBuilder_New()
+ {
+ var builder = WebApplication.CreateBuilder(new string[] { "--urls", "http://localhost:5001" });
+
+ await using var app = builder.Build();
+ var newApp = (app as IApplicationBuilder).New();
+ Assert.NotNull(newApp.ServerFeatures);
+ }
+
[Fact]
public async Task WebApplicationBuilderConfiguration_IncludesCommandLineArguments()
{
@@ -1696,13 +1706,13 @@ public void EmptyAppConfiguration()
createdDirectory = true;
Directory.CreateDirectory(wwwroot);
}
-
+
try
{
var builder = WebApplication.CreateBuilder();
-
+
builder.WebHost.ConfigureAppConfiguration((ctx, config) => { });
-
+
using var app = builder.Build();
var hostEnv = app.Services.GetRequiredService();
Assert.Equal(wwwroot, hostEnv.WebRootPath);
diff --git a/src/HttpClientFactory/Polly/src/PolicyHttpMessageHandler.cs b/src/HttpClientFactory/Polly/src/PolicyHttpMessageHandler.cs
index c32c52fc2f1d..71bfe54ce0f7 100644
--- a/src/HttpClientFactory/Polly/src/PolicyHttpMessageHandler.cs
+++ b/src/HttpClientFactory/Polly/src/PolicyHttpMessageHandler.cs
@@ -167,7 +167,7 @@ protected virtual async Task SendCoreAsync(HttpRequestMessa
disposable.Dispose();
}
- var result = await base.SendAsync(request, cancellationToken);
+ var result = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
request.Properties[PriorResponseKey] = result;
diff --git a/src/Installers/Windows/SharedFrameworkBundle/Bundle.wxs b/src/Installers/Windows/SharedFrameworkBundle/Bundle.wxs
index 453548c27511..ca33112a07ce 100644
--- a/src/Installers/Windows/SharedFrameworkBundle/Bundle.wxs
+++ b/src/Installers/Windows/SharedFrameworkBundle/Bundle.wxs
@@ -4,6 +4,7 @@
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelStateDictionary.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelStateDictionary.cs
index e72d6443c4e1..1ff9b7dd9b3c 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelStateDictionary.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelStateDictionary.cs
@@ -25,6 +25,9 @@ public class ModelStateDictionary : IReadOnlyDictionary
public static readonly int DefaultMaxAllowedErrors = 200;
+ // internal for testing
+ internal const int DefaultMaxRecursionDepth = 32;
+
private const char DelimiterDot = '.';
private const char DelimiterOpen = '[';
@@ -43,8 +46,18 @@ public ModelStateDictionary()
/// Initializes a new instance of the class.
///
public ModelStateDictionary(int maxAllowedErrors)
+ : this(maxAllowedErrors, maxValidationDepth: DefaultMaxRecursionDepth, maxStateDepth: DefaultMaxRecursionDepth)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ private ModelStateDictionary(int maxAllowedErrors, int maxValidationDepth, int maxStateDepth)
{
MaxAllowedErrors = maxAllowedErrors;
+ MaxValidationDepth = maxValidationDepth;
+ MaxStateDepth = maxStateDepth;
var emptySegment = new StringSegment(buffer: string.Empty);
_root = new ModelStateNode(subKey: emptySegment)
{
@@ -58,7 +71,9 @@ public ModelStateDictionary(int maxAllowedErrors)
///
/// The to copy values from.
public ModelStateDictionary(ModelStateDictionary dictionary)
- : this(dictionary?.MaxAllowedErrors ?? DefaultMaxAllowedErrors)
+ : this(dictionary?.MaxAllowedErrors ?? DefaultMaxAllowedErrors,
+ dictionary?.MaxValidationDepth ?? DefaultMaxRecursionDepth,
+ dictionary?.MaxStateDepth ?? DefaultMaxRecursionDepth)
{
if (dictionary == null)
{
@@ -154,7 +169,7 @@ public bool IsValid
}
///
- public ModelValidationState ValidationState => GetValidity(_root) ?? ModelValidationState.Valid;
+ public ModelValidationState ValidationState => GetValidity(_root, currentDepth: 0) ?? ModelValidationState.Valid;
///
public ModelStateEntry? this[string key]
@@ -174,6 +189,10 @@ public ModelStateEntry? this[string key]
// Flag that indicates if TooManyModelErrorException has already been added to this dictionary.
private bool HasRecordedMaxModelError { get; set; }
+ internal int? MaxValidationDepth { get; set; }
+
+ internal int? MaxStateDepth { get; set; }
+
///
/// Adds the specified to the instance
/// that is associated with the specified . If the maximum number of allowed
@@ -217,7 +236,6 @@ public bool TryAddModelException(string key, Exception exception)
return false;
}
- ErrorCount++;
AddModelErrorCore(key, exception);
return true;
}
@@ -327,7 +345,6 @@ public bool TryAddModelError(string key, Exception exception, ModelMetadata meta
return TryAddModelError(key, exception.Message);
}
- ErrorCount++;
AddModelErrorCore(key, exception);
return true;
}
@@ -385,13 +402,13 @@ public bool TryAddModelError(string key, string errorMessage)
return false;
}
- ErrorCount++;
var modelState = GetOrAddNode(key);
Count += !modelState.IsContainerNode ? 0 : 1;
modelState.ValidationState = ModelValidationState.Invalid;
modelState.MarkNonContainerNode();
modelState.Errors.Add(errorMessage);
+ ErrorCount++;
return true;
}
@@ -411,7 +428,7 @@ public ModelValidationState GetFieldValidationState(string key)
}
var item = GetNode(key);
- return GetValidity(item) ?? ModelValidationState.Unvalidated;
+ return GetValidity(item, currentDepth: 0) ?? ModelValidationState.Unvalidated;
}
///
@@ -611,11 +628,18 @@ private ModelStateNode GetOrAddNode(string key)
var current = _root;
if (key.Length > 0)
{
+ var currentDepth = 0;
var match = default(MatchResult);
do
{
+ if (MaxStateDepth != null && currentDepth >= MaxStateDepth)
+ {
+ throw new InvalidOperationException(Resources.FormatModelStateDictionary_MaxModelStateDepth(MaxStateDepth));
+ }
+
var subKey = FindNext(key, ref match);
current = current.GetOrAddNode(subKey);
+ currentDepth++;
} while (match.Type != Delimiter.None);
@@ -661,9 +685,10 @@ private static StringSegment FindNext(string key, ref MatchResult currentMatch)
return new StringSegment(key, keyStart, index - keyStart);
}
- private static ModelValidationState? GetValidity(ModelStateNode? node)
+ private ModelValidationState? GetValidity(ModelStateNode? node, int currentDepth)
{
- if (node == null)
+ if (node == null ||
+ (MaxValidationDepth != null && currentDepth >= MaxValidationDepth))
{
return null;
}
@@ -686,9 +711,11 @@ private static StringSegment FindNext(string key, ref MatchResult currentMatch)
if (node.ChildNodes != null)
{
+ currentDepth++;
+
for (var i = 0; i < node.ChildNodes.Count; i++)
{
- var entryState = GetValidity(node.ChildNodes[i]);
+ var entryState = GetValidity(node.ChildNodes[i], currentDepth);
if (entryState == ModelValidationState.Unvalidated)
{
@@ -712,7 +739,6 @@ private void EnsureMaxErrorsReachedRecorded()
var exception = new TooManyModelErrorsException(Resources.ModelStateDictionary_MaxModelStateErrors);
AddModelErrorCore(string.Empty, exception);
HasRecordedMaxModelError = true;
- ErrorCount++;
}
}
@@ -723,6 +749,8 @@ private void AddModelErrorCore(string key, Exception exception)
modelState.ValidationState = ModelValidationState.Invalid;
modelState.MarkNonContainerNode();
modelState.Errors.Add(exception);
+
+ ErrorCount++;
}
///
diff --git a/src/Mvc/Mvc.Abstractions/src/Resources.resx b/src/Mvc/Mvc.Abstractions/src/Resources.resx
index c4159218e799..5d38b2bdae14 100644
--- a/src/Mvc/Mvc.Abstractions/src/Resources.resx
+++ b/src/Mvc/Mvc.Abstractions/src/Resources.resx
@@ -180,4 +180,7 @@
Record type '{0}' has validation metadata defined on property '{1}' that will be ignored. '{1}' is a parameter in the record primary constructor and validation metadata must be associated with the constructor parameter.
-
+
+ The specified key exceeded the maximum ModelState depth: {0}
+
+
\ No newline at end of file
diff --git a/src/Mvc/Mvc.Abstractions/test/ModelBinding/ModelStateDictionaryTest.cs b/src/Mvc/Mvc.Abstractions/test/ModelBinding/ModelStateDictionaryTest.cs
index 229457d71006..750ada389f97 100644
--- a/src/Mvc/Mvc.Abstractions/test/ModelBinding/ModelStateDictionaryTest.cs
+++ b/src/Mvc/Mvc.Abstractions/test/ModelBinding/ModelStateDictionaryTest.cs
@@ -1601,6 +1601,163 @@ public void GetModelStateForProperty_ReturnsModelStateForIndexedChildren()
Assert.Equal("value1", property.RawValue);
}
+
+ [Fact]
+ public void GetFieldValidationState_ReturnsUnvalidated_IfTreeHeightIsGreaterThanLimit()
+ {
+ // Arrange
+ var stackLimit = 5;
+ var dictionary = new ModelStateDictionary();
+ var key = string.Join(".", Enumerable.Repeat("foo", stackLimit + 1));
+ dictionary.MaxValidationDepth = stackLimit;
+ dictionary.MaxStateDepth = null;
+ dictionary.MarkFieldValid(key);
+
+ // Act
+ var validationState = dictionary.GetFieldValidationState("foo");
+
+ // Assert
+ Assert.Equal(ModelValidationState.Unvalidated, validationState);
+ }
+
+ [Fact]
+ public void IsValidProperty_ReturnsTrue_IfTreeHeightIsGreaterThanLimit()
+ {
+ // Arrange
+ var stackLimit = 5;
+ var dictionary = new ModelStateDictionary();
+ var key = string.Join(".", Enumerable.Repeat("foo", stackLimit + 1));
+ dictionary.MaxValidationDepth = stackLimit;
+ dictionary.MaxStateDepth = null;
+ dictionary.AddModelError(key, "some error");
+
+ // Act
+ var isValid = dictionary.IsValid;
+ var validationState = dictionary.ValidationState;
+
+ // Assert
+ Assert.True(isValid);
+ Assert.Equal(ModelValidationState.Valid, validationState);
+ }
+
+ [Fact]
+ public void TryAddModelException_Throws_IfKeyHasTooManySegments()
+ {
+ // Arrange
+ var exception = new TestException();
+
+ var stateDepth = 5;
+ var dictionary = new ModelStateDictionary();
+ var key = string.Join(".", Enumerable.Repeat("foo", stateDepth + 1));
+ dictionary.MaxStateDepth = stateDepth;
+
+ // Act
+ var invalidException = Assert.Throws(() => dictionary.TryAddModelException(key, exception));
+
+ // Assert
+ Assert.Equal(
+ $"The specified key exceeded the maximum ModelState depth: {dictionary.MaxStateDepth}",
+ invalidException.Message);
+ }
+
+ [Fact]
+ public void TryAddModelError_Throws_IfKeyHasTooManySegments()
+ {
+ // Arrange
+ var stateDepth = 5;
+ var dictionary = new ModelStateDictionary();
+ var key = string.Join(".", Enumerable.Repeat("foo", stateDepth + 1));
+ dictionary.MaxStateDepth = stateDepth;
+
+ // Act
+ var invalidException = Assert.Throws(() => dictionary.TryAddModelError(key, "errorMessage"));
+
+ // Assert
+ Assert.Equal(
+ $"The specified key exceeded the maximum ModelState depth: {dictionary.MaxStateDepth}",
+ invalidException.Message);
+ }
+
+ [Fact]
+ public void SetModelValue_Throws_IfKeyHasTooManySegments()
+ {
+ var stateDepth = 5;
+ var dictionary = new ModelStateDictionary();
+ var key = string.Join(".", Enumerable.Repeat("foo", stateDepth + 1));
+ dictionary.MaxStateDepth = stateDepth;
+
+ // Act
+ var invalidException = Assert.Throws(() => dictionary.SetModelValue(key, string.Empty, string.Empty));
+
+ // Assert
+ Assert.Equal(
+ $"The specified key exceeded the maximum ModelState depth: {dictionary.MaxStateDepth}",
+ invalidException.Message);
+ }
+
+ [Fact]
+ public void MarkFieldValid_Throws_IfKeyHasTooManySegments()
+ {
+ // Arrange
+ var stateDepth = 5;
+ var source = new ModelStateDictionary();
+ var key = string.Join(".", Enumerable.Repeat("foo", stateDepth + 1));
+ source.MaxStateDepth = stateDepth;
+
+ // Act
+ var exception = Assert.Throws(() => source.MarkFieldValid(key));
+
+ // Assert
+ Assert.Equal(
+ $"The specified key exceeded the maximum ModelState depth: {source.MaxStateDepth}",
+ exception.Message);
+ }
+
+ [Fact]
+ public void MarkFieldSkipped_Throws_IfKeyHasTooManySegments()
+ {
+ // Arrange
+ var stateDepth = 5;
+ var source = new ModelStateDictionary();
+ var key = string.Join(".", Enumerable.Repeat("foo", stateDepth + 1));
+ source.MaxStateDepth = stateDepth;
+
+ // Act
+ var exception = Assert.Throws(() => source.MarkFieldSkipped(key));
+
+ // Assert
+ Assert.Equal(
+ $"The specified key exceeded the maximum ModelState depth: {source.MaxStateDepth}",
+ exception.Message);
+ }
+
+ [Fact]
+ public void Constructor_SetsDefaultRecursionDepth()
+ {
+ // Arrange && Act
+ var dictionary = new ModelStateDictionary();
+
+ // Assert
+ Assert.Equal(ModelStateDictionary.DefaultMaxRecursionDepth, dictionary.MaxValidationDepth);
+ Assert.Equal(ModelStateDictionary.DefaultMaxRecursionDepth, dictionary.MaxStateDepth);
+ }
+
+ [Fact]
+ public void CopyConstructor_PreservesRecursionDepth()
+ {
+ // Arrange
+ var dictionary = new ModelStateDictionary();
+ dictionary.MaxValidationDepth = 5;
+ dictionary.MaxStateDepth = 4;
+
+ // Act
+ var newDictionary = new ModelStateDictionary(dictionary);
+
+ // Assert
+ Assert.Equal(dictionary.MaxValidationDepth, newDictionary.MaxValidationDepth);
+ Assert.Equal(dictionary.MaxStateDepth, newDictionary.MaxStateDepth);
+ }
+
private class OptionsAccessor : IOptions
{
public MvcOptions Value { get; } = new MvcOptions();
diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/ControllerActionInvokerProvider.cs b/src/Mvc/Mvc.Core/src/Infrastructure/ControllerActionInvokerProvider.cs
index dd576bf2c8ad..c1a8f07877f8 100644
--- a/src/Mvc/Mvc.Core/src/Infrastructure/ControllerActionInvokerProvider.cs
+++ b/src/Mvc/Mvc.Core/src/Infrastructure/ControllerActionInvokerProvider.cs
@@ -20,6 +20,8 @@ internal class ControllerActionInvokerProvider : IActionInvokerProvider
private readonly ControllerActionInvokerCache _controllerActionInvokerCache;
private readonly IReadOnlyList _valueProviderFactories;
private readonly int _maxModelValidationErrors;
+ private readonly int? _maxValidationDepth;
+ private readonly int _maxModelBindingRecursionDepth;
private readonly ILogger _logger;
private readonly DiagnosticListener _diagnosticListener;
private readonly IActionResultTypeMapper _mapper;
@@ -46,6 +48,8 @@ public ControllerActionInvokerProvider(
_controllerActionInvokerCache = controllerActionInvokerCache;
_valueProviderFactories = optionsAccessor.Value.ValueProviderFactories.ToArray();
_maxModelValidationErrors = optionsAccessor.Value.MaxModelValidationErrors;
+ _maxValidationDepth = optionsAccessor.Value.MaxValidationDepth;
+ _maxModelBindingRecursionDepth = optionsAccessor.Value.MaxModelBindingRecursionDepth;
_logger = loggerFactory.CreateLogger();
_diagnosticListener = diagnosticListener;
_mapper = mapper;
@@ -70,6 +74,8 @@ public void OnProvidersExecuting(ActionInvokerProviderContext context)
ValueProviderFactories = new CopyOnWriteList(_valueProviderFactories)
};
controllerContext.ModelState.MaxAllowedErrors = _maxModelValidationErrors;
+ controllerContext.ModelState.MaxValidationDepth = _maxValidationDepth;
+ controllerContext.ModelState.MaxStateDepth = _maxModelBindingRecursionDepth;
var (cacheEntry, filters) = _controllerActionInvokerCache.GetCachedResult(controllerContext);
diff --git a/src/Mvc/Mvc.Core/src/Routing/ControllerRequestDelegateFactory.cs b/src/Mvc/Mvc.Core/src/Routing/ControllerRequestDelegateFactory.cs
index 74d84f8541e4..d62237dbfb92 100644
--- a/src/Mvc/Mvc.Core/src/Routing/ControllerRequestDelegateFactory.cs
+++ b/src/Mvc/Mvc.Core/src/Routing/ControllerRequestDelegateFactory.cs
@@ -21,6 +21,8 @@ internal class ControllerRequestDelegateFactory : IRequestDelegateFactory
private readonly ControllerActionInvokerCache _controllerActionInvokerCache;
private readonly IReadOnlyList _valueProviderFactories;
private readonly int _maxModelValidationErrors;
+ private readonly int? _maxValidationDepth;
+ private readonly int _maxModelBindingRecursionDepth;
private readonly ILogger _logger;
private readonly DiagnosticListener _diagnosticListener;
private readonly IActionResultTypeMapper _mapper;
@@ -48,6 +50,8 @@ public ControllerRequestDelegateFactory(
_controllerActionInvokerCache = controllerActionInvokerCache;
_valueProviderFactories = optionsAccessor.Value.ValueProviderFactories.ToArray();
_maxModelValidationErrors = optionsAccessor.Value.MaxModelValidationErrors;
+ _maxValidationDepth = optionsAccessor.Value.MaxValidationDepth;
+ _maxModelBindingRecursionDepth = optionsAccessor.Value.MaxModelBindingRecursionDepth;
_enableActionInvokers = optionsAccessor.Value.EnableActionInvokers;
_logger = loggerFactory.CreateLogger();
_diagnosticListener = diagnosticListener;
@@ -86,6 +90,8 @@ public ControllerRequestDelegateFactory(
};
controllerContext.ModelState.MaxAllowedErrors = _maxModelValidationErrors;
+ controllerContext.ModelState.MaxValidationDepth = _maxValidationDepth;
+ controllerContext.ModelState.MaxStateDepth = _maxModelBindingRecursionDepth;
var (cacheEntry, filters) = _controllerActionInvokerCache.GetCachedResult(controllerContext);
diff --git a/src/Mvc/Mvc.Core/test/Infrastructure/ControllerActionInvokerProviderTest.cs b/src/Mvc/Mvc.Core/test/Infrastructure/ControllerActionInvokerProviderTest.cs
new file mode 100644
index 000000000000..c278f8ba7f24
--- /dev/null
+++ b/src/Mvc/Mvc.Core/test/Infrastructure/ControllerActionInvokerProviderTest.cs
@@ -0,0 +1,97 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics;
+using System.Reflection;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.Abstractions;
+using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
+using Microsoft.AspNetCore.Routing;
+using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Extensions.Options;
+using Moq;
+
+namespace Microsoft.AspNetCore.Mvc.Infrastructure
+{
+ public class ControllerActionInvokerProviderTest
+ {
+ [Fact]
+ public void OnExecuting_ConfiguresModelState_WithMvcOptions()
+ {
+ // Arrange
+ var provider = CreateInvokerProvider(new MvcOptions() { MaxValidationDepth = 1, MaxModelBindingRecursionDepth = 2, MaxModelValidationErrors = 3 });
+
+ var context = new ActionInvokerProviderContext(new ActionContext()
+ {
+ ActionDescriptor = GetControllerActionDescriptor(),
+ HttpContext = new DefaultHttpContext(),
+ RouteData = new RouteData(),
+ });
+
+ // Act
+ provider.OnProvidersExecuting(context);
+
+ // Assert
+ var invoker = Assert.IsType(context.Result);
+ Assert.Equal(1, invoker.ControllerContext.ModelState.MaxValidationDepth);
+ Assert.Equal(2, invoker.ControllerContext.ModelState.MaxStateDepth);
+ Assert.Equal(3, invoker.ControllerContext.ModelState.MaxAllowedErrors);
+
+ }
+
+ private static ControllerActionDescriptor GetControllerActionDescriptor()
+ {
+ var method = typeof(TestActions).GetMethod(nameof(TestActions.GetAction));
+ var actionDescriptor = new ControllerActionDescriptor
+ {
+ MethodInfo = method,
+ FilterDescriptors = new List(),
+ ControllerTypeInfo = typeof(TestActions).GetTypeInfo(),
+ };
+
+ foreach (var filterAttribute in method.GetCustomAttributes().OfType())
+ {
+ actionDescriptor.FilterDescriptors.Add(new FilterDescriptor(filterAttribute, FilterScope.Action));
+ }
+
+ return actionDescriptor;
+ }
+
+ private static ControllerActionInvokerProvider CreateInvokerProvider(MvcOptions mvcOptions = null)
+ {
+ var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
+ var modelBinderFactory = TestModelBinderFactory.CreateDefault();
+ mvcOptions ??= new MvcOptions();
+
+ var parameterBinder = new ParameterBinder(
+ modelMetadataProvider,
+ TestModelBinderFactory.CreateDefault(),
+ Mock.Of(),
+ Options.Create(mvcOptions),
+ NullLoggerFactory.Instance);
+
+ var cache = new ControllerActionInvokerCache(
+ parameterBinder,
+ modelBinderFactory,
+ modelMetadataProvider,
+ new[] { new DefaultFilterProvider() },
+ Mock.Of(),
+ Options.Create(mvcOptions));
+
+ return new(
+ cache,
+ Options.Create(mvcOptions),
+ NullLoggerFactory.Instance,
+ new DiagnosticListener("Microsoft.AspNetCore"),
+ new ActionResultTypeMapper());
+ }
+
+ private class TestActions : Controller
+ {
+ public IActionResult GetAction() => new OkResult();
+ }
+ }
+}
diff --git a/src/Shared/CertificateGeneration/MacOSCertificateManager.cs b/src/Shared/CertificateGeneration/MacOSCertificateManager.cs
index c58eff3e0382..a63aeb50ed82 100644
--- a/src/Shared/CertificateGeneration/MacOSCertificateManager.cs
+++ b/src/Shared/CertificateGeneration/MacOSCertificateManager.cs
@@ -19,17 +19,17 @@ internal class MacOSCertificateManager : CertificateManager
private static readonly string MacOSUserKeyChain = Environment.GetEnvironmentVariable("HOME") + "/Library/Keychains/login.keychain-db";
private const string MacOSSystemKeyChain = "/Library/Keychains/System.keychain";
private const string MacOSFindCertificateCommandLine = "security";
- private const string MacOSFindCertificateCommandLineArgumentsFormat = "find-certificate -c {0} -a -Z -p " + MacOSSystemKeyChain;
+ private const string MacOSFindCertificateCommandLineArgumentsFormat = "find-certificate -c {0} -a -Z -p \"" + MacOSSystemKeyChain + "\"";
private const string MacOSFindCertificateOutputRegex = "SHA-1 hash: ([0-9A-Z]+)";
private const string MacOSRemoveCertificateTrustCommandLine = "sudo";
- private const string MacOSRemoveCertificateTrustCommandLineArgumentsFormat = "security remove-trusted-cert -d {0}";
+ private const string MacOSRemoveCertificateTrustCommandLineArgumentsFormat = "security remove-trusted-cert -d \"{0}\"";
private const string MacOSDeleteCertificateCommandLine = "sudo";
- private const string MacOSDeleteCertificateCommandLineArgumentsFormat = "security delete-certificate -Z {0} {1}";
+ private const string MacOSDeleteCertificateCommandLineArgumentsFormat = "security delete-certificate -Z {0} \"{1}\"";
private const string MacOSTrustCertificateCommandLine = "sudo";
- private const string MacOSTrustCertificateCommandLineArguments = "security add-trusted-cert -d -r trustRoot -k " + MacOSSystemKeyChain + " ";
+ private const string MacOSTrustCertificateCommandLineArguments = "security add-trusted-cert -d -r trustRoot -k \"" + MacOSSystemKeyChain + "\" ";
private const string MacOSAddCertificateToKeyChainCommandLine = "security";
- private static readonly string MacOSAddCertificateToKeyChainCommandLineArgumentsFormat = "import {0} -k " + MacOSUserKeyChain + " -t cert -f pkcs12 -P {1} -A";
+ private static readonly string MacOSAddCertificateToKeyChainCommandLineArgumentsFormat = "import \"{0}\" -k \"" + MacOSUserKeyChain + "\" -t cert -f pkcs12 -P {1} -A";
public const string InvalidCertificateState = "The ASP.NET Core developer certificate is in an invalid state. " +
"To fix this issue, run the following commands 'dotnet dev-certs https --clean' and 'dotnet dev-certs https' to remove all existing ASP.NET Core development certificates " +
diff --git a/src/submodules/googletest b/src/submodules/googletest
index 96f51426e4c7..dd7a9d29a33d 160000
--- a/src/submodules/googletest
+++ b/src/submodules/googletest
@@ -1 +1 @@
-Subproject commit 96f51426e4c776a71d0a446c1e4f4c7a5ea921df
+Subproject commit dd7a9d29a33de34836c345c3b753d4eba15c5f44
diff --git a/src/submodules/spa-templates b/src/submodules/spa-templates
index 74e05a19dc83..0c5a96babb59 160000
--- a/src/submodules/spa-templates
+++ b/src/submodules/spa-templates
@@ -1 +1 @@
-Subproject commit 74e05a19dc83b736877cb2c5120456948d7799f1
+Subproject commit 0c5a96babb595838516b43680db6f100c8867a7c