Skip to content

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

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    Pillar: Complete Blazor WebPriority:2Work that is important, but not critical for the releasearea-blazorIncludes: Blazor, Razor ComponentsenhancementThis issue represents an ask for new feature or an enhancement to an existing one

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions