aspnetcore icon indicating copy to clipboard operation
aspnetcore copied to clipboard

Blazor Value cannot be null. (Parameter 'obj')

Open omuleanu opened this issue 2 years ago • 3 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Describe the bug

when calling EditContext.NotifyFieldChanged(FieldIdentifier); with a FieldIdentifier that has .FieldName == null (because the custom component is not declared using @bind ) we'll get this not very useful error message:

Value cannot be null. (Parameter 'obj')`

Expected Behavior

a better error message

Steps To Reproduce

No response

Exceptions (if any)

No response

.NET Version

6

Anything else?

No response

omuleanu avatar Nov 14 '22 22:11 omuleanu

Thanks for contacting us.

We're moving this issue to the .NET 8 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 avatar Nov 15 '22 17:11 ghost

This is caused by this line https://github.com/dotnet/aspnetcore/blob/ea529f4756841fdf8d7cee5b3c188210520c1323/src/Components/Forms/src/FieldIdentifier.cs#L70

I don't really know how can we create a test case for this one, the struct is read-only, so any advice on how can I create a test case for it?

I can edit the HashCode method to check for nulls, but I'm not sure if the scenarios where the field name is null are possible.

tmricardo7 avatar Nov 24 '22 18:11 tmricardo7

here's a test case, (can't get it to fail in BlazorFiddle, but fails on my local, .net 7)

@page "/page1"
<EditForm  Model="model1"> 
        <Editor1 Value="val1" />
</EditForm>
@code {    
    private int? val1;
    Model1 model1 = new Model1();    
    class Model1{}
}

Editor1:

@using Microsoft.AspNetCore.Components.Forms;
@using System.Linq.Expressions;
@value

@code {
    private int? value;

    [Parameter]
    public int? Value
    {
        set
        {
            this.value = value;
        }
    }

    [Parameter]
    public EventCallback<int?> ValueChanged { get; set; }

    protected async override Task OnInitializedAsync()
    {
        if (value is null)
        {            
            value = 1;
            await ValueChanged.InvokeAsync(1);
            FieldChanged();
        }
    }

    [Parameter] public Expression<Func<int?>> ValueExpression { get; set; }

    [Parameter] public string DisplayName { get; set; }

    protected EditContext EditContext { get; set; } = default!;

    [CascadingParameter] EditContext CascadedEditContext { get; set; } = default!;

    /// <summary>
    /// Gets the <see cref="FieldIdentifier"/> for the bound value.
    /// </summary>
    protected internal FieldIdentifier FieldIdentifier { get; set; }

    /// <inheritdoc />
    public override Task SetParametersAsync(ParameterView parameters)
    {
        parameters.SetParameterProperties(this);

        if (EditContext == null)
        {
            // This is the first run
            // Could put this logic in OnInit, but its nice to avoid forcing people who override OnInit to call base.OnInit()

            if (CascadedEditContext != null)
            {
                EditContext = CascadedEditContext;
            }

            if (ValueExpression != null)
            {
                FieldIdentifier = FieldIdentifier.Create(ValueExpression);
            }
        }
        else if (CascadedEditContext != EditContext)
        {         
            throw new InvalidOperationException($"{GetType()} does not support changing the " +
                                                $"{nameof(EditContext)} dynamically.");
        }

        // For derived components, retain the usual lifecycle with OnInit/OnParametersSet/etc.
        return base.SetParametersAsync(ParameterView.Empty);
    }

    protected void FieldChanged()
    {
        EditContext?.NotifyFieldChanged(FieldIdentifier);
    }
}

omuleanu avatar Nov 24 '22 21:11 omuleanu

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 avatar Oct 06 '23 17:10 ghost

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

ghost avatar Dec 22 '23 03:12 ghost