Skip to content

Conversation

@pranavkm
Copy link
Contributor

Contributes to #5680

@ghost ghost added the area-blazor Includes: Blazor, Razor Components label Jun 21, 2020
@pranavkm pranavkm changed the title Annotate Components.Forms \ Components.Web with nullable attributes Annotate Components.Forms \ Components.Web \ Component.Server with nullable attributes Jun 21, 2020
@pranavkm pranavkm marked this pull request as ready for review June 22, 2020 15:06
@pranavkm pranavkm force-pushed the prkrishn/nullable-components-forms branch from a28f1a8 to 454ff06 Compare June 22, 2020 15:13
@pranavkm pranavkm requested a review from a team June 22, 2020 15:13
break;
if (constantExpression.Value is null)
{
throw new ArgumentException("The provided expression must evaluate to a non-null value.");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the implementation a bit here. Creating a FieldIdentifier with a null value will results in an argument null exception. This provides a slightly better error experience.

<DefineConstants>$(DefineConstants);ENABLE_UNSAFE_MSGPACK;SPAN_BUILTIN;MESSAGEPACK_INTERNAL;COMPONENTS_SERVER</DefineConstants>
<IsPackable>false</IsPackable>
<EmbeddedFilesManifestFileName>Microsoft.Extensions.FileProviders.Embedded.Manifest.xml</EmbeddedFilesManifestFileName>
<Nullable>annotations</Nullable>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The vast majority of the server's code is internal implementation types and I don't want to spend time fixing that up at this point. Consequently it only has annotations on, which means you get nullability hints, but the code is not checked for correctness.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this means the compiler doesn't do the check within the library but that we "trust" the annotations?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup. The API surface is annotated, but the implementation isn't null-checked. I want to do a follow up on these things, but it'd be useful to get the user API in first.

if (configure == null)
{
builder.Services.Configure<HubOptions<ComponentHub>>(configure);
throw new ArgumentNullException(nameof(configure));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This matches the behavior of AddCircuitOptions. Seems very strange to call this and not have it do anything by passing in a null.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this follows a specific pattern, I believe we do it this way across all asp.net core. I would suggest we keep it as is for consistency.

@pranavkm pranavkm force-pushed the prkrishn/nullable-components-forms branch from 454ff06 to 0763580 Compare June 22, 2020 19:07
/// An optional format to use when converting values.
/// </param>
public BindInputElementAttribute(string type, string suffix, string valueAttribute, string changeAttribute, bool isInvariantCulture, string format)
public BindInputElementAttribute(string? type, string? suffix, string? valueAttribute, string? changeAttribute, bool isInvariantCulture, string? format)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does it mean for the type to be null? Isn't type required? Or does it default to "text"?

In cases like these, we should consider applying defaults to the properties when we receive null-values and avoid having the code that uses these things from having to deal with null values.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[BindInputElement(null, null, "value", "onchange", isInvariantCulture: false, format: null)]

[AllowNull]
[MaybeNull]
[Parameter]
public TValue Value { get; set; } = default;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it because TValue is a generic parameter that we can't do something like TValue? Value?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you can only apply nullable to generics if you define them to be either reference or value types. Opaque types, not so much. This says even if you declare an InputText<string> the value could be null, either because it was initialized as such or the value being assigned to it cannot be guaranteed to be non-null.

/// </summary>
[Parameter(CaptureUnmatchedValues = true)]
public IReadOnlyDictionary<string, object> AdditionalAttributes { get; set; }
public IReadOnlyDictionary<string, object?>? AdditionalAttributes { get; set; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we use this annotation on all AdditionalAttributes parameters? I think I've seen one that is different, but I can't find it now. Just double check that these are consistent across different components.

Does the current annotation mean that the dictionary and its contents can be both null? (So you have a valid entry with a null value) What's the scenario for that last case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we use this annotation on all AdditionalAttributes parameters?

Yup, the compiler should complain if we missed some.

Does the current annotation mean that the dictionary and its contents can be both null? (So you have a valid entry with a null value) What's the scenario for that last case?

I went back and checked, and I don't think there's a scenario for the values inside the dictionary being null. I can change that. The dictionary itself would be null.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I see what happened here. RenderTreeBuilder allows null-valued attributes here: https://github.com/dotnet/aspnetcore/blob/master/src/Components/Components/src/Rendering/RenderTreeBuilder.cs#L329-L333. Making https://github.com/dotnet/aspnetcore/blob/master/src/Components/Components/src/Rendering/RenderTreeBuilder.cs#L405 allow nullable attributes prevents these properties from having a non-nullable value.

It's a bit of a compromise, but we'll declare AddMultipleAttributes to accept non-null values. ComponentProperties already produces a non-null valued dictionary, so we should be good.

Copy link
Member

@javiercn javiercn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, left a couple of questions, but it's good to go once we clarify things.

@pranavkm pranavkm force-pushed the prkrishn/nullable-components-forms branch from 0763580 to 625ef7c Compare June 25, 2020 16:03
@pranavkm pranavkm requested a review from a team June 25, 2020 16:07
@ghost
Copy link

ghost commented Jun 25, 2020

Hello @pranavkm!

Because this pull request has the auto-merge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

@pranavkm pranavkm added this to the 5.0.0-preview8 milestone Jun 25, 2020
@ghost ghost merged commit c42d1a3 into master Jun 25, 2020
@ghost ghost deleted the prkrishn/nullable-components-forms branch June 25, 2020 17:36
pranavkm added a commit that referenced this pull request Jun 25, 2020
…llable attributes (#23204)

* Annotate Components.Forms \ Components.Web with nullable attributes
Contributes to #5680

* Fixup

* Fixup rebase

* Undo nullable

* Fixup
mkArtakMSFT pushed a commit that referenced this pull request Jun 25, 2020
…llable attributes (#23204) (#23355)

* Annotate Components.Forms \ Components.Web with nullable attributes
Contributes to #5680

* Fixup

* Fixup rebase

* Undo nullable

* Fixup
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-blazor Includes: Blazor, Razor Components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants