diff --git a/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs b/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs index 4d95f68c0fc5..953c8a941358 100644 --- a/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs +++ b/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs @@ -135,7 +135,13 @@ internal async Task InitializeStandardComponentServicesAsync( routingStateProvider.RouteData = new RouteData(componentType, httpContext.GetRouteData().Values); if (httpContext.GetEndpoint() is RouteEndpoint routeEndpoint) { - routingStateProvider.RouteData.Template = routeEndpoint.RoutePattern.RawText; + // Verify that the endpoint route pattern matches the current component's route attributes + // to prevent stale route data during hot reload scenarios + if (IsValidRouteTemplateForComponent(componentType, routeEndpoint.RoutePattern.RawText)) + { + routingStateProvider.RouteData.Template = routeEndpoint.RoutePattern.RawText; + } + // If template doesn't match, leave Template as null to force normal routing } } } @@ -253,6 +259,29 @@ private static string GetContextBaseUri(HttpRequest request) return result.EndsWith('/') ? result : result += "/"; } + private static bool IsValidRouteTemplateForComponent(Type componentType, string? routeTemplate) + { + // If route template is null or empty, it's not valid + if (string.IsNullOrEmpty(routeTemplate)) + { + return false; + } + + // Get the current route attributes from the component type + var routeAttributes = componentType.GetCustomAttributes(typeof(RouteAttribute), inherit: false); + + // Check if the endpoint's route template matches any of the component's current route attributes + foreach (RouteAttribute attribute in routeAttributes) + { + if (string.Equals(attribute.Template, routeTemplate, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + + return false; + } + private sealed class FormCollectionReadOnlyDictionary : IReadOnlyDictionary { private readonly IFormCollection _form;