dotnet / dotnet/aspnetcore

[Blazor] Guarantee that interactive root component parameter updates originate from the correct source

Open
#51,073 2 comments 0 reactions 0 assignees View on GitHub
area-blazor enhancement Pillar: Complete Blazor Web Priority:2
Dominant language
C#
Stars
38.5k
Forks
11.5k
Avg merge
2d 7h
Merged PRs (30d)
275

Description

## Description

Starting in .NET 8, Blazor components can be rendered statically from a Blazor endpoint. If a component has an interactive render mode specified, it emits an HTML comment with a payload (we call this a "marker") that can be used by an interactive runtime to either:
* Instantiate a new interactive root component, or...
* Update the parameters of an existing interactive root component.

Since Blazor endpoints don't have any knowledge of what the existing DOM structure is (or if one even exists at all), it's up to the client to determine whether a component marker matches up with an existing interactive component. This means that a client has the power to supply the parameters from a component marker to a potentially unrelated existing interactive component.

To prevent this from happening, a "key" gets generated and included in the marker payload to deterministically identify component instances by their location on the page. In the case of Blazor Server, this key also gets data-protected and round-tripped back to the server to verify that a parameter update only applies to a component previously rendered with a matching key. Currently, the key's format consists of:
* The hashed component type
* The component's render tree sequence number
* An optional, developer-specified component key (the value of the `@key` attribute)

Ignoring the `@key` attribute (since it's optional), the first two parts of the marker key are typically enough to uniquely identify a component among its siblings, but not technically enough to distinguish it between components in other branches of the component hierarchy. While it's unlikely to happen, this means that interactive components rendered from a Blazor endpoint could be incorrectly matched with existing interactive components in other branches of the component hierarchy.

However, this fact alone isn't enough for components to receive parameter updates from an unrelated component. Blazor also has a rule where, if an interactive root component's parameters change via Blazor endpoint render, the existing interactive component instance must get disposed and a new one should get initialized in its place with the updated set of parameters. The exception to this rule is that if a component has a non-empty `@key` attribute value, it gets opted-into having its parameters updated dynamically. So, in order for an interactive root component to receive parameters from an unrelated component:
* Both components must have the same component type
* Both components must have the same render tree sequence number
* Both components must have _explicitly_ opted into dynamic parameter changes via a matching `@key` attribute
* Assuming a well-behaved client, both components must get rendered at the same depth in the DOM hierarchy

Despite this problem being unlikely to manifest in the wild, it would be more correct to include information about the component's complete hierarchy in the auto-generated part of the marker key.

## Potential solution

We could address this by incrementally computing a hash for each ancestor to a component with an interactive render mode. Each ancestor component contributes its own component type and sequence number to the incremental hash. We would also have a cache to ensure that we don't have to re-compute parts of the incremental hash that have already been computed for common ancestors.

This change would effectively eliminate the edge case described above by guaranteeing that interactive root components may only receive parameter updates if the marker was rendered by a component in a structurally identical position, even if all the other aforementioned criteria for the edge case are met.

Contributor guide

Open the contributing guide

Research direction

Start by tracing the interactive root component marker key generation and the server-side validation described in the issue. Review how component type and sequence numbers are currently incorporated, then determine how ancestor information and shared-prefix caching should be represented; done means parameter updates are accepted only for structurally identical component hierarchies.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
full-stack
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.