|
9 | 9 | namespace Microsoft.AspNetCore.Components.Routing; |
10 | 10 |
|
11 | 11 | [ExcludeFromCodeCoverage] |
12 | | -#if NET5_0 |
13 | | -[DebuggerDisplay("Handler = {Handler}, Template = {Template}")] |
14 | | -internal class RouteEntry |
15 | | -{ |
16 | | - public RouteEntry(RouteTemplate template, Type handler, string[] unusedRouteParameterNames) |
17 | | - { |
18 | | - Template = template; |
19 | | - UnusedRouteParameterNames = unusedRouteParameterNames; |
20 | | - Handler = handler; |
21 | | - } |
22 | | - |
23 | | - public RouteTemplate Template { get; } |
24 | | - |
25 | | - public string[] UnusedRouteParameterNames { get; } |
26 | | - |
27 | | - public Type Handler { get; } |
28 | | - |
29 | | - internal void Match(RouteContext context) |
30 | | - { |
31 | | - var pathIndex = 0; |
32 | | - var templateIndex = 0; |
33 | | - Dictionary<string, object> parameters = null; |
34 | | - // We will iterate over the path segments and the template segments until we have consumed |
35 | | - // one of them. |
36 | | - // There are three cases we need to account here for: |
37 | | - // * Path is shorter than template -> |
38 | | - // * This can match only if we have t-p optional parameters at the end. |
39 | | - // * Path and template have the same number of segments |
40 | | - // * This can happen when the catch-all segment matches 1 segment |
41 | | - // * This can happen when an optional parameter has been specified. |
42 | | - // * This can happen when the route only contains literals and parameters. |
43 | | - // * Path is longer than template -> This can only match if the parameter has a catch-all at the end. |
44 | | - // * We still need to iterate over all the path segments if the catch-all is constrained. |
45 | | - // * We still need to iterate over all the template/path segments before the catch-all |
46 | | - while (pathIndex < context.Segments.Length && templateIndex < Template.Segments.Length) |
47 | | - { |
48 | | - var pathSegment = context.Segments[pathIndex]; |
49 | | - var templateSegment = Template.Segments[templateIndex]; |
50 | | - |
51 | | - var matches = templateSegment.Match(pathSegment, out var match); |
52 | | - if (!matches) |
53 | | - { |
54 | | - // A constraint or literal didn't match |
55 | | - return; |
56 | | - } |
57 | | - |
58 | | - if (!templateSegment.IsCatchAll) |
59 | | - { |
60 | | - // We were dealing with a literal or a parameter, so just advance both cursors. |
61 | | - pathIndex++; |
62 | | - templateIndex++; |
63 | | - |
64 | | - if (templateSegment.IsParameter) |
65 | | - { |
66 | | - parameters ??= new(StringComparer.OrdinalIgnoreCase); |
67 | | - parameters[templateSegment.Value] = match; |
68 | | - } |
69 | | - } |
70 | | - else |
71 | | - { |
72 | | - if (templateSegment.Constraints.Length == 0) |
73 | | - { |
74 | | - |
75 | | - // Unconstrained catch all, we can stop early |
76 | | - parameters ??= new(StringComparer.OrdinalIgnoreCase); |
77 | | - parameters[templateSegment.Value] = string.Join('/', context.Segments, pathIndex, context.Segments.Length - pathIndex); |
78 | | - |
79 | | - // Mark the remaining segments as consumed. |
80 | | - pathIndex = context.Segments.Length; |
81 | | - |
82 | | - // Catch-alls are always last. |
83 | | - templateIndex++; |
84 | | - |
85 | | - // We are done, so break out of the loop. |
86 | | - break; |
87 | | - } |
88 | | - else |
89 | | - { |
90 | | - // For constrained catch-alls, we advance the path index but keep the template index on the catch-all. |
91 | | - pathIndex++; |
92 | | - if (pathIndex == context.Segments.Length) |
93 | | - { |
94 | | - parameters ??= new(StringComparer.OrdinalIgnoreCase); |
95 | | - parameters[templateSegment.Value] = string.Join('/', context.Segments, templateIndex, context.Segments.Length - templateIndex); |
96 | | - |
97 | | - // This is important to signal that we consumed the entire template. |
98 | | - templateIndex++; |
99 | | - } |
100 | | - } |
101 | | - } |
102 | | - } |
103 | | - |
104 | | - var hasRemainingOptionalSegments = templateIndex < Template.Segments.Length && |
105 | | - RemainingSegmentsAreOptional(pathIndex, Template.Segments); |
106 | | - |
107 | | - if ((pathIndex == context.Segments.Length && templateIndex == Template.Segments.Length) || hasRemainingOptionalSegments) |
108 | | - { |
109 | | - if (hasRemainingOptionalSegments) |
110 | | - { |
111 | | - parameters ??= new Dictionary<string, object>(StringComparer.Ordinal); |
112 | | - AddDefaultValues(parameters, templateIndex, Template.Segments); |
113 | | - } |
114 | | - if (UnusedRouteParameterNames?.Length > 0) |
115 | | - { |
116 | | - parameters ??= new Dictionary<string, object>(StringComparer.Ordinal); |
117 | | - for (var i = 0; i < UnusedRouteParameterNames.Length; i++) |
118 | | - { |
119 | | - parameters[UnusedRouteParameterNames[i]] = null; |
120 | | - } |
121 | | - } |
122 | | - context.Handler = Handler; |
123 | | - context.Parameters = parameters; |
124 | | - } |
125 | | - } |
126 | | - |
127 | | - private void AddDefaultValues(Dictionary<string, object> parameters, int templateIndex, TemplateSegment[] segments) |
128 | | - { |
129 | | - for (var i = templateIndex; i < segments.Length; i++) |
130 | | - { |
131 | | - var currentSegment = segments[i]; |
132 | | - parameters[currentSegment.Value] = null; |
133 | | - } |
134 | | - } |
135 | | - |
136 | | - private bool RemainingSegmentsAreOptional(int index, TemplateSegment[] segments) |
137 | | - { |
138 | | - for (var i = index; index < segments.Length - 1; index++) |
139 | | - { |
140 | | - if (!segments[i].IsOptional) |
141 | | - { |
142 | | - return false; |
143 | | - } |
144 | | - } |
145 | | - |
146 | | - return segments[^1].IsOptional || segments[^1].IsCatchAll; |
147 | | - } |
148 | | -} |
149 | | -#else |
150 | 12 | [DebuggerDisplay("Handler = {Handler}, Template = {Template}")] |
151 | 13 | internal class RouteEntry |
152 | 14 | { |
@@ -284,4 +146,5 @@ private bool RemainingSegmentsAreOptional(int index, TemplateSegment[] segments) |
284 | 146 | return segments[^1].IsOptional || segments[^1].IsCatchAll; |
285 | 147 | } |
286 | 148 | } |
287 | | -#endif |
| 149 | + |
| 150 | +#nullable restore warnings |
0 commit comments