Aspnetcore: Question: Where in the Blazor source code are URL parameters matched with Component properties?

Created on 10 May 2020  路  2Comments  路  Source: dotnet/aspnetcore

Hi!

I am interested in studying the point in the Blazor source where URL parameters are taken from their string representations and matched to a property of a component. For example, in a Razor page you might see:

@page "/students/{StudentId:int}"

And then further down you would find:

@code
{
    [Parameter]
    public int StudentId { get; set; }
}

For my education, I would like to study the portion of "under-the-hood" magic that takes the value from the URL and assigns it to the StudentId property.

Please could anybody who knows this codebase point me to the correct class or method?

Thanks for your advice!

Benjamin

Answered Resolved area-blazor question

Most helpful comment

Great question!

From the routing side of things, the magic starts in the TemplateParser class which interprets what the different components of a string route template are.

In particular, it takes a route like /students/{StudentId:int} and splits it by / to get each path-separated segment. Then parses each path segment to determine whether the segment is a static value (e.g. "students") or contains a parameter (e.g. "StudentId:int"). From this parsing, it produces a RouteTemplate object.

Each RouteTemplate object contains a set of TemplateSegment objects that match to each template. This TemplateSegment provides some information about whether or not the segment is related to a Parameter and exposes a Match function that takes in an input segment and checks to see if it matches the TemplateSegment. Note that this Match function also extracts parameter matches.

The Match function implemented in the TemplateSegment is invoked in the RouteEntry class. The TL;DR of this class is that it processes a given path, like /students/123 and finds the route that has the most number of matching templates segments. It also stores all the parameters used in the route in the RouteContext object.

So at this point, the parameters passed in the URL are loaded into the parameter object in the route context. It's used in the Route component which renders the route with a RouteData object that contains the parameter using the Found render fragment.

<Router AppAssembly=typeof(StandaloneApp.Program).Assembly>
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <LayoutView Layout="@typeof(MainLayout)">
            <h2>Not found</h2>
            Sorry, there's nothing at this address.
        </LayoutView>
    </NotFound>
</Router>

The example above shows a standard App component setup with the Found render fragment. Here, you can see that this is rendering a RouteView component.

The RouteView can render the page with the parameters mapped in as attributes. The RenderTreeBuilder provides an AddAttribute API for setting these properties.

Once the attributes are set, the ParameterView component provides functionality for extracting the parameters from the render tree. In particular, it contains a SetParameterProperties method that updates each of the parameters on the component to the values mapped by the ParameterView (which come from the RenderTree fragment which comes from the RouteView which is invoked in by the Route component).

The ComponentProperties processes the attributes in the component and updates their values accordingly.

TL;DR: The process of mapping a URL parameter to a component properties is supported by shared data structures like the RouteContext and various classes/methods that build the mapping from: string URL -> parsed route -> parameter object -> parameters injected into view -> parameters mapped to properties.

All 2 comments

Great question!

From the routing side of things, the magic starts in the TemplateParser class which interprets what the different components of a string route template are.

In particular, it takes a route like /students/{StudentId:int} and splits it by / to get each path-separated segment. Then parses each path segment to determine whether the segment is a static value (e.g. "students") or contains a parameter (e.g. "StudentId:int"). From this parsing, it produces a RouteTemplate object.

Each RouteTemplate object contains a set of TemplateSegment objects that match to each template. This TemplateSegment provides some information about whether or not the segment is related to a Parameter and exposes a Match function that takes in an input segment and checks to see if it matches the TemplateSegment. Note that this Match function also extracts parameter matches.

The Match function implemented in the TemplateSegment is invoked in the RouteEntry class. The TL;DR of this class is that it processes a given path, like /students/123 and finds the route that has the most number of matching templates segments. It also stores all the parameters used in the route in the RouteContext object.

So at this point, the parameters passed in the URL are loaded into the parameter object in the route context. It's used in the Route component which renders the route with a RouteData object that contains the parameter using the Found render fragment.

<Router AppAssembly=typeof(StandaloneApp.Program).Assembly>
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <LayoutView Layout="@typeof(MainLayout)">
            <h2>Not found</h2>
            Sorry, there's nothing at this address.
        </LayoutView>
    </NotFound>
</Router>

The example above shows a standard App component setup with the Found render fragment. Here, you can see that this is rendering a RouteView component.

The RouteView can render the page with the parameters mapped in as attributes. The RenderTreeBuilder provides an AddAttribute API for setting these properties.

Once the attributes are set, the ParameterView component provides functionality for extracting the parameters from the render tree. In particular, it contains a SetParameterProperties method that updates each of the parameters on the component to the values mapped by the ParameterView (which come from the RenderTree fragment which comes from the RouteView which is invoked in by the Route component).

The ComponentProperties processes the attributes in the component and updates their values accordingly.

TL;DR: The process of mapping a URL parameter to a component properties is supported by shared data structures like the RouteContext and various classes/methods that build the mapping from: string URL -> parsed route -> parameter object -> parameters injected into view -> parameters mapped to properties.

Thank you very much for this detailed answer and relevant links! A lot to get my head around but should be much easier after your explanation.

Was this page helpful?
0 / 5 - 0 ratings