Blazor SSR Component changes subtypes of Model type when rendering page

49 views Asked by At

My application is typical Warehouse app. Simple one. It is coded in Fluent Blazor Web App template (.Net 8), Interactivity: Server, Render mode: Global.

It looks like there is something wrong with my component (code at bottom). It seems it replaces names of subtypes of my Model class with value of its Id.

On first screenshot just when assigning Model/Content to EditContext everything looks ok. Currency has its name, PartVm, StateVm and Warehouse also.

enter image description here

A miliseconds later just after the components page has rendered it looks completely different. Name properities of my subtypes have values of theirs corresponding Ids.

enter image description here

This is code of my component:

@* AssetVm Edit Component *@
@inject IMediator _mediator
@implements IDialogContentComponent<AssetVm>

@* Header *@
<FluentDialogHeader ShowDismiss="true">
    <FluentStack VerticalAlignment="VerticalAlignment.Center">
        <FluentIcon Value="@(new Icons.Regular.Size24.WindowApps())" />
        <FluentLabel Typo="Typography.PaneHeader">
            @Dialog.Instance.Parameters.Title
        </FluentLabel>
    </FluentStack>
</FluentDialogHeader>
@* Footer *@
<FluentDialogFooter>
    <FluentButton Appearance="Appearance.Accent" OnClick="@SaveAsync"
                  Disabled="@(!_editContext.Validate())">
        Save
    </FluentButton>
    <FluentButton Appearance="Appearance.Neutral" OnClick="@CancelAsync">Cancel</FluentButton>
</FluentDialogFooter>
@* Body *@
<FluentDialogBody Orientation="Orientation.Horizontal">
    <EditForm EditContext="_editContext">
        <FluentValidationValidator @ref="_fluentValidator" />

        <FluentGrid Justify="@Justification">
            @* AssetTagNumber *@
            <FluentGridItem xs="6" sm="4">
                <div class="card">

                    <FluentTextField Id="AssetTagNumber" @bind-Value="@Content.AssetTagNumber"
                                     Disabled = "@editmode"
                                     Placeholder="AssetTagNumber"> AssetTagNumber: </FluentTextField>
                    <FluentValidationMessage For="@(() => Content.AssetTagNumber)" />

                </div>
            </FluentGridItem>
            @* Serial Number *@
            <FluentGridItem xs="6" sm="4">
                <div class="card">
                    <FluentTextField Id="SerialNumber" @bind-Value="@Content.SerialNumber"
                                     Disabled="@editmode" 
                                     Placeholder="Enter last name"> SerialNumber: </FluentTextField>
                    <FluentValidationMessage For="@(() => Content.SerialNumber)" />
                </div>
            </FluentGridItem>
            @* Part *@
            <FluentGridItem xs="6" sm="4">
                <div class="card">
                    @{
                        <FluentSelect TOption="PartVm"
                                      Label="Select part:"
                                      Items="@itemPartsList"
                                      Id="PartId"
                                      Width="150px"
                                      Height="250px"
                                      OptionValue="@(p => p.Id.ToString())"
                                      OptionText="@(p => p.Name)"
                                      @bind-Value="@Content.PartVm.Name"
                                      @bind-SelectedOption="@Content.PartVm" />
                    }
                    <FluentValidationMessage For="@(() => Content.PartVm)" />
                </div>
            </FluentGridItem>
            @* State *@
            <FluentGridItem xs="6" sm="4">
                <div class="card">
                    @{
                        <FluentSelect TOption="StateVm"
                                      Label="Select state:"
                                      Items="@itemStatesList"
                                      Id="StateId"
                                      Width="150px"
                                      Height="250px"
                                      OptionValue="@(p => p.Id.ToString())"
                                      OptionText="@(p => p.Name)"
                                      @bind-Value="@Content.StateVm.Name"
                                      @bind-SelectedOption="@Content.StateVm" />
                    }

                    <FluentValidationMessage For="@(() => Content.StateVm)" />
                </div>
            </FluentGridItem>
            @* Employee *@
            <FluentGridItem xs="6" sm="4">
                <div class="card">
                    @{
                        <FluentSelect TOption="EmployeeVm"
                                      Label="Select employee:"
                                      Items="@itemEmployeesList"
                                      Id="EmployeeId"
                                      Width="150px"
                                      Height="250px"
                                      OptionValue="@(p => p.Id.ToString())"
                                      OptionText="@(p => p.LongName)"
                                      @bind-Value="@Content.EmployeeVm.LongName"
                                      @bind-SelectedOption="@Content.EmployeeVm" />
                    }

                    <FluentValidationMessage For="@(() => Content.EmployeeVm)" />
                </div>
            </FluentGridItem>
            @* Warehouse *@
            <FluentGridItem xs="6" sm="4">
                <div class="card">
                    @{
                        <FluentSelect TOption="WarehouseVm"
                                      Label="Select warehouse:"
                                      Items="@itemWarehousesList"
                                      Id="WareHId"
                                      Width="150px"
                                      Height="250px"
                                      OptionValue="@(p => p.Id.ToString())"
                                      OptionText="@(p => p.Name)"
                                      @bind-Value="@Content.WarehouseVm.Name"
                                      @bind-SelectedOption="@Content.WarehouseVm" />
                    }

                    <FluentValidationMessage For="@(() => Content.WarehouseVm)" />
                </div>
            </FluentGridItem>
            @* Price *@
            <FluentGridItem xs="6" sm="4">
                <div class="card">
                    <FluentNumberField Id="Price" @bind-Value="@Content.Price" Disabled="@editmode" Placeholder="Price..."> Price: </FluentNumberField>
                    
                </div>
            </FluentGridItem>
            @* Currency *@
            <FluentGridItem xs="6" sm="4">
                <div class="card">
                    <FluentSelect TOption="CurrencyVm"
                        Label="Select currency:"
                        Items="@itemCurrenciesList"
                        Id="CurrencyId"
                        Width="150px"
                        Height="250px"
                        OptionValue="@(p => p.Id.ToString())"
                        OptionText="@(p => p.Name)"
                        @bind-Value="@Content.CurrencyVm.Name"
                        @bind-SelectedOption="@Content.CurrencyVm" />

                    <FluentValidationMessage For="@(() => Content.CurrencyVm)" />
                </div>
            </FluentGridItem>
            @* Purchase Date *@
            <FluentGridItem xs="6" sm="4">
                <div class="card">
                    <FluentDatePicker Id="PurchDate" @bind-Value="@Content.PurchaseDate" Disabled="@editmode" Placeholder="Enter purchase date"> Purchase date: </FluentDatePicker>
                    <FluentValidationMessage For="@(() => Content.PurchaseDate)" />
                </div>
            </FluentGridItem>
        </FluentGrid>

        @if (!string.IsNullOrEmpty(errorMessage))
        {
            <div class="validation-error"><p style="color:red;">@errorMessage</p></div>
        }
    </EditForm>
</FluentDialogBody>


@code {
    [Parameter]
    public AssetVm Content { get; set; } = default!;

    [CascadingParameter]
    public FluentDialog Dialog { get; set; } = default!;

    JustifyContent Justification = JustifyContent.FlexStart;

    private EditContext _editContext;
    private bool editmode = false;
    private FluentValidationValidator? _fluentValidator;
    private string errorMessage;

    private IQueryable<PartVm> itemPartsList { get; set; }
    private IQueryable<InvoiceVm> itemInvoicesList { get; set; }
    private IQueryable<StateVm> itemStatesList { get; set; }
    private IQueryable<EmployeeVm> itemEmployeesList { get; set; }
    private IQueryable<WarehouseVm> itemWarehousesList { get; set; }
    private IQueryable<CurrencyVm> itemCurrenciesList { get; set; }

    protected override async Task OnInitializedAsync()
    {
        _editContext = new EditContext(Content);

        itemPartsList = await _mediator.Send(new GetAllPartsForSelectQuery());
        itemInvoicesList = await _mediator.Send(new GetAllInvoicesForSelectQuery());
        itemStatesList = await _mediator.Send(new GetAllStatesForSelectQuery());
        itemEmployeesList = await _mediator.Send(new GetAllEmployeesForSelectQuery());
        itemWarehousesList = await _mediator.Send(new GetAllWarehousesForSelectQuery());
        itemCurrenciesList = await _mediator.Send(new GetAllCurrenciesForSelectQuery());


        if (Content.Id > 0)
        {
            editmode = true;
        }

        base.OnInitialized();
    }

    private async Task SaveAsync()
    {

        if (Content.Id != 0)
        {
            await Dialog.CloseAsync(Content);
        }
        else
        {
            Console.WriteLine("Something went wrong!");
        }

    }

    private async Task CancelAsync()
    {
        await Dialog.CancelAsync();
    }
}

Interesting fact is, it renders ok. But when I change values of those dropdowns it shows changed name property.

I tried to change bind-values from subtype's property to type (for instance: @Content.EmployeeVm.LongName to @Content.EmployeeVm. But it generates other errors...

1

There are 1 answers

0
ZnowuJa On

Well, it apeared that from those components:

<FluentSelect TOption="StateVm"
  Label="Select state:"
  Items="@itemStatesList"
  Id="StateId"
  Width="150px"
  Height="250px"
  OptionValue="@(p => p.Id.ToString())"
  OptionText="@(p => p.Name)"
  @bind-Value="@Content.StateVm.Name"
  @bind-SelectedOption="@Content.StateVm" />

I removed @bind-Value line and everything works perfect!