dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.33k stars 9.97k forks source link

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

Open MackinnonBuck opened 1 year ago

MackinnonBuck commented 1 year ago

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:

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:

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:

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.

ghost commented 1 year ago

Thanks for contacting us.

We're moving this issue to the .NET 9 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s). If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

ghost commented 9 months ago

Thanks for contacting us.

We're moving this issue to the .NET 9 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s). If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.