From 9e2c389ab7f31d45e4e805edba34341ff859749b Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Thu, 27 Oct 2022 13:02:00 -0500 Subject: [PATCH 1/2] Use the Regex source generator in the AlphaRouteConstraint. The Regex source generator is faster because it doesn't need to interpret the regex. It does add slightly more code to the compiled app, but the tradeoff seems worth it. I switched the pattern from `a-z` with IgnoreCase to `A-Za-z` because the source generator generates better code with that pattern. --- .../SingleRouteWithConstraintsBenchmark.cs | 4 ++-- src/Http/Routing/src/Constraints/AlphaRouteConstraint.cs | 9 +++++++-- src/Http/Routing/src/Constraints/RegexRouteConstraint.cs | 3 ++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Http/Routing/perf/Microbenchmarks/LinkGeneration/SingleRouteWithConstraintsBenchmark.cs b/src/Http/Routing/perf/Microbenchmarks/LinkGeneration/SingleRouteWithConstraintsBenchmark.cs index 925bc5159db7..ea22d5cb45c2 100644 --- a/src/Http/Routing/perf/Microbenchmarks/LinkGeneration/SingleRouteWithConstraintsBenchmark.cs +++ b/src/Http/Routing/perf/Microbenchmarks/LinkGeneration/SingleRouteWithConstraintsBenchmark.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using BenchmarkDotNet.Attributes; @@ -17,7 +17,7 @@ public class SingleRouteWithConstraintsBenchmark : EndpointRoutingBenchmarkBase [GlobalSetup] public void Setup() { - var template = "Customers/Details/{category}/{region}/{id:int}"; + var template = "Customers/Details/{category:alpha}/{region:alpha}/{id:int}"; var defaults = new { controller = "Customers", action = "Details" }; var requiredValues = new { controller = "Customers", action = "Details" }; diff --git a/src/Http/Routing/src/Constraints/AlphaRouteConstraint.cs b/src/Http/Routing/src/Constraints/AlphaRouteConstraint.cs index abb503139640..0e9cf957ac95 100644 --- a/src/Http/Routing/src/Constraints/AlphaRouteConstraint.cs +++ b/src/Http/Routing/src/Constraints/AlphaRouteConstraint.cs @@ -1,17 +1,22 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.RegularExpressions; + namespace Microsoft.AspNetCore.Routing.Constraints; /// /// Constrains a route parameter to contain only lowercase or uppercase letters A through Z in the English alphabet. /// -public class AlphaRouteConstraint : RegexRouteConstraint +public partial class AlphaRouteConstraint : RegexRouteConstraint { /// /// Initializes a new instance of the class. /// - public AlphaRouteConstraint() : base(@"^[a-z]*$") + public AlphaRouteConstraint() : base(GetAlphaRouteRegex()) { } + + [GeneratedRegex(@"^[A-Za-z]*$", RegexOptions.CultureInvariant)] + private static partial Regex GetAlphaRouteRegex(); } diff --git a/src/Http/Routing/src/Constraints/RegexRouteConstraint.cs b/src/Http/Routing/src/Constraints/RegexRouteConstraint.cs index 27b0a08a9de9..f9228fb9d90e 100644 --- a/src/Http/Routing/src/Constraints/RegexRouteConstraint.cs +++ b/src/Http/Routing/src/Constraints/RegexRouteConstraint.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.Globalization; using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; @@ -33,7 +34,7 @@ public RegexRouteConstraint(Regex regex) /// Constructor for a given a . /// /// A string containing the regex pattern. - public RegexRouteConstraint(string regexPattern) + public RegexRouteConstraint([StringSyntax(StringSyntaxAttribute.Regex)] string regexPattern) { if (regexPattern == null) { From 14762a33ffa008dd88bf85e424aac66f63ea86ba Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Thu, 10 Nov 2022 16:41:13 -0600 Subject: [PATCH 2/2] PR feedback --- src/Http/Routing/src/Constraints/AlphaRouteConstraint.cs | 2 +- src/Http/Routing/src/Constraints/RegexRouteConstraint.cs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Http/Routing/src/Constraints/AlphaRouteConstraint.cs b/src/Http/Routing/src/Constraints/AlphaRouteConstraint.cs index 0e9cf957ac95..687481275388 100644 --- a/src/Http/Routing/src/Constraints/AlphaRouteConstraint.cs +++ b/src/Http/Routing/src/Constraints/AlphaRouteConstraint.cs @@ -17,6 +17,6 @@ public AlphaRouteConstraint() : base(GetAlphaRouteRegex()) { } - [GeneratedRegex(@"^[A-Za-z]*$", RegexOptions.CultureInvariant)] + [GeneratedRegex(@"^[A-Za-z]*$")] private static partial Regex GetAlphaRouteRegex(); } diff --git a/src/Http/Routing/src/Constraints/RegexRouteConstraint.cs b/src/Http/Routing/src/Constraints/RegexRouteConstraint.cs index f9228fb9d90e..1d7d7e5e6b52 100644 --- a/src/Http/Routing/src/Constraints/RegexRouteConstraint.cs +++ b/src/Http/Routing/src/Constraints/RegexRouteConstraint.cs @@ -34,7 +34,9 @@ public RegexRouteConstraint(Regex regex) /// Constructor for a given a . /// /// A string containing the regex pattern. - public RegexRouteConstraint([StringSyntax(StringSyntaxAttribute.Regex)] string regexPattern) + public RegexRouteConstraint( + [StringSyntax(StringSyntaxAttribute.Regex, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase)] + string regexPattern) { if (regexPattern == null) {