|
1 | | -using Microsoft.AspNetCore.Mvc; |
2 | | -using Microsoft.AspNetCore.Mvc.Abstractions; |
3 | 1 | using Microsoft.AspNetCore.Mvc.Infrastructure; |
4 | 2 | using System.Text.RegularExpressions; |
5 | 3 |
|
6 | 4 | namespace EssentialCSharp.Web.Services; |
7 | 5 |
|
8 | 6 | public class RouteConfigurationService : IRouteConfigurationService |
9 | 7 | { |
| 8 | + private static readonly Regex s_routeParameterRegex = |
| 9 | + new(@"\{[^}]+\}|\[[^\]]+\]", RegexOptions.Compiled); |
| 10 | + |
10 | 11 | private readonly IActionDescriptorCollectionProvider _ActionDescriptorCollectionProvider; |
11 | 12 | private readonly HashSet<string> _StaticRoutes; |
12 | 13 | private readonly HashSet<string> _IndexableRoutes; |
@@ -72,80 +73,11 @@ private HashSet<string> ExtractStaticRoutes() |
72 | 73 |
|
73 | 74 | private HashSet<string> ExtractIndexableRoutes() |
74 | 75 | { |
75 | | - var indexableRoutes = new HashSet<string>(StringComparer.OrdinalIgnoreCase); |
76 | | - |
77 | | - // Get all action descriptors |
78 | | - var actionDescriptors = _ActionDescriptorCollectionProvider.ActionDescriptors.Items; |
79 | | - |
80 | | - foreach (var actionDescriptor in actionDescriptors) |
81 | | - { |
82 | | - // Skip if controller is marked with [ApiController] |
83 | | - if (IsApiController(actionDescriptor)) |
84 | | - continue; |
85 | | - |
86 | | - // Look for route attributes |
87 | | - if (actionDescriptor.AttributeRouteInfo?.Template != null) |
88 | | - { |
89 | | - string template = actionDescriptor.AttributeRouteInfo.Template; |
90 | | - |
91 | | - // Skip routes with parameters (e.g., {chapter}, {id:guid}, [optional]) |
92 | | - if (ContainsRouteParameters(template)) |
93 | | - continue; |
94 | | - |
95 | | - // Skip routes starting with /api/ |
96 | | - if (template.StartsWith("/api/", StringComparison.OrdinalIgnoreCase)) |
97 | | - continue; |
98 | | - |
99 | | - // Remove leading slash and add to our set |
100 | | - string routePath = template.TrimStart('/').ToLowerInvariant(); |
101 | | - indexableRoutes.Add(routePath); |
102 | | - } |
103 | | - |
104 | | - // Skip the default fallback route (Index action in HomeController) |
105 | | - if (actionDescriptor.RouteValues.TryGetValue("action", out var action) && action == "Index") |
106 | | - continue; |
107 | | - |
108 | | - // Skip Error actions |
109 | | - if (action == "Error") |
110 | | - continue; |
111 | | - |
112 | | - // For actions without attribute routes, use conventional routing |
113 | | - if (actionDescriptor.AttributeRouteInfo?.Template == null && |
114 | | - actionDescriptor.RouteValues.TryGetValue("action", out var actionName) && |
115 | | - actionDescriptor.RouteValues.TryGetValue("controller", out var controllerName) && |
116 | | - controllerName?.Equals("Home", StringComparison.OrdinalIgnoreCase) == true && |
117 | | - actionName != null) |
118 | | - { |
119 | | - // Use the action name directly as the route |
120 | | - indexableRoutes.Add(actionName.ToLowerInvariant()); |
121 | | - } |
122 | | - } |
123 | | - |
124 | | - return indexableRoutes; |
125 | | - } |
126 | | - |
127 | | - private static bool IsApiController(ActionDescriptor actionDescriptor) |
128 | | - { |
129 | | - // Check for [ApiController] attribute |
130 | | - if (actionDescriptor.EndpointMetadata?.OfType<ApiControllerAttribute>().Any() == true) |
131 | | - return true; |
132 | | - |
133 | | - // Check if controller inherits from ControllerBase (not Controller) |
134 | | - if (actionDescriptor.RouteValues.TryGetValue("controller", out var controllerName)) |
135 | | - { |
136 | | - // Known API controllers |
137 | | - var apiControllers = new[] { "ListingSourceCode", "Chat", "McpToken", "MCP" }; |
138 | | - if (apiControllers.Contains(controllerName, StringComparer.OrdinalIgnoreCase)) |
139 | | - return true; |
140 | | - } |
141 | | - |
142 | | - return false; |
143 | | - } |
144 | | - |
145 | | - private static bool ContainsRouteParameters(string template) |
146 | | - { |
147 | | - // Match {param}, {param:constraint}, [optional], etc. |
148 | | - return Regex.IsMatch(template, @"\{[^}]+\}|\[[^\]]+\]"); |
| 76 | + return _StaticRoutes |
| 77 | + .Where(route => !route.StartsWith("api/", StringComparison.OrdinalIgnoreCase)) |
| 78 | + .Where(route => !s_routeParameterRegex.IsMatch(route)) |
| 79 | + .Where(route => !route.Contains("identity", StringComparison.OrdinalIgnoreCase)) |
| 80 | + .ToHashSet(StringComparer.OrdinalIgnoreCase); |
149 | 81 | } |
150 | 82 | } |
151 | 83 |
|
0 commit comments