API Proposal RoutingStateProvider; RouteData breaking change
See original GitHub issueBackground and Motivation
As part of Blazor United we want to make Static, Server, and Webassembly app models similar to each other. As part of that, Blazor United will always render the root component you specify in MapRazorComponents<App>()
. Your App
component needs to have a Router
component to ensure the appropriate page is rendered.
For static rendering we want to add a scoped service RoutingStateProvider
that holds RouteData
from httpContext. With this RouteData
we already know what page to render. This way we will avoid routing twice in Router
component. The Router
component will check RouteData
to render the appropriate page.
namespace Microsoft.AspNetCore.Components.Routing;
public class RoutingStateProvider
{
public virtual RouteData? RouteData { get; }
}
We also want to change RouteData.
public sealed class RouteData
{
- public RouteData([DynamicallyAccessedMembers(Component)] Type pageType, IReadOnlyDictionary<string, object> routeValues) {}
+ public RouteData([DynamicallyAccessedMembers(Component)] Type pageType, IReadOnlyDictionary<string, object?> routeValues) {}
[DynamicallyAccessedMembers(Component)]
public Type PageType { get; }
- public IReadOnlyDictionary<string, object> RouteValues { get; }
+ public IReadOnlyDictionary<string, object?> RouteValues { get; }
}
The reason for this is when creating RouteData
for routeValues
parameter we provide httpContext.GetRouteData().Values
of type RouteValueDictionary : IReadOnlyDictionary<string, object?>
. There is CS8620.
Proposed API
namespace Microsoft.AspNetCore.Components.Routing;
public class RoutingStateProvider
{
public virtual RouteData? RouteData { get; }
}
public sealed class RouteData
{
- public RouteData([DynamicallyAccessedMembers(Component)] Type pageType, IReadOnlyDictionary<string, object> routeValues) {}
+ public RouteData([DynamicallyAccessedMembers(Component)] Type pageType, IReadOnlyDictionary<string, object?> routeValues) {}
[DynamicallyAccessedMembers(Component)]
public Type PageType { get; }
- public IReadOnlyDictionary<string, object> RouteValues { get; }
+ public IReadOnlyDictionary<string, object?> RouteValues { get; }
}
Usage Examples
Router
component will check if RoutingStateProvider
RouteData
is not null and render the page. If it is null then it will work as usual (try to match current url to a page and then render that page).
if (RoutingStateProvider.RouteData != null)
{
_renderHandle.Render(Found(RoutingStateProvider.RouteData));
return;
}
RouteData
new RouteData(componentType, httpContext.GetRouteData().Values)
Alternative Designs
Suppress CS8620.
Risks
Issue Analytics
- State:
- Created 5 months ago
- Comments:8 (8 by maintainers)
API Review Notes for
RootComponentMetadata
(we already approved the rest of the proposal):MapRazorComponents<TRootComponent>()
whereRootComponentMetata.Type
istypeof(TRootComponent)
.httpContext.GetEndpoint().Metadata.GetMetadata<RootComponentMetata>()
.Microsoft.AspNetCore.Builder
namespace?ComponentTypeMetadata
, but that’s also new in .NET 8 and can be moved.Microsoft.AspNetCore.Components.Endpoints
. It’s a new dll, but the namespace has already been used for some stuff: https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.endpoints?view=aspnetcore-8.0API Approved! Make sure we update the namespace for both
RootComponentMetadata
andRootComponentMetadata
.Reopening for API review.
Thanks for the updated proposal. Can you update the latest comment to show
interface IRoutingStateProvider
instead ofclass RoutingStateProvider
? It looks like there was a copy-paste issue.Can you also provide usage examples for
RootComponentMetadata
since that’s new?I also wonder if we should put
RootComponentMetadata
in theMicrosoft.AspNetCore.Components.Endpoints
rather than theMicrosoft.AspNetCore.Builder
namespace.Microsoft.AspNetCore.Builder
is consistent withComponentTypeMetadata
, but I’m not sure this type will be commonly used enough to warrant including in a namespace that’s a default global using.