Skip to content

[Blazor] Removing automatic backing field support for @ref in 3.0.0-preview9 #381

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
NTaylorMullen opened this issue Aug 14, 2019 · 0 comments
Labels
3.0.0 Announcements related to ASP.NET Core 3.0 Announcement

Comments

@NTaylorMullen
Copy link

NTaylorMullen commented Aug 14, 2019

What's happening

In ASP.NET Core 3.0 Preview 8 release we added a productivity feature in Blazor to automatically generate backing fields for elements that utilized the @ref attribute. Unfortunately, we missed a critical design flaw which prevents this from working end-to-end.

Trying to invoke build on a project with a Counter component that looked like the following would result in a build error:

<Counter @ref="myCounter" />

@code {
    // This will not compile because there will be no backing field for myCounter
    private readonly int _incrementingBy = myCounter.IncrementAmount;
}

Given that we're so close to a 3.0 release, we are going to cut this feature from 3.0. We will think about viable solutions to this in future releases, if we can find one, we may consider it then.

The problem deep dive

To summarize the problem effectively, I need to describe how the Razor compilation process works. It's a two-phase process:

  1. Discovery: All the components and directive attributes are discovered. Razor does this by generating a skeleton of each component file and then introspecting on their structure, we call these files declarations. Basically, any content in your Razor file that isn't a directive or inside of a directive block @code is thrown out to avoid compilation errors during this phase.
  2. Compiling: The actual Razor file compilation where it uses the inputs resolved in phase 1. This phase utilizes all of discovered components to properly parse HTML elements that look like components and uses all of the discovered directive attributes to properly parse those elements corresponding attributes that look like directive attributes.

The process is broken into two phases to enable Components to be written in Razor yet also impact other Razor files in the project. This is why you can write a Counter.razor file and still recursively use it in the same Counter.razor file.

The core problem is that during the discovery phase the Razor compiler has no awareness of the available components or directive attributes (it hasn't discovered them yet). This means, the @ref attribute and other component's existence is not available in this phase. This introduces a problem because a user may have written code in their @code block that references the supposed backing field generated from @ref; however, during discovery we didn't know about @ref so no backing field was generated. This results in Razor skeleton file that can't be compiled or introspected on (C# errors). We considered working around this limitation by hard coding @ref to not require the first phase but quickly found that would not work either because if a user writes <Counter @ref="myCounter" /> We need to generate a proper type name for the auto-generated backing field (private Counter myCounter;) which isn't reliably available because during the discovery phase we haven't yet discovered anything (it's not till phase 2 that we know of Counter).

Workaround

In 3.0.0-preview8 in order to utilize the @ref attribute you must do:

<button @ref="myButton" @ref:suppressField />
@code {
    ElementReference myButton;
}

Once 3.0.0-preview9 and up ships you will be able to use the older syntax such as:

<button @ref="myButton" />
@code {
    ElementReference myButton;
}
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
3.0.0 Announcements related to ASP.NET Core 3.0 Announcement
Projects
None yet
Development

No branches or pull requests

1 participant