diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs
index 95ff1316b4..c9f9d5b058 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs
@@ -427,7 +427,7 @@ namespace Microsoft.AspNetCore.Mvc.Core
}
///
- /// While processing template '{0}', a replacement value for the token '{1}' could not be found. Available tokens: '{2}'.
+ /// While processing template '{0}', a replacement value for the token '{1}' could not be found. Available tokens: '{2}'. To use a '[' or ']' as a literal string in a route or within a constraint, use '[[' or ']]' instead.
///
internal static string AttributeRoute_TokenReplacement_ReplacementValueNotFound
{
@@ -435,7 +435,7 @@ namespace Microsoft.AspNetCore.Mvc.Core
}
///
- /// While processing template '{0}', a replacement value for the token '{1}' could not be found. Available tokens: '{2}'.
+ /// While processing template '{0}', a replacement value for the token '{1}' could not be found. Available tokens: '{2}'. To use a '[' or ']' as a literal string in a route or within a constraint, use '[[' or ']]' instead.
///
internal static string FormatAttributeRoute_TokenReplacement_ReplacementValueNotFound(object p0, object p1, object p2)
{
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx b/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx
index 8a35cabd50..f6236e6e64 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx
@@ -1,17 +1,17 @@
-
@@ -199,7 +199,7 @@
{1} is the specific error message.
- While processing template '{0}', a replacement value for the token '{1}' could not be found. Available tokens: '{2}'.
+ While processing template '{0}', a replacement value for the token '{1}' could not be found. Available tokens: '{2}'. To use a '[' or ']' as a literal string in a route or within a constraint, use '[[' or ']]' instead.
A replacement token is not closed.
diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Properties/Resources.Designer.cs
index a5637e77f7..4241a5c649 100644
--- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Properties/Resources.Designer.cs
+++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Properties/Resources.Designer.cs
@@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
}
///
- /// The @page directive for the Razor page at {0} cannot override the relative path prefix.
+ /// The route for the page at '{0}' cannot start with / or ~/. Pages do not support overriding the file path of the page.
///
internal static string FormatPageActionDescriptorProvider_RouteTemplateCannotBeOverrideable(object p0)
{
@@ -74,22 +74,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
return string.Format(CultureInfo.CurrentCulture, GetString("ActivatedInstance_MustBeAnInstanceOf"), p0, p1);
}
- ///
- /// The Razor page type '{0}' does not have a parameterless constructor.
- ///
- internal static string PageActivator_TypeDoesNotHaveParameterlessConstructor
- {
- get { return GetString("PageActivator_TypeDoesNotHaveParameterlessConstructor"); }
- }
-
- ///
- /// The Razor page type '{0}' does not have a parameterless constructor.
- ///
- internal static string FormatPageActivator_TypeDoesNotHaveParameterlessConstructor(object p0)
- {
- return string.Format(CultureInfo.CurrentCulture, GetString("PageActivator_TypeDoesNotHaveParameterlessConstructor"), p0);
- }
-
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);
diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ApplicationModel/AttributeRouteModelTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ApplicationModel/AttributeRouteModelTests.cs
index ab1a76ee0b..e3a54e159e 100644
--- a/test/Microsoft.AspNetCore.Mvc.Core.Test/ApplicationModel/AttributeRouteModelTests.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ApplicationModel/AttributeRouteModelTests.cs
@@ -174,11 +174,12 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
Assert.Equal(expected, ex.Message);
}
- [Fact]
- public void ReplaceTokens_UnknownValue()
+ [Theory]
+ [InlineData("[area]/[controller]/[action]/{deptName:regex(^[a-zA-Z]{1}[a-zA-Z0-9_]*$)}", "a-zA-Z")]
+ [InlineData("[area]/[controller]/[action2]", "action2")]
+ public void ReplaceTokens_UnknownValue(string template, string token)
{
// Arrange
- var template = "[area]/[controller]/[action2]";
var values = new Dictionary(StringComparer.OrdinalIgnoreCase)
{
{ "area", "Help" },
@@ -187,9 +188,10 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
};
var expected =
- "While processing template '[area]/[controller]/[action2]', " +
- "a replacement value for the token 'action2' could not be found. " +
- "Available tokens: 'action, area, controller'.";
+ $"While processing template '{template}', " +
+ $"a replacement value for the token '{token}' could not be found. " +
+ "Available tokens: 'action, area, controller'. To use a '[' or ']' as a literal string in a " +
+ "route or within a constraint, use '[[' or ']]' instead.";
// Act
var ex = Assert.Throws(
diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ControllerActionDescriptorProviderTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ControllerActionDescriptorProviderTests.cs
index faa86f90b2..5a6302c484 100644
--- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ControllerActionDescriptorProviderTests.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ControllerActionDescriptorProviderTests.cs
@@ -444,7 +444,8 @@ namespace Microsoft.AspNetCore.Mvc.Internal
"Error 1:" + Environment.NewLine +
$"For action: '{controllerTypeInfo.FullName}.Unknown ({assemblyName})'" + Environment.NewLine +
"Error: While processing template 'stub/[action]/[unknown]', a replacement value for the token 'unknown' " +
- "could not be found. Available tokens: 'action, controller'." + Environment.NewLine +
+ "could not be found. Available tokens: 'action, controller'. To use a '[' or ']' as a literal string in" +
+ " a route or within a constraint, use '[[' or ']]' instead." + Environment.NewLine +
Environment.NewLine +
"Error 2:" + Environment.NewLine +
$"For action: '{controllerTypeInfo.FullName}.Invalid ({assemblyName})'" + Environment.NewLine +
@@ -701,7 +702,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
VerifyMultiLineError(expectedMessage, exception.Message, unorderedStart: 1, unorderedLineCount: 2);
}
- // Verify that the expected exception and error message is thrown even when the user builds the model
+ // Verify that the expected exception and error message is thrown even when the user builds the model
// incorrectly.
[Fact]
public void AttributeRouting_ThrowsIfAttributeRoutedAndNonAttributedActions_OnTheSameMethod_UsingCustomConvention()
@@ -906,7 +907,8 @@ namespace Microsoft.AspNetCore.Mvc.Internal
"Error 1:" + Environment.NewLine +
$"For action: '{controllerTypeInfo.FullName}.Get ({assemblyName})'" + Environment.NewLine +
"Error: While processing template 'Products_[unknown]', a replacement value for the token 'unknown' " +
- "could not be found. Available tokens: 'action, controller'.";
+ "could not be found. Available tokens: 'action, controller'. To use a '[' or ']' as a literal string" +
+ " in a route or within a constraint, use '[[' or ']]' instead.";
// Act & Assert
var ex = Assert.Throws(() => { provider.GetDescriptors(); });