Przeglądaj źródła

Add route string syntax attribute (#42179)

James Newton-King 3 lat temu
rodzic
commit
561b0c90ca
24 zmienionych plików z 101 dodań i 75 usunięć
  1. 16 16
      src/Http/Routing/src/Builder/EndpointRouteBuilderExtensions.cs
  2. 2 1
      src/Http/Routing/src/Builder/FallbackEndpointRouteBuilderExtensions.cs
  3. 4 4
      src/Http/Routing/src/MapRouteRouteBuilderExtensions.cs
  4. 2 1
      src/Http/Routing/src/Patterns/RoutePatternException.cs
  5. 5 5
      src/Http/Routing/src/Patterns/RoutePatternFactory.cs
  6. 18 17
      src/Http/Routing/src/RequestDelegateRouteBuilderExtensions.cs
  7. 5 3
      src/Http/Routing/src/Route.cs
  8. 1 1
      src/Http/Routing/src/RouteBase.cs
  9. 3 2
      src/Middleware/StaticFiles/src/StaticFilesEndpointRouteBuilderExtensions.cs
  10. 2 0
      src/Mvc/Mvc.Core/src/AcceptVerbsAttribute.cs
  11. 5 3
      src/Mvc/Mvc.Core/src/ApplicationModels/AttributeRouteModel.cs
  12. 8 7
      src/Mvc/Mvc.Core/src/Builder/ControllerEndpointRouteBuilderExtensions.cs
  13. 5 4
      src/Mvc/Mvc.Core/src/Builder/MvcAreaRouteBuilderExtensions.cs
  14. 2 1
      src/Mvc/Mvc.Core/src/HttpDeleteAttribute.cs
  15. 2 1
      src/Mvc/Mvc.Core/src/HttpGetAttribute.cs
  16. 2 1
      src/Mvc/Mvc.Core/src/HttpHeadAttribute.cs
  17. 2 1
      src/Mvc/Mvc.Core/src/HttpOptionsAttribute.cs
  18. 2 1
      src/Mvc/Mvc.Core/src/HttpPatchAttribute.cs
  19. 2 1
      src/Mvc/Mvc.Core/src/HttpPostAttribute.cs
  20. 2 1
      src/Mvc/Mvc.Core/src/HttpPutAttribute.cs
  21. 3 1
      src/Mvc/Mvc.Core/src/RouteAttribute.cs
  22. 2 1
      src/Mvc/Mvc.Core/src/Routing/HttpMethodAttribute.cs
  23. 3 0
      src/Mvc/Mvc.Core/src/Routing/IRouteTemplateProvider.cs
  24. 3 2
      src/Mvc/Mvc.RazorPages/src/DependencyInjection/PageConventionCollectionExtensions.cs

+ 16 - 16
src/Http/Routing/src/Builder/EndpointRouteBuilderExtensions.cs

@@ -37,7 +37,7 @@ public static class EndpointRouteBuilderExtensions
     /// A <see cref="RouteGroupBuilder"/> that is both an <see cref="IEndpointRouteBuilder"/> and an <see cref="IEndpointConventionBuilder"/>.
     /// The same builder can be used to add endpoints with the given <paramref name="prefix"/>, and to customize those endpoints using conventions.
     /// </returns>
-    public static RouteGroupBuilder MapGroup(this IEndpointRouteBuilder endpoints, string prefix) =>
+    public static RouteGroupBuilder MapGroup(this IEndpointRouteBuilder endpoints, [StringSyntax("Route")] string prefix) =>
         endpoints.MapGroup(RoutePatternFactory.Parse(prefix ?? throw new ArgumentNullException(nameof(prefix))));
 
     /// <summary>
@@ -68,7 +68,7 @@ public static class EndpointRouteBuilderExtensions
     [RequiresUnreferencedCode(EndpointRouteBuilderExtensions.MapEndpointTrimmerWarning)]
     public static IEndpointConventionBuilder MapGet(
         this IEndpointRouteBuilder endpoints,
-        string pattern,
+        [StringSyntax("Route")] string pattern,
         RequestDelegate requestDelegate)
     {
         var returnType = requestDelegate.Method.ReturnType;
@@ -89,7 +89,7 @@ public static class EndpointRouteBuilderExtensions
     /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
     public static IEndpointConventionBuilder MapPost(
         this IEndpointRouteBuilder endpoints,
-        string pattern,
+        [StringSyntax("Route")] string pattern,
         RequestDelegate requestDelegate)
     {
         return MapMethods(endpoints, pattern, PostVerb, requestDelegate);
@@ -105,7 +105,7 @@ public static class EndpointRouteBuilderExtensions
     /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
     public static IEndpointConventionBuilder MapPut(
         this IEndpointRouteBuilder endpoints,
-        string pattern,
+        [StringSyntax("Route")] string pattern,
         RequestDelegate requestDelegate)
     {
         return MapMethods(endpoints, pattern, PutVerb, requestDelegate);
@@ -121,7 +121,7 @@ public static class EndpointRouteBuilderExtensions
     /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
     public static IEndpointConventionBuilder MapDelete(
         this IEndpointRouteBuilder endpoints,
-        string pattern,
+        [StringSyntax("Route")] string pattern,
         RequestDelegate requestDelegate)
     {
         return MapMethods(endpoints, pattern, DeleteVerb, requestDelegate);
@@ -137,7 +137,7 @@ public static class EndpointRouteBuilderExtensions
     /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
     public static IEndpointConventionBuilder MapPatch(
         this IEndpointRouteBuilder endpoints,
-        string pattern,
+        [StringSyntax("Route")] string pattern,
         RequestDelegate requestDelegate)
     {
         return MapMethods(endpoints, pattern, PatchVerb, requestDelegate);
@@ -154,7 +154,7 @@ public static class EndpointRouteBuilderExtensions
     /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
     public static IEndpointConventionBuilder MapMethods(
        this IEndpointRouteBuilder endpoints,
-       string pattern,
+       [StringSyntax("Route")] string pattern,
        IEnumerable<string> httpMethods,
        RequestDelegate requestDelegate)
     {
@@ -176,7 +176,7 @@ public static class EndpointRouteBuilderExtensions
     /// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
     public static IEndpointConventionBuilder Map(
         this IEndpointRouteBuilder endpoints,
-        string pattern,
+        [StringSyntax("Route")] string pattern,
         RequestDelegate requestDelegate)
     {
         return Map(endpoints, RoutePatternFactory.Parse(pattern), requestDelegate);
@@ -242,7 +242,7 @@ public static class EndpointRouteBuilderExtensions
     [RequiresUnreferencedCode(MapEndpointTrimmerWarning)]
     public static RouteHandlerBuilder MapGet(
         this IEndpointRouteBuilder endpoints,
-        string pattern,
+        [StringSyntax("Route")] string pattern,
         Delegate handler)
     {
         return MapMethods(endpoints, pattern, GetVerb, handler);
@@ -259,7 +259,7 @@ public static class EndpointRouteBuilderExtensions
     [RequiresUnreferencedCode(MapEndpointTrimmerWarning)]
     public static RouteHandlerBuilder MapPost(
         this IEndpointRouteBuilder endpoints,
-        string pattern,
+        [StringSyntax("Route")] string pattern,
         Delegate handler)
     {
         return MapMethods(endpoints, pattern, PostVerb, handler);
@@ -276,7 +276,7 @@ public static class EndpointRouteBuilderExtensions
     [RequiresUnreferencedCode(MapEndpointTrimmerWarning)]
     public static RouteHandlerBuilder MapPut(
         this IEndpointRouteBuilder endpoints,
-        string pattern,
+        [StringSyntax("Route")] string pattern,
         Delegate handler)
     {
         return MapMethods(endpoints, pattern, PutVerb, handler);
@@ -293,7 +293,7 @@ public static class EndpointRouteBuilderExtensions
     [RequiresUnreferencedCode(MapEndpointTrimmerWarning)]
     public static RouteHandlerBuilder MapDelete(
         this IEndpointRouteBuilder endpoints,
-        string pattern,
+        [StringSyntax("Route")] string pattern,
         Delegate handler)
     {
         return MapMethods(endpoints, pattern, DeleteVerb, handler);
@@ -310,7 +310,7 @@ public static class EndpointRouteBuilderExtensions
     [RequiresUnreferencedCode(MapEndpointTrimmerWarning)]
     public static RouteHandlerBuilder MapPatch(
         this IEndpointRouteBuilder endpoints,
-        string pattern,
+        [StringSyntax("Route")] string pattern,
         Delegate handler)
     {
         return MapMethods(endpoints, pattern, PatchVerb, handler);
@@ -328,7 +328,7 @@ public static class EndpointRouteBuilderExtensions
     [RequiresUnreferencedCode(MapEndpointTrimmerWarning)]
     public static RouteHandlerBuilder MapMethods(
        this IEndpointRouteBuilder endpoints,
-       string pattern,
+       [StringSyntax("Route")] string pattern,
        IEnumerable<string> httpMethods,
        Delegate handler)
     {
@@ -375,7 +375,7 @@ public static class EndpointRouteBuilderExtensions
     [RequiresUnreferencedCode(MapEndpointTrimmerWarning)]
     public static RouteHandlerBuilder Map(
         this IEndpointRouteBuilder endpoints,
-        string pattern,
+        [StringSyntax("Route")] string pattern,
         Delegate handler)
     {
         return Map(endpoints, RoutePatternFactory.Parse(pattern), handler);
@@ -450,7 +450,7 @@ public static class EndpointRouteBuilderExtensions
     [RequiresUnreferencedCode(MapEndpointTrimmerWarning)]
     public static RouteHandlerBuilder MapFallback(
         this IEndpointRouteBuilder endpoints,
-        string pattern,
+        [StringSyntax("Route")] string pattern,
         Delegate handler)
     {
         ArgumentNullException.ThrowIfNull(endpoints);

+ 2 - 1
src/Http/Routing/src/Builder/FallbackEndpointRouteBuilderExtensions.cs

@@ -1,6 +1,7 @@
 // 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.CodeAnalysis;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Routing;
 
@@ -66,7 +67,7 @@ public static class FallbackEndpointRouteBuilderExtensions
     /// </remarks>
     public static IEndpointConventionBuilder MapFallback(
         this IEndpointRouteBuilder endpoints,
-        string pattern,
+        [StringSyntax("Route")] string pattern,
         RequestDelegate requestDelegate)
     {
         ArgumentNullException.ThrowIfNull(endpoints);

+ 4 - 4
src/Http/Routing/src/MapRouteRouteBuilderExtensions.cs

@@ -26,7 +26,7 @@ public static class MapRouteRouteBuilderExtensions
     public static IRouteBuilder MapRoute(
         this IRouteBuilder routeBuilder,
         string? name,
-        string? template)
+        [StringSyntax("Route")] string? template)
     {
         MapRoute(routeBuilder, name, template, defaults: null);
         return routeBuilder;
@@ -47,7 +47,7 @@ public static class MapRouteRouteBuilderExtensions
     public static IRouteBuilder MapRoute(
         this IRouteBuilder routeBuilder,
         string? name,
-        string? template,
+        [StringSyntax("Route")] string? template,
         object? defaults)
     {
         return MapRoute(routeBuilder, name, template, defaults, constraints: null);
@@ -73,7 +73,7 @@ public static class MapRouteRouteBuilderExtensions
     public static IRouteBuilder MapRoute(
         this IRouteBuilder routeBuilder,
         string? name,
-        string? template,
+        [StringSyntax("Route")] string? template,
         object? defaults,
         object? constraints)
     {
@@ -104,7 +104,7 @@ public static class MapRouteRouteBuilderExtensions
     public static IRouteBuilder MapRoute(
         this IRouteBuilder routeBuilder,
         string? name,
-        string? template,
+        [StringSyntax("Route")] string? template,
         object? defaults,
         object? constraints,
         object? dataTokens)

+ 2 - 1
src/Http/Routing/src/Patterns/RoutePatternException.cs

@@ -1,6 +1,7 @@
 // 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.CodeAnalysis;
 using System.Runtime.Serialization;
 
 namespace Microsoft.AspNetCore.Routing.Patterns;
@@ -22,7 +23,7 @@ public sealed class RoutePatternException : Exception
     /// </summary>
     /// <param name="pattern">The route pattern as raw text.</param>
     /// <param name="message">The exception message.</param>
-    public RoutePatternException(string pattern, string message)
+    public RoutePatternException([StringSyntax("Route")] string pattern, string message)
         : base(message)
     {
         if (pattern == null)

+ 5 - 5
src/Http/Routing/src/Patterns/RoutePatternFactory.cs

@@ -27,7 +27,7 @@ public static class RoutePatternFactory
     /// </summary>
     /// <param name="pattern">The route pattern string to parse.</param>
     /// <returns>The <see cref="RoutePattern"/>.</returns>
-    public static RoutePattern Parse(string pattern)
+    public static RoutePattern Parse([StringSyntax("Route")] string pattern)
     {
         if (pattern == null)
         {
@@ -55,7 +55,7 @@ public static class RoutePatternFactory
     /// </param>
     /// <returns>The <see cref="RoutePattern"/>.</returns>
     [RequiresUnreferencedCode(RouteValueDictionaryTrimmerWarning.Warning)]
-    public static RoutePattern Parse(string pattern, object? defaults, object? parameterPolicies)
+    public static RoutePattern Parse([StringSyntax("Route")] string pattern, object? defaults, object? parameterPolicies)
     {
         if (pattern == null)
         {
@@ -83,7 +83,7 @@ public static class RoutePatternFactory
     /// Multiple policies can be specified for a key by providing a collection as the value.
     /// </param>
     /// <returns>The <see cref="RoutePattern"/>.</returns>
-    public static RoutePattern Parse(string pattern, RouteValueDictionary? defaults, RouteValueDictionary? parameterPolicies)
+    public static RoutePattern Parse([StringSyntax("Route")] string pattern, RouteValueDictionary? defaults, RouteValueDictionary? parameterPolicies)
     {
         if (pattern == null)
         {
@@ -115,7 +115,7 @@ public static class RoutePatternFactory
     /// </param>
     /// <returns>The <see cref="RoutePattern"/>.</returns>
     [RequiresUnreferencedCode(RouteValueDictionaryTrimmerWarning.Warning)]
-    public static RoutePattern Parse(string pattern, object? defaults, object? parameterPolicies, object? requiredValues)
+    public static RoutePattern Parse([StringSyntax("Route")] string pattern, object? defaults, object? parameterPolicies, object? requiredValues)
     {
         if (pattern == null)
         {
@@ -146,7 +146,7 @@ public static class RoutePatternFactory
     /// Route values that can be substituted for parameters in the route pattern. See remarks on <see cref="RoutePattern.RequiredValues"/>.
     /// </param>
     /// <returns>The <see cref="RoutePattern"/>.</returns>
-    public static RoutePattern Parse(string pattern, RouteValueDictionary? defaults, RouteValueDictionary? parameterPolicies, RouteValueDictionary? requiredValues)
+    public static RoutePattern Parse([StringSyntax("Route")] string pattern, RouteValueDictionary? defaults, RouteValueDictionary? parameterPolicies, RouteValueDictionary? requiredValues)
     {
         if (pattern is null)
         {

+ 18 - 17
src/Http/Routing/src/RequestDelegateRouteBuilderExtensions.cs

@@ -1,6 +1,7 @@
 // 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.CodeAnalysis;
 using Microsoft.AspNetCore.Builder;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Routing.Constraints;
@@ -21,7 +22,7 @@ public static class RequestDelegateRouteBuilderExtensions
     /// <param name="template">The route template.</param>
     /// <param name="handler">The <see cref="RequestDelegate"/> route handler.</param>
     /// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
-    public static IRouteBuilder MapRoute(this IRouteBuilder builder, string template, RequestDelegate handler)
+    public static IRouteBuilder MapRoute(this IRouteBuilder builder, [StringSyntax("Route")] string template, RequestDelegate handler)
     {
         var route = new Route(
             new RouteHandler(handler),
@@ -43,7 +44,7 @@ public static class RequestDelegateRouteBuilderExtensions
     /// <param name="template">The route template.</param>
     /// <param name="action">The action to apply to the <see cref="IApplicationBuilder"/>.</param>
     /// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
-    public static IRouteBuilder MapMiddlewareRoute(this IRouteBuilder builder, string template, Action<IApplicationBuilder> action)
+    public static IRouteBuilder MapMiddlewareRoute(this IRouteBuilder builder, [StringSyntax("Route")] string template, Action<IApplicationBuilder> action)
     {
         var nested = builder.ApplicationBuilder.New();
         action(nested);
@@ -58,7 +59,7 @@ public static class RequestDelegateRouteBuilderExtensions
     /// <param name="template">The route template.</param>
     /// <param name="handler">The <see cref="RequestDelegate"/> route handler.</param>
     /// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
-    public static IRouteBuilder MapDelete(this IRouteBuilder builder, string template, RequestDelegate handler)
+    public static IRouteBuilder MapDelete(this IRouteBuilder builder, [StringSyntax("Route")] string template, RequestDelegate handler)
     {
         return builder.MapVerb("DELETE", template, handler);
     }
@@ -71,7 +72,7 @@ public static class RequestDelegateRouteBuilderExtensions
     /// <param name="template">The route template.</param>
     /// <param name="action">The action to apply to the <see cref="IApplicationBuilder"/>.</param>
     /// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
-    public static IRouteBuilder MapMiddlewareDelete(this IRouteBuilder builder, string template, Action<IApplicationBuilder> action)
+    public static IRouteBuilder MapMiddlewareDelete(this IRouteBuilder builder, [StringSyntax("Route")] string template, Action<IApplicationBuilder> action)
     {
         return builder.MapMiddlewareVerb("DELETE", template, action);
     }
@@ -86,7 +87,7 @@ public static class RequestDelegateRouteBuilderExtensions
     /// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
     public static IRouteBuilder MapDelete(
         this IRouteBuilder builder,
-        string template,
+        [StringSyntax("Route")] string template,
         Func<HttpRequest, HttpResponse, RouteData, Task> handler)
     {
         return builder.MapVerb("DELETE", template, handler);
@@ -100,7 +101,7 @@ public static class RequestDelegateRouteBuilderExtensions
     /// <param name="template">The route template.</param>
     /// <param name="handler">The <see cref="RequestDelegate"/> route handler.</param>
     /// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
-    public static IRouteBuilder MapGet(this IRouteBuilder builder, string template, RequestDelegate handler)
+    public static IRouteBuilder MapGet(this IRouteBuilder builder, [StringSyntax("Route")] string template, RequestDelegate handler)
     {
         return builder.MapVerb(HttpMethods.Get, template, handler);
     }
@@ -113,7 +114,7 @@ public static class RequestDelegateRouteBuilderExtensions
     /// <param name="template">The route template.</param>
     /// <param name="action">The action to apply to the <see cref="IApplicationBuilder"/>.</param>
     /// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
-    public static IRouteBuilder MapMiddlewareGet(this IRouteBuilder builder, string template, Action<IApplicationBuilder> action)
+    public static IRouteBuilder MapMiddlewareGet(this IRouteBuilder builder, [StringSyntax("Route")] string template, Action<IApplicationBuilder> action)
     {
         return builder.MapMiddlewareVerb(HttpMethods.Get, template, action);
     }
@@ -128,7 +129,7 @@ public static class RequestDelegateRouteBuilderExtensions
     /// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
     public static IRouteBuilder MapGet(
         this IRouteBuilder builder,
-        string template,
+        [StringSyntax("Route")] string template,
         Func<HttpRequest, HttpResponse, RouteData, Task> handler)
     {
         return builder.MapVerb(HttpMethods.Get, template, handler);
@@ -142,7 +143,7 @@ public static class RequestDelegateRouteBuilderExtensions
     /// <param name="template">The route template.</param>
     /// <param name="handler">The <see cref="RequestDelegate"/> route handler.</param>
     /// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
-    public static IRouteBuilder MapPost(this IRouteBuilder builder, string template, RequestDelegate handler)
+    public static IRouteBuilder MapPost(this IRouteBuilder builder, [StringSyntax("Route")] string template, RequestDelegate handler)
     {
         return builder.MapVerb(HttpMethods.Post, template, handler);
     }
@@ -155,7 +156,7 @@ public static class RequestDelegateRouteBuilderExtensions
     /// <param name="template">The route template.</param>
     /// <param name="action">The action to apply to the <see cref="IApplicationBuilder"/>.</param>
     /// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
-    public static IRouteBuilder MapMiddlewarePost(this IRouteBuilder builder, string template, Action<IApplicationBuilder> action)
+    public static IRouteBuilder MapMiddlewarePost(this IRouteBuilder builder, [StringSyntax("Route")] string template, Action<IApplicationBuilder> action)
     {
         return builder.MapMiddlewareVerb(HttpMethods.Post, template, action);
     }
@@ -170,7 +171,7 @@ public static class RequestDelegateRouteBuilderExtensions
     /// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
     public static IRouteBuilder MapPost(
         this IRouteBuilder builder,
-        string template,
+        [StringSyntax("Route")] string template,
         Func<HttpRequest, HttpResponse, RouteData, Task> handler)
     {
         return builder.MapVerb(HttpMethods.Post, template, handler);
@@ -184,7 +185,7 @@ public static class RequestDelegateRouteBuilderExtensions
     /// <param name="template">The route template.</param>
     /// <param name="handler">The <see cref="RequestDelegate"/> route handler.</param>
     /// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
-    public static IRouteBuilder MapPut(this IRouteBuilder builder, string template, RequestDelegate handler)
+    public static IRouteBuilder MapPut(this IRouteBuilder builder, [StringSyntax("Route")] string template, RequestDelegate handler)
     {
         return builder.MapVerb(HttpMethods.Put, template, handler);
     }
@@ -197,7 +198,7 @@ public static class RequestDelegateRouteBuilderExtensions
     /// <param name="template">The route template.</param>
     /// <param name="action">The action to apply to the <see cref="IApplicationBuilder"/>.</param>
     /// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
-    public static IRouteBuilder MapMiddlewarePut(this IRouteBuilder builder, string template, Action<IApplicationBuilder> action)
+    public static IRouteBuilder MapMiddlewarePut(this IRouteBuilder builder, [StringSyntax("Route")] string template, Action<IApplicationBuilder> action)
     {
         return builder.MapMiddlewareVerb(HttpMethods.Put, template, action);
     }
@@ -212,7 +213,7 @@ public static class RequestDelegateRouteBuilderExtensions
     /// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
     public static IRouteBuilder MapPut(
         this IRouteBuilder builder,
-        string template,
+        [StringSyntax("Route")] string template,
         Func<HttpRequest, HttpResponse, RouteData, Task> handler)
     {
         return builder.MapVerb(HttpMethods.Put, template, handler);
@@ -230,7 +231,7 @@ public static class RequestDelegateRouteBuilderExtensions
     public static IRouteBuilder MapVerb(
         this IRouteBuilder builder,
         string verb,
-        string template,
+        [StringSyntax("Route")] string template,
         Func<HttpRequest, HttpResponse, RouteData, Task> handler)
     {
         RequestDelegate requestDelegate = (httpContext) =>
@@ -253,7 +254,7 @@ public static class RequestDelegateRouteBuilderExtensions
     public static IRouteBuilder MapVerb(
         this IRouteBuilder builder,
         string verb,
-        string template,
+        [StringSyntax("Route")] string template,
         RequestDelegate handler)
     {
         var constraints = new RouteValueDictionary
@@ -285,7 +286,7 @@ public static class RequestDelegateRouteBuilderExtensions
     public static IRouteBuilder MapMiddlewareVerb(
         this IRouteBuilder builder,
         string verb,
-        string template,
+        [StringSyntax("Route")] string template,
         Action<IApplicationBuilder> action)
     {
         var nested = builder.ApplicationBuilder.New();

+ 5 - 3
src/Http/Routing/src/Route.cs

@@ -1,6 +1,8 @@
 // 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.CodeAnalysis;
+
 namespace Microsoft.AspNetCore.Routing;
 
 /// <summary>
@@ -18,7 +20,7 @@ public class Route : RouteBase
     /// <param name="inlineConstraintResolver">An <see cref="IInlineConstraintResolver"/> used for resolving inline constraints.</param>
     public Route(
         IRouter target,
-        string routeTemplate,
+        [StringSyntax("Route")] string routeTemplate,
         IInlineConstraintResolver inlineConstraintResolver)
         : this(
             target,
@@ -41,7 +43,7 @@ public class Route : RouteBase
     /// <param name="inlineConstraintResolver">An <see cref="IInlineConstraintResolver"/> used for resolving inline constraints.</param>
     public Route(
         IRouter target,
-        string routeTemplate,
+        [StringSyntax("Route")] string routeTemplate,
         RouteValueDictionary? defaults,
         IDictionary<string, object>? constraints,
         RouteValueDictionary? dataTokens,
@@ -63,7 +65,7 @@ public class Route : RouteBase
     public Route(
         IRouter target,
         string? routeName,
-        string? routeTemplate,
+        [StringSyntax("Route")] string? routeTemplate,
         RouteValueDictionary? defaults,
         IDictionary<string, object>? constraints,
         RouteValueDictionary? dataTokens,

+ 1 - 1
src/Http/Routing/src/RouteBase.cs

@@ -32,7 +32,7 @@ public abstract partial class RouteBase : IRouter, INamedRouter
     /// <param name="constraints">The constraints for the route.</param>
     /// <param name="dataTokens">The data tokens for the route.</param>
     public RouteBase(
-        string? template,
+        [StringSyntax("Route")] string? template,
         string? name,
         IInlineConstraintResolver constraintResolver,
         RouteValueDictionary? defaults,

+ 3 - 2
src/Middleware/StaticFiles/src/StaticFilesEndpointRouteBuilderExtensions.cs

@@ -1,6 +1,7 @@
 // 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.CodeAnalysis;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Routing;
 using Microsoft.AspNetCore.StaticFiles;
@@ -120,7 +121,7 @@ public static class StaticFilesEndpointRouteBuilderExtensions
     /// </remarks>
     public static IEndpointConventionBuilder MapFallbackToFile(
         this IEndpointRouteBuilder endpoints,
-        string pattern,
+        [StringSyntax("Route")] string pattern,
         string filePath)
     {
         if (endpoints == null)
@@ -168,7 +169,7 @@ public static class StaticFilesEndpointRouteBuilderExtensions
     /// </remarks>
     public static IEndpointConventionBuilder MapFallbackToFile(
         this IEndpointRouteBuilder endpoints,
-        string pattern,
+        [StringSyntax("Route")] string pattern,
         string filePath,
         StaticFileOptions options)
     {

+ 2 - 0
src/Mvc/Mvc.Core/src/AcceptVerbsAttribute.cs

@@ -1,6 +1,7 @@
 // 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.CodeAnalysis;
 using System.Linq;
 using Microsoft.AspNetCore.Mvc.Routing;
 
@@ -46,6 +47,7 @@ public sealed class AcceptVerbsAttribute : Attribute, IActionHttpMethodProvider,
     /// <summary>
     /// The route template. May be null.
     /// </summary>
+    [StringSyntax("Route")]
     public string? Route { get; set; }
 
     /// <inheritdoc />

+ 5 - 3
src/Mvc/Mvc.Core/src/ApplicationModels/AttributeRouteModel.cs

@@ -1,6 +1,7 @@
 // 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.CodeAnalysis;
 using System.Linq;
 using System.Text;
 using Microsoft.AspNetCore.Mvc.Core;
@@ -67,6 +68,7 @@ public class AttributeRouteModel
     /// <summary>
     /// Gets or sets the attribute route template.
     /// </summary>
+    [StringSyntax("Route")]
     public string? Template { get; set; }
 
     /// <summary>
@@ -140,7 +142,7 @@ public class AttributeRouteModel
     /// <param name="prefix">The prefix.</param>
     /// <param name="template">The route template.</param>
     /// <returns>The combined pattern.</returns>
-    public static string? CombineTemplates(string? prefix, string? template)
+    public static string? CombineTemplates([StringSyntax("Route")] string? prefix, [StringSyntax("Route")] string? template)
     {
         var result = CombineCore(prefix, template);
         return CleanTemplate(result);
@@ -154,7 +156,7 @@ public class AttributeRouteModel
     /// <remarks>
     /// Route templates starting with "~/" or "/" can be used to override the prefix.
     /// </remarks>
-    public static bool IsOverridePattern(string? template)
+    public static bool IsOverridePattern([StringSyntax("Route")] string? template)
     {
         return template != null &&
             (template.StartsWith("~/", StringComparison.Ordinal) ||
@@ -265,7 +267,7 @@ public class AttributeRouteModel
     /// <param name="values">The token values to use.</param>
     /// <param name="routeTokenTransformer">The route token transformer.</param>
     /// <returns>A new string with the replaced values.</returns>
-    public static string ReplaceTokens(string template, IDictionary<string, string?> values, IOutboundParameterTransformer? routeTokenTransformer)
+    public static string ReplaceTokens([StringSyntax("Route")] string template, IDictionary<string, string?> values, IOutboundParameterTransformer? routeTokenTransformer)
     {
         var builder = new StringBuilder();
         var state = TemplateParserState.Plaintext;

+ 8 - 7
src/Mvc/Mvc.Core/src/Builder/ControllerEndpointRouteBuilderExtensions.cs

@@ -1,6 +1,7 @@
 // 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.CodeAnalysis;
 using System.Linq;
 using Microsoft.AspNetCore.Mvc.Core;
 using Microsoft.AspNetCore.Mvc.Infrastructure;
@@ -85,7 +86,7 @@ public static class ControllerEndpointRouteBuilderExtensions
     public static ControllerActionEndpointConventionBuilder MapControllerRoute(
         this IEndpointRouteBuilder endpoints,
         string name,
-        string pattern,
+        [StringSyntax("Route")] string pattern,
         object? defaults = null,
         object? constraints = null,
         object? dataTokens = null)
@@ -134,7 +135,7 @@ public static class ControllerEndpointRouteBuilderExtensions
         this IEndpointRouteBuilder endpoints,
         string name,
         string areaName,
-        string pattern,
+        [StringSyntax("Route")] string pattern,
         object? defaults = null,
         object? constraints = null,
         object? dataTokens = null)
@@ -263,7 +264,7 @@ public static class ControllerEndpointRouteBuilderExtensions
     /// </remarks>
     public static IEndpointConventionBuilder MapFallbackToController(
         this IEndpointRouteBuilder endpoints,
-        string pattern,
+        [StringSyntax("Route")] string pattern,
         string action,
         string controller)
     {
@@ -414,7 +415,7 @@ public static class ControllerEndpointRouteBuilderExtensions
     /// </remarks>
     public static IEndpointConventionBuilder MapFallbackToAreaController(
         this IEndpointRouteBuilder endpoints,
-        string pattern,
+        [StringSyntax("Route")] string pattern,
         string action,
         string controller,
         string area)
@@ -475,7 +476,7 @@ public static class ControllerEndpointRouteBuilderExtensions
     /// Register <typeparamref name="TTransformer"/> with the desired service lifetime in <c>ConfigureServices</c>.
     /// </para>
     /// </remarks>
-    public static void MapDynamicControllerRoute<TTransformer>(this IEndpointRouteBuilder endpoints, string pattern)
+    public static void MapDynamicControllerRoute<TTransformer>(this IEndpointRouteBuilder endpoints, [StringSyntax("Route")] string pattern)
         where TTransformer : DynamicRouteValueTransformer
     {
         if (endpoints == null)
@@ -505,7 +506,7 @@ public static class ControllerEndpointRouteBuilderExtensions
     /// is required when using <paramref name="state" />.
     /// </para>
     /// </remarks>
-    public static void MapDynamicControllerRoute<TTransformer>(this IEndpointRouteBuilder endpoints, string pattern, object? state)
+    public static void MapDynamicControllerRoute<TTransformer>(this IEndpointRouteBuilder endpoints, [StringSyntax("Route")] string pattern, object? state)
         where TTransformer : DynamicRouteValueTransformer
     {
         if (endpoints == null)
@@ -543,7 +544,7 @@ public static class ControllerEndpointRouteBuilderExtensions
     /// is required when using <paramref name="state" />.
     /// </para>
     /// </remarks>
-    public static void MapDynamicControllerRoute<TTransformer>(this IEndpointRouteBuilder endpoints, string pattern, object state, int order)
+    public static void MapDynamicControllerRoute<TTransformer>(this IEndpointRouteBuilder endpoints, [StringSyntax("Route")] string pattern, object state, int order)
         where TTransformer : DynamicRouteValueTransformer
     {
         if (endpoints == null)

+ 5 - 4
src/Mvc/Mvc.Core/src/Builder/MvcAreaRouteBuilderExtensions.cs

@@ -1,6 +1,7 @@
 // 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.CodeAnalysis;
 using Microsoft.AspNetCore.Mvc.Core;
 using Microsoft.AspNetCore.Routing;
 using Microsoft.AspNetCore.Routing.Constraints;
@@ -25,7 +26,7 @@ public static class MvcAreaRouteBuilderExtensions
         this IRouteBuilder routeBuilder,
         string name,
         string areaName,
-        string? template)
+        [StringSyntax("Route")] string? template)
     {
         MapAreaRoute(routeBuilder, name, areaName, template, defaults: null, constraints: null, dataTokens: null);
         return routeBuilder;
@@ -49,7 +50,7 @@ public static class MvcAreaRouteBuilderExtensions
         this IRouteBuilder routeBuilder,
         string name,
         string areaName,
-        string? template,
+        [StringSyntax("Route")] string? template,
         object? defaults)
     {
         MapAreaRoute(routeBuilder, name, areaName, template, defaults, constraints: null, dataTokens: null);
@@ -78,7 +79,7 @@ public static class MvcAreaRouteBuilderExtensions
         this IRouteBuilder routeBuilder,
         string name,
         string areaName,
-        string? template,
+        [StringSyntax("Route")] string? template,
         object? defaults,
         object? constraints)
     {
@@ -112,7 +113,7 @@ public static class MvcAreaRouteBuilderExtensions
         this IRouteBuilder routeBuilder,
         string name,
         string areaName,
-        string? template,
+        [StringSyntax("Route")] string? template,
         object? defaults,
         object? constraints,
         object? dataTokens)

+ 2 - 1
src/Mvc/Mvc.Core/src/HttpDeleteAttribute.cs

@@ -1,6 +1,7 @@
 // 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.CodeAnalysis;
 using Microsoft.AspNetCore.Mvc.Routing;
 
 namespace Microsoft.AspNetCore.Mvc;
@@ -24,7 +25,7 @@ public class HttpDeleteAttribute : HttpMethodAttribute
     /// Creates a new <see cref="HttpDeleteAttribute"/> with the given route template.
     /// </summary>
     /// <param name="template">The route template. May not be null.</param>
-    public HttpDeleteAttribute(string template)
+    public HttpDeleteAttribute([StringSyntax("Route")] string template)
         : base(_supportedMethods, template)
     {
         if (template == null)

+ 2 - 1
src/Mvc/Mvc.Core/src/HttpGetAttribute.cs

@@ -1,6 +1,7 @@
 // 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.CodeAnalysis;
 using Microsoft.AspNetCore.Mvc.Routing;
 
 namespace Microsoft.AspNetCore.Mvc;
@@ -24,7 +25,7 @@ public class HttpGetAttribute : HttpMethodAttribute
     /// Creates a new <see cref="HttpGetAttribute"/> with the given route template.
     /// </summary>
     /// <param name="template">The route template. May not be null.</param>
-    public HttpGetAttribute(string template)
+    public HttpGetAttribute([StringSyntax("Route")] string template)
         : base(_supportedMethods, template)
     {
         if (template == null)

+ 2 - 1
src/Mvc/Mvc.Core/src/HttpHeadAttribute.cs

@@ -1,6 +1,7 @@
 // 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.CodeAnalysis;
 using Microsoft.AspNetCore.Mvc.Routing;
 
 namespace Microsoft.AspNetCore.Mvc;
@@ -24,7 +25,7 @@ public class HttpHeadAttribute : HttpMethodAttribute
     /// Creates a new <see cref="HttpHeadAttribute"/> with the given route template.
     /// </summary>
     /// <param name="template">The route template. May not be null.</param>
-    public HttpHeadAttribute(string template)
+    public HttpHeadAttribute([StringSyntax("Route")] string template)
         : base(_supportedMethods, template)
     {
         if (template == null)

+ 2 - 1
src/Mvc/Mvc.Core/src/HttpOptionsAttribute.cs

@@ -1,6 +1,7 @@
 // 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.CodeAnalysis;
 using Microsoft.AspNetCore.Mvc.Routing;
 
 namespace Microsoft.AspNetCore.Mvc;
@@ -24,7 +25,7 @@ public class HttpOptionsAttribute : HttpMethodAttribute
     /// Creates a new <see cref="HttpOptionsAttribute"/> with the given route template.
     /// </summary>
     /// <param name="template">The route template. May not be null.</param>
-    public HttpOptionsAttribute(string template)
+    public HttpOptionsAttribute([StringSyntax("Route")] string template)
         : base(_supportedMethods, template)
     {
         if (template == null)

+ 2 - 1
src/Mvc/Mvc.Core/src/HttpPatchAttribute.cs

@@ -1,6 +1,7 @@
 // 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.CodeAnalysis;
 using Microsoft.AspNetCore.Mvc.Routing;
 
 namespace Microsoft.AspNetCore.Mvc;
@@ -24,7 +25,7 @@ public class HttpPatchAttribute : HttpMethodAttribute
     /// Creates a new <see cref="HttpPatchAttribute"/> with the given route template.
     /// </summary>
     /// <param name="template">The route template. May not be null.</param>
-    public HttpPatchAttribute(string template)
+    public HttpPatchAttribute([StringSyntax("Route")] string template)
         : base(_supportedMethods, template)
     {
         if (template == null)

+ 2 - 1
src/Mvc/Mvc.Core/src/HttpPostAttribute.cs

@@ -1,6 +1,7 @@
 // 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.CodeAnalysis;
 using Microsoft.AspNetCore.Mvc.Routing;
 
 namespace Microsoft.AspNetCore.Mvc;
@@ -24,7 +25,7 @@ public class HttpPostAttribute : HttpMethodAttribute
     /// Creates a new <see cref="HttpPostAttribute"/> with the given route template.
     /// </summary>
     /// <param name="template">The route template. May not be null.</param>
-    public HttpPostAttribute(string template)
+    public HttpPostAttribute([StringSyntax("Route")] string template)
         : base(_supportedMethods, template)
     {
         if (template == null)

+ 2 - 1
src/Mvc/Mvc.Core/src/HttpPutAttribute.cs

@@ -1,6 +1,7 @@
 // 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.CodeAnalysis;
 using Microsoft.AspNetCore.Mvc.Routing;
 
 namespace Microsoft.AspNetCore.Mvc;
@@ -24,7 +25,7 @@ public class HttpPutAttribute : HttpMethodAttribute
     /// Creates a new <see cref="HttpPutAttribute"/> with the given route template.
     /// </summary>
     /// <param name="template">The route template. May not be null.</param>
-    public HttpPutAttribute(string template)
+    public HttpPutAttribute([StringSyntax("Route")] string template)
         : base(_supportedMethods, template)
     {
         if (template == null)

+ 3 - 1
src/Mvc/Mvc.Core/src/RouteAttribute.cs

@@ -1,6 +1,7 @@
 // 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.CodeAnalysis;
 using Microsoft.AspNetCore.Mvc.Routing;
 
 namespace Microsoft.AspNetCore.Mvc;
@@ -17,12 +18,13 @@ public class RouteAttribute : Attribute, IRouteTemplateProvider
     /// Creates a new <see cref="RouteAttribute"/> with the given route template.
     /// </summary>
     /// <param name="template">The route template. May not be null.</param>
-    public RouteAttribute(string template)
+    public RouteAttribute([StringSyntax("Route")] string template)
     {
         Template = template ?? throw new ArgumentNullException(nameof(template));
     }
 
     /// <inheritdoc />
+    [StringSyntax("Route")]
     public string Template { get; }
 
     /// <summary>

+ 2 - 1
src/Mvc/Mvc.Core/src/Routing/HttpMethodAttribute.cs

@@ -32,7 +32,7 @@ public abstract class HttpMethodAttribute : Attribute, IActionHttpMethodProvider
     /// </summary>
     /// <param name="httpMethods">The set of supported methods. May not be null.</param>
     /// <param name="template">The route template.</param>
-    public HttpMethodAttribute(IEnumerable<string> httpMethods, string? template)
+    public HttpMethodAttribute(IEnumerable<string> httpMethods, [StringSyntax("Route")] string? template)
     {
         if (httpMethods == null)
         {
@@ -47,6 +47,7 @@ public abstract class HttpMethodAttribute : Attribute, IActionHttpMethodProvider
     public IEnumerable<string> HttpMethods => _httpMethods;
 
     /// <inheritdoc />
+    [StringSyntax("Route")]
     public string? Template { get; }
 
     /// <summary>

+ 3 - 0
src/Mvc/Mvc.Core/src/Routing/IRouteTemplateProvider.cs

@@ -1,6 +1,8 @@
 // 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.CodeAnalysis;
+
 namespace Microsoft.AspNetCore.Mvc.Routing;
 
 /// <summary>
@@ -11,6 +13,7 @@ public interface IRouteTemplateProvider
     /// <summary>
     /// The route template. May be <see langword="null"/>.
     /// </summary>
+    [StringSyntax("Route")]
     string? Template { get; }
 
     /// <summary>

+ 3 - 2
src/Mvc/Mvc.RazorPages/src/DependencyInjection/PageConventionCollectionExtensions.cs

@@ -1,6 +1,7 @@
 // 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.CodeAnalysis;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Mvc.ApplicationModels;
 using Microsoft.AspNetCore.Mvc.Authorization;
@@ -466,7 +467,7 @@ public static class PageConventionCollectionExtensions
     /// <param name="pageName">The page name.</param>
     /// <param name="route">The route to associate with the page.</param>
     /// <returns>The <see cref="PageConventionCollection"/>.</returns>
-    public static PageConventionCollection AddPageRoute(this PageConventionCollection conventions, string pageName, string route)
+    public static PageConventionCollection AddPageRoute(this PageConventionCollection conventions, string pageName, [StringSyntax("Route")] string route)
     {
         if (conventions == null)
         {
@@ -511,7 +512,7 @@ public static class PageConventionCollectionExtensions
         this PageConventionCollection conventions,
         string areaName,
         string pageName,
-        string route)
+        [StringSyntax("Route")] string route)
     {
         if (conventions == null)
         {