diff --git a/src/BootstrapBlazor/Components/Tab/BootstrapBlazorAuthorizeView.cs b/src/BootstrapBlazor/Components/Tab/BootstrapBlazorAuthorizeView.cs
index fbf60ae680c..01b83611cb6 100644
--- a/src/BootstrapBlazor/Components/Tab/BootstrapBlazorAuthorizeView.cs
+++ b/src/BootstrapBlazor/Components/Tab/BootstrapBlazorAuthorizeView.cs
@@ -11,7 +11,7 @@
namespace BootstrapBlazor.Components;
///
-///
+/// BootstrapBlazorAuthorizeView 组件
///
public class BootstrapBlazorAuthorizeView : ComponentBase
{
@@ -49,16 +49,14 @@ public class BootstrapBlazorAuthorizeView : ComponentBase
[Inject]
private IAuthorizationService? AuthorizationService { get; set; }
-#if NET6_0_OR_GREATER
[Inject]
[NotNull]
private NavigationManager? NavigationManager { get; set; }
-#endif
private bool Authorized { get; set; }
///
- /// OnInitializedAsync 方法
+ ///
///
///
protected override async Task OnInitializedAsync()
@@ -68,7 +66,7 @@ protected override async Task OnInitializedAsync()
}
///
- /// BuildRenderTree 方法
+ ///
///
///
protected override void BuildRenderTree(RenderTreeBuilder builder)
@@ -82,9 +80,7 @@ protected override void BuildRenderTree(RenderTreeBuilder builder)
{
builder.AddAttribute(index++, kv.Key, kv.Value);
}
-#if NET6_0_OR_GREATER
BuildQueryParameters();
-#endif
builder.CloseComponent();
}
else
@@ -92,7 +88,6 @@ protected override void BuildRenderTree(RenderTreeBuilder builder)
builder.AddContent(0, NotAuthorized);
}
-#if NET6_0_OR_GREATER
void BuildQueryParameters()
{
var queryParameterSupplier = QueryParameterValueSupplier.ForType(Type);
@@ -106,6 +101,5 @@ void BuildQueryParameters()
queryParameterSupplier.RenderParametersFromQueryString(builder, query);
}
}
-#endif
}
}
diff --git a/src/BootstrapBlazor/Components/Tab/Route/IRouteTable.cs b/src/BootstrapBlazor/Components/Tab/Route/IRouteTable.cs
deleted file mode 100644
index bad59907899..00000000000
--- a/src/BootstrapBlazor/Components/Tab/Route/IRouteTable.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-// Website: https://www.blazor.zone or https://argozhang.github.io/
-
-namespace Microsoft.AspNetCore.Components.Routing;
-
-#if NET5_0
-///
-/// Provides an abstraction over .
-/// the legacy route matching logic is removed.
-///
-internal interface IRouteTable
-{
- void Route(RouteContext routeContext);
-}
-#endif
diff --git a/src/BootstrapBlazor/Components/Tab/Route/RouteConstraint.cs b/src/BootstrapBlazor/Components/Tab/Route/RouteConstraint.cs
index 3b3067e24a7..7139243ab1c 100644
--- a/src/BootstrapBlazor/Components/Tab/Route/RouteConstraint.cs
+++ b/src/BootstrapBlazor/Components/Tab/Route/RouteConstraint.cs
@@ -5,86 +5,6 @@
namespace Microsoft.AspNetCore.Components.Routing;
[ExcludeFromCodeCoverage]
-#if NET5_0
-internal abstract class RouteConstraint
-{
- // note: the things that prevent this cache from growing unbounded is that
- // we're the only caller to this code path, and the fact that there are only
- // 8 possible instances that we create.
- //
- // The values passed in here for parsing are always static text defined in route attributes.
- private static readonly ConcurrentDictionary _cachedConstraints
- = new ConcurrentDictionary();
-
- public abstract bool Match(string pathSegment, out object? convertedValue);
-
- public static RouteConstraint Parse(string template, string segment, string constraint)
- {
- if (string.IsNullOrEmpty(constraint))
- {
- throw new ArgumentException($"Malformed segment '{segment}' in route '{template}' contains an empty constraint.");
- }
-
- if (_cachedConstraints.TryGetValue(constraint, out var cachedInstance))
- {
- return cachedInstance;
- }
- else
- {
- var newInstance = CreateRouteConstraint(constraint);
- if (newInstance != null)
- {
- // We've done to the work to create the constraint now, but it's possible
- // we're competing with another thread. GetOrAdd can ensure only a single
- // instance is returned so that any extra ones can be GC'ed.
- return _cachedConstraints.GetOrAdd(constraint, newInstance);
- }
- else
- {
- throw new ArgumentException($"Unsupported constraint '{constraint}' in route '{template}'.");
- }
- }
- }
-
- ///
- /// Creates a structured RouteConstraint object given a string that contains
- /// the route constraint. A constraint is the place after the colon in a
- /// parameter definition, for example `{age:int?}`.
- ///
- /// String representation of the constraint
- /// Type-specific RouteConstraint object
- private static RouteConstraint? CreateRouteConstraint(string constraint)
- {
- switch (constraint)
- {
- case "bool":
- return new TypeRouteConstraint(bool.TryParse);
- case "datetime":
- return new TypeRouteConstraint((string str, out DateTime result)
- => DateTime.TryParse(str, CultureInfo.InvariantCulture, DateTimeStyles.None, out result));
- case "decimal":
- return new TypeRouteConstraint((string str, out decimal result)
- => decimal.TryParse(str, NumberStyles.Number, CultureInfo.InvariantCulture, out result));
- case "double":
- return new TypeRouteConstraint((string str, out double result)
- => double.TryParse(str, NumberStyles.Number, CultureInfo.InvariantCulture, out result));
- case "float":
- return new TypeRouteConstraint((string str, out float result)
- => float.TryParse(str, NumberStyles.Number, CultureInfo.InvariantCulture, out result));
- case "guid":
- return new TypeRouteConstraint(Guid.TryParse);
- case "int":
- return new TypeRouteConstraint((string str, out int result)
- => int.TryParse(str, NumberStyles.Integer, CultureInfo.InvariantCulture, out result));
- case "long":
- return new TypeRouteConstraint((string str, out long result)
- => long.TryParse(str, NumberStyles.Integer, CultureInfo.InvariantCulture, out result));
- default:
- return null;
- }
- }
-}
-#else
internal static class RouteConstraint
{
public static UrlValueConstraint Parse(string template, string segment, string constraint)
@@ -116,4 +36,3 @@ public static UrlValueConstraint Parse(string template, string segment, string c
_ => null,
};
}
-#endif
diff --git a/src/BootstrapBlazor/Components/Tab/Route/RouteContext.cs b/src/BootstrapBlazor/Components/Tab/Route/RouteContext.cs
index 41e77c24f5e..685b87a859c 100644
--- a/src/BootstrapBlazor/Components/Tab/Route/RouteContext.cs
+++ b/src/BootstrapBlazor/Components/Tab/Route/RouteContext.cs
@@ -23,9 +23,7 @@ public RouteContext(string path)
public string[] Segments { get; }
-#if NET6_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
-#endif
public Type? Handler { get; set; }
public IReadOnlyDictionary? Parameters { get; set; }
diff --git a/src/BootstrapBlazor/Components/Tab/Route/RouteEntry.cs b/src/BootstrapBlazor/Components/Tab/Route/RouteEntry.cs
index d32e78dc5cd..b14a2c3e31a 100644
--- a/src/BootstrapBlazor/Components/Tab/Route/RouteEntry.cs
+++ b/src/BootstrapBlazor/Components/Tab/Route/RouteEntry.cs
@@ -9,144 +9,6 @@
namespace Microsoft.AspNetCore.Components.Routing;
[ExcludeFromCodeCoverage]
-#if NET5_0
-[DebuggerDisplay("Handler = {Handler}, Template = {Template}")]
-internal class RouteEntry
-{
- public RouteEntry(RouteTemplate template, Type handler, string[] unusedRouteParameterNames)
- {
- Template = template;
- UnusedRouteParameterNames = unusedRouteParameterNames;
- Handler = handler;
- }
-
- public RouteTemplate Template { get; }
-
- public string[] UnusedRouteParameterNames { get; }
-
- public Type Handler { get; }
-
- internal void Match(RouteContext context)
- {
- var pathIndex = 0;
- var templateIndex = 0;
- Dictionary parameters = null;
- // We will iterate over the path segments and the template segments until we have consumed
- // one of them.
- // There are three cases we need to account here for:
- // * Path is shorter than template ->
- // * This can match only if we have t-p optional parameters at the end.
- // * Path and template have the same number of segments
- // * This can happen when the catch-all segment matches 1 segment
- // * This can happen when an optional parameter has been specified.
- // * This can happen when the route only contains literals and parameters.
- // * Path is longer than template -> This can only match if the parameter has a catch-all at the end.
- // * We still need to iterate over all the path segments if the catch-all is constrained.
- // * We still need to iterate over all the template/path segments before the catch-all
- while (pathIndex < context.Segments.Length && templateIndex < Template.Segments.Length)
- {
- var pathSegment = context.Segments[pathIndex];
- var templateSegment = Template.Segments[templateIndex];
-
- var matches = templateSegment.Match(pathSegment, out var match);
- if (!matches)
- {
- // A constraint or literal didn't match
- return;
- }
-
- if (!templateSegment.IsCatchAll)
- {
- // We were dealing with a literal or a parameter, so just advance both cursors.
- pathIndex++;
- templateIndex++;
-
- if (templateSegment.IsParameter)
- {
- parameters ??= new(StringComparer.OrdinalIgnoreCase);
- parameters[templateSegment.Value] = match;
- }
- }
- else
- {
- if (templateSegment.Constraints.Length == 0)
- {
-
- // Unconstrained catch all, we can stop early
- parameters ??= new(StringComparer.OrdinalIgnoreCase);
- parameters[templateSegment.Value] = string.Join('/', context.Segments, pathIndex, context.Segments.Length - pathIndex);
-
- // Mark the remaining segments as consumed.
- pathIndex = context.Segments.Length;
-
- // Catch-alls are always last.
- templateIndex++;
-
- // We are done, so break out of the loop.
- break;
- }
- else
- {
- // For constrained catch-alls, we advance the path index but keep the template index on the catch-all.
- pathIndex++;
- if (pathIndex == context.Segments.Length)
- {
- parameters ??= new(StringComparer.OrdinalIgnoreCase);
- parameters[templateSegment.Value] = string.Join('/', context.Segments, templateIndex, context.Segments.Length - templateIndex);
-
- // This is important to signal that we consumed the entire template.
- templateIndex++;
- }
- }
- }
- }
-
- var hasRemainingOptionalSegments = templateIndex < Template.Segments.Length &&
- RemainingSegmentsAreOptional(pathIndex, Template.Segments);
-
- if ((pathIndex == context.Segments.Length && templateIndex == Template.Segments.Length) || hasRemainingOptionalSegments)
- {
- if (hasRemainingOptionalSegments)
- {
- parameters ??= new Dictionary(StringComparer.Ordinal);
- AddDefaultValues(parameters, templateIndex, Template.Segments);
- }
- if (UnusedRouteParameterNames?.Length > 0)
- {
- parameters ??= new Dictionary(StringComparer.Ordinal);
- for (var i = 0; i < UnusedRouteParameterNames.Length; i++)
- {
- parameters[UnusedRouteParameterNames[i]] = null;
- }
- }
- context.Handler = Handler;
- context.Parameters = parameters;
- }
- }
-
- private void AddDefaultValues(Dictionary parameters, int templateIndex, TemplateSegment[] segments)
- {
- for (var i = templateIndex; i < segments.Length; i++)
- {
- var currentSegment = segments[i];
- parameters[currentSegment.Value] = null;
- }
- }
-
- private bool RemainingSegmentsAreOptional(int index, TemplateSegment[] segments)
- {
- for (var i = index; index < segments.Length - 1; index++)
- {
- if (!segments[i].IsOptional)
- {
- return false;
- }
- }
-
- return segments[^1].IsOptional || segments[^1].IsCatchAll;
- }
-}
-#else
[DebuggerDisplay("Handler = {Handler}, Template = {Template}")]
internal class RouteEntry
{
@@ -284,4 +146,5 @@ private bool RemainingSegmentsAreOptional(int index, TemplateSegment[] segments)
return segments[^1].IsOptional || segments[^1].IsCatchAll;
}
}
-#endif
+
+#nullable restore warnings
diff --git a/src/BootstrapBlazor/Components/Tab/Route/RouteKey.cs b/src/BootstrapBlazor/Components/Tab/Route/RouteKey.cs
index a619b7447d5..d35d2c2aaff 100644
--- a/src/BootstrapBlazor/Components/Tab/Route/RouteKey.cs
+++ b/src/BootstrapBlazor/Components/Tab/Route/RouteKey.cs
@@ -5,7 +5,6 @@
namespace Microsoft.AspNetCore.Components.Routing;
-#if NET6_0_OR_GREATER
[ExcludeFromCodeCoverage]
internal readonly struct RouteKey : IEquatable
{
@@ -61,4 +60,3 @@ public override int GetHashCode()
return HashCode.Combine(AppAssembly, AdditionalAssemblies.Count);
}
}
-#endif
diff --git a/src/BootstrapBlazor/Components/Tab/Route/RouteTable.cs b/src/BootstrapBlazor/Components/Tab/Route/RouteTable.cs
index 94ab0bc298c..c2f6018ec46 100644
--- a/src/BootstrapBlazor/Components/Tab/Route/RouteTable.cs
+++ b/src/BootstrapBlazor/Components/Tab/Route/RouteTable.cs
@@ -5,11 +5,7 @@
namespace Microsoft.AspNetCore.Components.Routing;
[ExcludeFromCodeCoverage]
-#if NET5_0
-internal class RouteTable : IRouteTable
-#else
internal class RouteTable
-#endif
{
public RouteTable(RouteEntry[] routes)
{
diff --git a/src/BootstrapBlazor/Components/Tab/Route/RouteTableFactory.cs b/src/BootstrapBlazor/Components/Tab/Route/RouteTableFactory.cs
index e6b86ea3f60..ab6c3b17da4 100644
--- a/src/BootstrapBlazor/Components/Tab/Route/RouteTableFactory.cs
+++ b/src/BootstrapBlazor/Components/Tab/Route/RouteTableFactory.cs
@@ -7,234 +7,6 @@
namespace Microsoft.AspNetCore.Components.Routing;
-#if NET5_0
-///
-/// Resolves components for an application.
-///
-[ExcludeFromCodeCoverage]
-internal static class RouteTableFactory
- {
- private static readonly ConcurrentDictionary Cache =
- new ConcurrentDictionary();
- public static readonly IComparer RoutePrecedence = Comparer.Create(RouteComparison);
-
- public static RouteTable Create(IEnumerable assemblies)
- {
- var key = new Key(assemblies.OrderBy(a => a.FullName).ToArray());
- if (Cache.TryGetValue(key, out var resolvedComponents))
- {
- return resolvedComponents;
- }
-
- var componentTypes = key.Assemblies.SelectMany(a => a.ExportedTypes.Where(t => typeof(IComponent).IsAssignableFrom(t)));
- var routeTable = Create(componentTypes);
- Cache.TryAdd(key, routeTable);
- return routeTable;
- }
-
- internal static RouteTable Create(IEnumerable componentTypes)
- {
- var templatesByHandler = new Dictionary();
- foreach (var componentType in componentTypes)
- {
- // We're deliberately using inherit = false here.
- //
- // RouteAttribute is defined as non-inherited, because inheriting a route attribute always causes an
- // ambiguity. You end up with two components (base class and derived class) with the same route.
- var routeAttributes = componentType.GetCustomAttributes(inherit: false);
-
- var templates = routeAttributes.Select(t => t.Template).ToArray();
- templatesByHandler.Add(componentType, templates);
- }
- return Create(templatesByHandler);
- }
-
- internal static RouteTable Create(Dictionary templatesByHandler)
- {
- var routes = new List();
- foreach (var keyValuePair in templatesByHandler)
- {
- var parsedTemplates = keyValuePair.Value.Select(v => TemplateParser.ParseTemplate(v)).ToArray();
- var allRouteParameterNames = parsedTemplates
- .SelectMany(GetParameterNames)
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .ToArray();
-
- foreach (var parsedTemplate in parsedTemplates)
- {
- var unusedRouteParameterNames = allRouteParameterNames
- .Except(GetParameterNames(parsedTemplate), StringComparer.OrdinalIgnoreCase)
- .ToArray();
- var entry = new RouteEntry(parsedTemplate, keyValuePair.Key, unusedRouteParameterNames);
- routes.Add(entry);
- }
- }
-
- return new RouteTable(routes.OrderBy(id => id, RoutePrecedence).ToArray());
- }
-
- private static string[] GetParameterNames(RouteTemplate routeTemplate)
- {
- return routeTemplate.Segments
- .Where(s => s.IsParameter)
- .Select(s => s.Value)
- .ToArray();
- }
-
- ///
- /// Route precedence algorithm.
- /// We collect all the routes and sort them from most specific to
- /// less specific. The specificity of a route is given by the specificity
- /// of its segments and the position of those segments in the route.
- /// * A literal segment is more specific than a parameter segment.
- /// * A parameter segment with more constraints is more specific than one with fewer constraints
- /// * Segment earlier in the route are evaluated before segments later in the route.
- /// For example:
- /// /Literal is more specific than /Parameter
- /// /Route/With/{parameter} is more specific than /{multiple}/With/{parameters}
- /// /Product/{id:int} is more specific than /Product/{id}
- ///
- /// Routes can be ambiguous if:
- /// They are composed of literals and those literals have the same values (case insensitive)
- /// They are composed of a mix of literals and parameters, in the same relative order and the
- /// literals have the same values.
- /// For example:
- /// * /literal and /Literal
- /// /{parameter}/literal and /{something}/literal
- /// /{parameter:constraint}/literal and /{something:constraint}/literal
- ///
- /// To calculate the precedence we sort the list of routes as follows:
- /// * Shorter routes go first.
- /// * A literal wins over a parameter in precedence.
- /// * For literals with different values (case insensitive) we choose the lexical order
- /// * For parameters with different numbers of constraints, the one with more wins
- /// If we get to the end of the comparison routing we've detected an ambiguous pair of routes.
- ///
- internal static int RouteComparison(RouteEntry x, RouteEntry y)
- {
- if (ReferenceEquals(x, y))
- {
- return 0;
- }
-
- var xTemplate = x.Template;
- var yTemplate = y.Template;
- var minSegments = Math.Min(xTemplate.Segments.Length, yTemplate.Segments.Length);
- var currentResult = 0;
- for (var i = 0; i < minSegments; i++)
- {
- var xSegment = xTemplate.Segments[i];
- var ySegment = yTemplate.Segments[i];
-
- var xRank = GetRank(xSegment);
- var yRank = GetRank(ySegment);
-
- currentResult = xRank.CompareTo(yRank);
-
- // If they are both literals we can disambiguate
- if ((xRank, yRank) == (0, 0))
- {
- currentResult = StringComparer.OrdinalIgnoreCase.Compare(xSegment.Value, ySegment.Value);
- }
-
- if (currentResult != 0)
- {
- break;
- }
- }
-
- if (currentResult == 0)
- {
- currentResult = xTemplate.Segments.Length.CompareTo(yTemplate.Segments.Length);
- }
-
- if (currentResult == 0)
- {
- throw new InvalidOperationException($@"The following routes are ambiguous:
- '{x.Template.TemplateText}' in '{x.Handler.FullName}'
- '{y.Template.TemplateText}' in '{y.Handler.FullName}'
- ");
- }
-
- return currentResult;
- }
-
- private static int GetRank(TemplateSegment xSegment)
- {
- return xSegment switch
- {
- // Literal
- { IsParameter: false } => 0,
- // Parameter with constraints
- { IsParameter: true, IsCatchAll: false, Constraints: { Length: > 0 } } => 1,
- // Parameter without constraints
- { IsParameter: true, IsCatchAll: false, Constraints: { Length: 0 } } => 2,
- // Catch all parameter with constraints
- { IsParameter: true, IsCatchAll: true, Constraints: { Length: > 0 } } => 3,
- // Catch all parameter without constraints
- { IsParameter: true, IsCatchAll: true, Constraints: { Length: 0 } } => 4,
- // The segment is not correct
- _ => throw new InvalidOperationException($"Unknown segment definition '{xSegment}.")
- };
- }
-
- private readonly struct Key : IEquatable
- {
- public readonly Assembly[] Assemblies;
-
- public Key(Assembly[] assemblies)
- {
- Assemblies = assemblies;
- }
-
- public override bool Equals(object? obj)
- {
- return obj is Key other ? base.Equals(other) : false;
- }
-
- public bool Equals(Key other)
- {
- if (Assemblies == null && other.Assemblies == null)
- {
- return true;
- }
- else if ((Assemblies == null) || (other.Assemblies == null))
- {
- return false;
- }
- else if (Assemblies.Length != other.Assemblies.Length)
- {
- return false;
- }
-
- for (var i = 0; i < Assemblies.Length; i++)
- {
- if (!Assemblies[i].Equals(other.Assemblies[i]))
- {
- return false;
- }
- }
-
- return true;
- }
-
- public override int GetHashCode()
- {
- var hash = new HashCode();
-
- if (Assemblies != null)
- {
- for (var i = 0; i < Assemblies.Length; i++)
- {
- hash.Add(Assemblies[i]);
- }
- }
-
- return hash.ToHashCode();
- }
- }
- }
-#else
///
/// Resolves components for an application.
///
@@ -468,4 +240,3 @@ private static int GetRank(TemplateSegment xSegment)
};
}
}
-#endif
diff --git a/src/BootstrapBlazor/Components/Tab/Route/RouteTemplate.cs b/src/BootstrapBlazor/Components/Tab/Route/RouteTemplate.cs
index cde3c57bbf0..bd07dc010b9 100644
--- a/src/BootstrapBlazor/Components/Tab/Route/RouteTemplate.cs
+++ b/src/BootstrapBlazor/Components/Tab/Route/RouteTemplate.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
-
using System.Diagnostics;
namespace Microsoft.AspNetCore.Components.Routing;
@@ -16,10 +15,6 @@ public RouteTemplate(string templateText, TemplateSegment[] segments)
TemplateText = templateText;
Segments = segments;
-#if NET5_0
- OptionalSegmentsCount = segments.Count(template => template.IsOptional);
- ContainsCatchAllSegment = segments.Any(template => template.IsCatchAll);
-#else
for (var i = 0; i < segments.Length; i++)
{
var segment = segments[i];
@@ -32,7 +27,6 @@ public RouteTemplate(string templateText, TemplateSegment[] segments)
ContainsCatchAllSegment = true;
}
}
-#endif
}
public string TemplateText { get; }
diff --git a/src/BootstrapBlazor/Components/Tab/Route/StringSegmentAccumulator.cs b/src/BootstrapBlazor/Components/Tab/Route/StringSegmentAccumulator.cs
index 1fd988a302b..b1e4cd8fd5e 100644
--- a/src/BootstrapBlazor/Components/Tab/Route/StringSegmentAccumulator.cs
+++ b/src/BootstrapBlazor/Components/Tab/Route/StringSegmentAccumulator.cs
@@ -4,7 +4,6 @@
namespace Microsoft.AspNetCore.Components.Routing;
-#if NET6_0_OR_GREATER
// This is very similar to Microsoft.Extensions.Primitives.StringValues, except it works in terms
// of ReadOnlyMemory rather than string, so the querystring handling logic doesn't need to
// allocate per-value when tracking things that will be parsed as value types.
@@ -64,4 +63,3 @@ public void Add(ReadOnlyMemory value)
}
}
}
-#endif
diff --git a/src/BootstrapBlazor/Components/Tab/Route/TemplateSegment.cs b/src/BootstrapBlazor/Components/Tab/Route/TemplateSegment.cs
index b889439f530..93f2ab7a9f6 100644
--- a/src/BootstrapBlazor/Components/Tab/Route/TemplateSegment.cs
+++ b/src/BootstrapBlazor/Components/Tab/Route/TemplateSegment.cs
@@ -5,146 +5,6 @@
namespace Microsoft.AspNetCore.Components.Routing;
[ExcludeFromCodeCoverage]
-#if NET5_0
-internal class TemplateSegment
-{
- public TemplateSegment(string template, string segment, bool isParameter)
- {
- IsParameter = isParameter;
-
- IsCatchAll = isParameter && segment.StartsWith('*');
-
- if (IsCatchAll)
- {
- // Only one '*' currently allowed
- Value = segment[1..];
-
- var invalidCharacterIndex = Value.IndexOf('*');
- if (invalidCharacterIndex != -1)
- {
- throw new InvalidOperationException($"Invalid template '{template}'. A catch-all parameter may only have one '*' at the beginning of the segment.");
- }
- }
- else
- {
- Value = segment;
- }
-
- // Process segments that parameters that do not contain a token separating a type constraint.
- if (IsParameter)
- {
- if (Value.IndexOf(':') < 0)
- {
-
- // Set the IsOptional flag to true for segments that contain
- // a parameter with no type constraints but optionality set
- // via the '?' token.
- var questionMarkIndex = Value.IndexOf('?');
- if (questionMarkIndex == Value.Length - 1)
- {
- IsOptional = true;
- Value = Value[0..^1];
- }
- // If the `?` optional marker shows up in the segment but not at the very end,
- // then throw an error.
- else if (questionMarkIndex >= 0)
- {
- throw new ArgumentException($"Malformed parameter '{segment}' in route '{template}'. '?' character can only appear at the end of parameter name.");
- }
-
- Constraints = Array.Empty();
- }
- else
- {
- var tokens = Value.Split(':');
- if (tokens[0].Length == 0)
- {
- throw new ArgumentException($"Malformed parameter '{segment}' in route '{template}' has no name before the constraints list.");
- }
-
- Value = tokens[0];
- IsOptional = tokens[^1].EndsWith('?');
- if (IsOptional)
- {
- tokens[^1] = tokens[^1][0..^1];
- }
-
- Constraints = new RouteConstraint[tokens.Length - 1];
- for (var i = 1; i < tokens.Length; i++)
- {
- Constraints[i - 1] = RouteConstraint.Parse(template, segment, tokens[i]);
- }
- }
- }
- else
- {
- Constraints = Array.Empty();
- }
-
- if (IsParameter)
- {
- if (IsOptional && IsCatchAll)
- {
- throw new InvalidOperationException($"Invalid segment '{segment}' in route '{template}'. A catch-all parameter cannot be marked optional.");
- }
-
- // Moving the check for this here instead of TemplateParser so we can allow catch-all.
- // We checked for '*' up above specifically for catch-all segments, this one checks for all others
- if (Value.IndexOf('*') != -1)
- {
- throw new InvalidOperationException($"Invalid template '{template}'. The character '*' in parameter segment '{{{segment}}}' is not allowed.");
- }
- }
- }
-
- // The value of the segment. The exact text to match when is a literal.
- // The parameter name when its a segment
- public string Value { get; }
-
- public bool IsParameter { get; }
-
- public bool IsOptional { get; }
-
- public bool IsCatchAll { get; }
-
- public RouteConstraint[] Constraints { get; }
-
- public bool Match(string pathSegment, out object? matchedParameterValue)
- {
- if (IsParameter)
- {
- matchedParameterValue = pathSegment;
-
- foreach (var constraint in Constraints)
- {
- if (!constraint.Match(pathSegment, out matchedParameterValue))
- {
- return false;
- }
- }
-
- return true;
- }
- else
- {
- matchedParameterValue = null;
- return string.Equals(Value, pathSegment, StringComparison.OrdinalIgnoreCase);
- }
- }
-
- public override string ToString() => this switch
- {
- { IsParameter: true, IsOptional: false, IsCatchAll: false, Constraints: { Length: 0 } } => $"{{{Value}}}",
- { IsParameter: true, IsOptional: false, IsCatchAll: false, Constraints: { Length: > 0 } } => $"{{{Value}:{string.Join(':', Constraints.Select(c => c.ToString()))}}}",
- { IsParameter: true, IsOptional: true, Constraints: { Length: 0 } } => $"{{{Value}?}}",
- { IsParameter: true, IsOptional: true, Constraints: { Length: > 0 } } => $"{{{Value}:{string.Join(':', Constraints.Select(c => c.ToString()))}?}}",
- { IsParameter: true, IsCatchAll: true, Constraints: { Length: 0 } } => $"{{*{Value}}}",
- { IsParameter: true, IsCatchAll: true, Constraints: { Length: > 0 } } => $"{{*{Value}:{string.Join(':', Constraints.Select(c => c.ToString()))}?}}",
- { IsParameter: false } => Value,
- _ => throw new InvalidOperationException("Invalid template segment.")
- };
-}
-#else
internal class TemplateSegment
{
public TemplateSegment(string template, string segment, bool isParameter)
@@ -283,4 +143,3 @@ public bool Match(string pathSegment, out object? matchedParameterValue)
_ => throw new InvalidOperationException("Invalid template segment.")
};
}
-#endif
diff --git a/src/BootstrapBlazor/Components/Tab/Route/TypeRouteConstraint.cs b/src/BootstrapBlazor/Components/Tab/Route/TypeRouteConstraint.cs
deleted file mode 100644
index 3295a461c6f..00000000000
--- a/src/BootstrapBlazor/Components/Tab/Route/TypeRouteConstraint.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-// Website: https://www.blazor.zone or https://argozhang.github.io/
-
-namespace Microsoft.AspNetCore.Components.Routing;
-
-#if NET5_0
-///
-/// A route constraint that requires the value to be parseable as a specified type.
-///
-/// The type to which the value must be parseable.
-[ExcludeFromCodeCoverage]
-internal class TypeRouteConstraint : RouteConstraint
-{
- public delegate bool TryParseDelegate(string str, [MaybeNullWhen(false)] out T result);
-
- private readonly TryParseDelegate _parser;
-
- public TypeRouteConstraint(TryParseDelegate parser)
- {
- _parser = parser;
- }
-
- public override bool Match(string pathSegment, out object? convertedValue)
- {
- if (_parser(pathSegment, out var result))
- {
- convertedValue = result;
- return true;
- }
- else
- {
- convertedValue = null;
- return false;
- }
- }
-
- public override string ToString() => typeof(T) switch
- {
- var x when x == typeof(bool) => "bool",
- var x when x == typeof(DateTime) => "datetime",
- var x when x == typeof(decimal) => "decimal",
- var x when x == typeof(double) => "double",
- var x when x == typeof(float) => "float",
- var x when x == typeof(Guid) => "guid",
- var x when x == typeof(int) => "int",
- var x when x == typeof(long) => "long",
- var x => x.Name.ToLowerInvariant()
- };
-}
-#endif
diff --git a/src/BootstrapBlazor/Components/Tab/Route/UrlValueConstraint.cs b/src/BootstrapBlazor/Components/Tab/Route/UrlValueConstraint.cs
index c3f3ee164e3..5ed24420434 100644
--- a/src/BootstrapBlazor/Components/Tab/Route/UrlValueConstraint.cs
+++ b/src/BootstrapBlazor/Components/Tab/Route/UrlValueConstraint.cs
@@ -7,7 +7,6 @@
namespace Microsoft.AspNetCore.Components.Routing;
-#if NET6_0_OR_GREATER
///
/// Shared logic for parsing tokens from route values and querystring values.
///
@@ -183,4 +182,3 @@ bool TryParseNullable(ReadOnlySpan value, [MaybeNullWhen(false)] out T? re
}
}
}
-#endif